+2014-09-03 Chris Manghane <cmang@google.com>
+
+ * go-gcc.cc (Gcc_backend::implicit_variable): Remove init
+ parameter. Add is_hidden parameter.
+ (Gcc_backend::implicit_variable_set_init): New method.
+ (Gcc_backend::implicit_variable_reference): New method.
+
2014-08-08 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Gcc_backend::compound_statement): Don't return
Location, Bstatement**);
Bvariable*
- implicit_variable(const std::string&, Btype*, Bexpression*, bool, bool,
+ implicit_variable(const std::string&, Btype*, bool, bool, bool,
size_t);
+ void
+ implicit_variable_set_init(Bvariable*, const std::string&, Btype*,
+ bool, bool, bool, Bexpression*);
+
+ Bvariable*
+ implicit_variable_reference(const std::string&, Btype*);
+
Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location);
Bvariable*
Gcc_backend::implicit_variable(const std::string& name, Btype* type,
- Bexpression* init, bool is_constant,
+ bool is_hidden, bool is_constant,
bool is_common, size_t alignment)
{
tree type_tree = type->get_tree();
- tree init_tree;
- if (init == NULL)
- init_tree = NULL_TREE;
- else
- init_tree = init->get_tree();
- if (type_tree == error_mark_node || init_tree == error_mark_node)
+ if (type_tree == error_mark_node)
return this->error_variable();
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
get_identifier_from_string(name), type_tree);
DECL_EXTERNAL(decl) = 0;
- TREE_PUBLIC(decl) = 0;
+ TREE_PUBLIC(decl) = !is_hidden;
TREE_STATIC(decl) = 1;
+ TREE_USED(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
if (is_common)
{
DECL_COMMON(decl) = 1;
- TREE_PUBLIC(decl) = 1;
- gcc_assert(init_tree == NULL_TREE);
+
+ // When the initializer for one implicit_variable refers to another,
+ // it needs to know the visibility of the referenced struct so that
+ // compute_reloc_for_constant will return the right value. On many
+ // systems calling make_decl_one_only will mark the decl as weak,
+ // which will change the return value of compute_reloc_for_constant.
+ // We can't reliably call make_decl_one_only yet, because we don't
+ // yet know the initializer. This issue doesn't arise in C because
+ // Go initializers, unlike C initializers, can be indirectly
+ // recursive. To ensure that compute_reloc_for_constant computes
+ // the right value if some other initializer refers to this one, we
+ // mark this symbol as weak here. We undo that below in
+ // immutable_struct_set_init before calling mark_decl_one_only.
+ DECL_WEAK(decl) = 1;
}
- else if (is_constant)
+ if (is_constant)
{
TREE_READONLY(decl) = 1;
TREE_CONSTANT(decl) = 1;
}
- DECL_INITIAL(decl) = init_tree;
-
if (alignment != 0)
{
DECL_ALIGN(decl) = alignment * BITS_PER_UNIT;
DECL_USER_ALIGN(decl) = 1;
}
+ go_preserve_from_gc(decl);
+ return new Bvariable(decl);
+}
+
+// Set the initalizer for a variable created by implicit_variable.
+// This is where we finish compiling the variable.
+
+void
+Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&,
+ Btype*, bool, bool, bool is_common,
+ Bexpression* init)
+{
+ tree decl = var->get_tree();
+ tree init_tree;
+ if (init == NULL)
+ init_tree = NULL_TREE;
+ else
+ init_tree = init->get_tree();
+ if (decl == error_mark_node || init_tree == error_mark_node)
+ return;
+
+ DECL_INITIAL(decl) = init_tree;
+
+ // Now that DECL_INITIAL is set, we can't call make_decl_one_only.
+ // See the comment where DECL_WEAK is set in implicit_variable.
+ if (is_common)
+ {
+ DECL_WEAK(decl) = 0;
+ make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
+ }
+
+ resolve_unique_section(decl, 2, 1);
+
rest_of_decl_compilation(decl, 1, 0);
+}
+// Return a reference to an implicit variable defined in another package.
+
+Bvariable*
+Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
+{
+ tree type_tree = btype->get_tree();
+ if (type_tree == error_mark_node)
+ return this->error_variable();
+
+ tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
+ get_identifier_from_string(name), type_tree);
+ DECL_EXTERNAL(decl) = 0;
+ TREE_PUBLIC(decl) = 1;
+ TREE_STATIC(decl) = 1;
+ DECL_ARTIFICIAL(decl) = 1;
+ go_preserve_from_gc(decl);
return new Bvariable(decl);
}
Bstatement** pstatement) = 0;
// Create an implicit variable that is compiler-defined. This is
- // used when generating GC root variables, when storing the values
- // of a slice constructor, and for the zero value of types. NAME is
- // the name of the variable, either gc# for GC roots or C# for slice
- // initializers. TYPE is the type of the implicit variable with an
- // initial value INIT. IS_CONSTANT is true if the implicit variable
- // should be treated like it is immutable. For slice initializers,
- // if the values must be copied to the heap, the variable
- // IS_CONSTANT. IS_COMMON is true if the implicit variable should
+ // used when generating GC data and roots, when storing the values
+ // of a slice constructor, and for the zero value of types. This returns a
+ // Bvariable because it corresponds to an initialized variable in C.
+ //
+ // NAME is the name to use for the initialized variable this will create.
+ //
+ // TYPE is the type of the implicit variable.
+ //
+ // IS_HIDDEN will be true if the descriptor should only be visible
+ // within the current object.
+ //
+ // IS_CONSTANT is true if the implicit variable should be treated like it is
+ // immutable. For slice initializers, if the values must be copied to the
+ // heap, the variable IS_CONSTANT.
+ //
+ // IS_COMMON is true if the implicit variable should
// be treated as a common variable (multiple definitions with
// different sizes permitted in different object files, all merged
// into the largest definition at link time); this will be true for
- // the zero value. If IS_COMMON is true, INIT will be NULL, and the
- // variable should be initialized to all zeros. If ALIGNMENT is not
- // zero, it is the desired alignment of the variable.
+ // the zero value. IS_HIDDEN and IS_COMMON will never both be true.
+ //
+ // If ALIGNMENT is not zero, it is the desired alignment of the variable.
virtual Bvariable*
- implicit_variable(const std::string& name, Btype* type, Bexpression* init,
+ implicit_variable(const std::string& name, Btype* type, bool is_hidden,
bool is_constant, bool is_common, size_t alignment) = 0;
+
+ // Set the initial value of a variable created by implicit_variable.
+ // This must be called even if there is no initializer, i.e., INIT is NULL.
+ // The NAME, TYPE, IS_HIDDEN, IS_CONSTANT, and IS_COMMON parameters are
+ // the same ones passed to implicit_variable. INIT will be a composite
+ // literal of type TYPE. It will not contain any function calls or anything
+ // else that can not be put into a read-only data section.
+ // It may contain the address of variables created by implicit_variable.
+ //
+ // If IS_COMMON is true, INIT will be NULL, and the
+ // variable should be initialized to all zeros.
+ virtual void
+ implicit_variable_set_init(Bvariable*, const std::string& name, Btype* type,
+ bool is_hidden, bool is_constant, bool is_common,
+ Bexpression* init) = 0;
+
+ // Create a reference to a named implicit variable defined in some other
+ // package. This will be a variable created by a call to implicit_variable
+ // with the same NAME and TYPE and with IS_COMMON passed as false. This
+ // corresponds to an extern global variable in C.
+ virtual Bvariable*
+ implicit_variable_reference(const std::string& name, Btype* type) = 0;
+
// Create a named immutable initialized data structure. This is
// used for type descriptors, map descriptors, and function
// descriptors. This returns a Bvariable because it corresponds to
int
do_traverse(Traverse* traverse);
+ bool
+ do_is_immutable() const;
+
Type*
do_type()
{ return this->type_; }
return TRAVERSE_CONTINUE;
}
+// Return whether an unsafe type conversion is immutable.
+
+bool
+Unsafe_type_conversion_expression::do_is_immutable() const
+{
+ Type* type = this->type_;
+ Type* expr_type = this->expr_->type();
+
+ if (type->interface_type() != NULL
+ || expr_type->interface_type() != NULL)
+ return false;
+
+ if (!this->expr_->is_immutable())
+ return false;
+
+ if (Type::are_convertible(type, expr_type, NULL))
+ return true;
+
+ return type->is_basic_type() && expr_type->is_basic_type();
+}
+
// Convert to backend representation.
Bexpression*
&& !context->is_const());
}
Bvariable* implicit =
- gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap,
+ gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap,
false, 0);
+ gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
+ true, copy_to_heap, false,
+ bexpr);
bexpr = gogo->backend()->var_expression(implicit, loc);
}
else if ((this->expr_->is_composite_literal()
return new Type_descriptor_expression(type, location);
}
+// An expression which evaluates to a pointer to the Garbage Collection symbol
+// of a type.
+
+class GC_symbol_expression : public Expression
+{
+ public:
+ GC_symbol_expression(Type* type)
+ : Expression(EXPRESSION_GC_SYMBOL, Linemap::predeclared_location()),
+ type_(type)
+ {}
+
+ protected:
+ Type*
+ do_type()
+ { return Type::make_pointer_type(Type::make_void_type()); }
+
+ bool
+ do_is_immutable() const
+ { return true; }
+
+ void
+ do_determine_type(const Type_context*)
+ { }
+
+ Expression*
+ do_copy()
+ { return this; }
+
+ Bexpression*
+ do_get_backend(Translate_context* context)
+ { return this->type_->gc_symbol_pointer(context->gogo()); }
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The type which this gc symbol describes.
+ Type* type_;
+};
+
+// Dump ast representation for a gc symbol expression.
+
+void
+GC_symbol_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "gcdata(";
+ ast_dump_context->dump_type(this->type_);
+ ast_dump_context->ostream() << ")";
+}
+
+// Make a gc symbol expression.
+
+Expression*
+Expression::make_gc_symbol(Type* type)
+{
+ return new GC_symbol_expression(type);
+}
+
// An expression which evaluates to some characteristic of a type.
// This is only used to initialize fields of a type descriptor. Using
// a new expression class is slightly inefficient but gives us a good
EXPRESSION_HEAP,
EXPRESSION_RECEIVE,
EXPRESSION_TYPE_DESCRIPTOR,
+ EXPRESSION_GC_SYMBOL,
EXPRESSION_TYPE_INFO,
EXPRESSION_SLICE_INFO,
EXPRESSION_SLICE_VALUE,
static Expression*
make_type_descriptor(Type* type, Location);
+ // Make an expression which evaluates to the address of the gc
+ // symbol for TYPE.
+ static Expression*
+ make_gc_symbol(Type* type);
+
// Make an expression which evaluates to some characteristic of a
// type. These are only used for type descriptors, so there is no
// location parameter.
do_is_constant() const
{ return this->left_->is_constant() && this->right_->is_constant(); }
+ bool
+ do_is_immutable() const
+ { return this->left_->is_immutable() && this->right_->is_immutable(); }
+
bool
do_numeric_constant_value(Numeric_constant*) const;
Btype* barray_type = this->backend()->array_type(bbtype_type, blength);
- return this->backend()->implicit_variable(this->zero_value_->name(),
- barray_type, NULL, true, true,
- this->zero_value_align_);
+ std::string zname = this->zero_value_->name();
+ Bvariable* zvar =
+ this->backend()->implicit_variable(zname, barray_type, false,
+ true, true, this->zero_value_align_);
+ this->backend()->implicit_variable_set_init(zvar, zname, barray_type,
+ false, true, true, NULL);
+ return zvar;
}
// Add statements to INIT_STMTS which run the initialization
{
named_type->
type_descriptor_pointer(gogo, Linemap::predeclared_location());
+ named_type->gc_symbol_pointer(gogo);
Type* pn = Type::make_pointer_type(named_type);
pn->type_descriptor_pointer(gogo, Linemap::predeclared_location());
+ pn->gc_symbol_pointer(gogo);
}
}
break;
// Class Type.
Type::Type(Type_classification classification)
- : classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
+ : classification_(classification), btype_(NULL), type_descriptor_var_(NULL),
+ gc_symbol_var_(NULL)
{
}
Type::type_descriptor_vars.insert(std::make_pair(this, bvnull));
if (!ins.second)
{
- // We've already build a type descriptor for this type.
+ // We've already built a type descriptor for this type.
this->type_descriptor_var_ = ins.first->second;
return;
}
return type->do_type_descriptor(gogo, name);
}
+// Generate the GC symbol for this TYPE. VALS is the data so far in this
+// symbol; extra values will be appended in do_gc_symbol. OFFSET is the
+// offset into the symbol where the GC data is located. STACK_SIZE is the
+// size of the GC stack when dealing with array types.
+
+void
+Type::gc_symbol(Gogo* gogo, Type* type, Expression_list** vals,
+ Expression** offset, int stack_size)
+{
+ type->do_gc_symbol(gogo, vals, offset, stack_size);
+}
+
// Make a builtin struct type from a list of fields. The fields are
// pairs of a name and a type.
// The type descriptor type.
Struct_type* type_descriptor_type =
- Type::make_builtin_struct_type(11,
- "Kind", uint8_type,
+ Type::make_builtin_struct_type(12,
+ "kind", uint8_type,
"align", uint8_type,
"fieldAlign", uint8_type,
"size", uintptr_type,
"hash", uint32_type,
"hashfn", uintptr_type,
"equalfn", uintptr_type,
+ "gc", unsafe_pointer_type,
"string", pointer_string_type,
"", pointer_uncommon_type,
"ptrToThis",
if (!this->has_pointer())
runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS;
Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("Kind"));
+ go_assert(p->is_field_name("kind"));
mpz_t iv;
mpz_init_set_ui(iv, runtime_type_kind);
vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
vals->push_back(Expression::make_func_code_reference(hash_fn, bloc));
vals->push_back(Expression::make_func_code_reference(equal_fn, bloc));
+ ++p;
+ go_assert(p->is_field_name("gc"));
+ vals->push_back(Expression::make_gc_symbol(this));
+
++p;
go_assert(p->is_field_name("string"));
Expression* s = Expression::make_string((name != NULL
return Expression::make_struct_composite_literal(td_type, vals, bloc);
}
+// Return a pointer to the Garbage Collection information for this type.
+
+Bexpression*
+Type::gc_symbol_pointer(Gogo* gogo)
+{
+ Type* t = this->forwarded();
+ if (t->named_type() != NULL && t->named_type()->is_alias())
+ t = t->named_type()->real_type();
+ if (t->gc_symbol_var_ == NULL)
+ {
+ t->make_gc_symbol_var(gogo);
+ go_assert(t->gc_symbol_var_ != NULL);
+ }
+ Location bloc = Linemap::predeclared_location();
+ Bexpression* var_expr =
+ gogo->backend()->var_expression(t->gc_symbol_var_, bloc);
+ return gogo->backend()->address_expression(var_expr, bloc);
+}
+
+// A mapping from unnamed types to GC symbol variables.
+
+Type::GC_symbol_vars Type::gc_symbol_vars;
+
+// Build the GC symbol for this type.
+
+void
+Type::make_gc_symbol_var(Gogo* gogo)
+{
+ go_assert(this->gc_symbol_var_ == NULL);
+
+ Named_type* nt = this->named_type();
+
+ // We can have multiple instances of unnamed types and similar to type
+ // descriptors, we only want to the emit the GC data once, so we use a
+ // hash table.
+ Bvariable** phash = NULL;
+ if (nt == NULL)
+ {
+ Bvariable* bvnull = NULL;
+ std::pair<GC_symbol_vars::iterator, bool> ins =
+ Type::gc_symbol_vars.insert(std::make_pair(this, bvnull));
+ if (!ins.second)
+ {
+ // We've already built a gc symbol for this type.
+ this->gc_symbol_var_ = ins.first->second;
+ return;
+ }
+ phash = &ins.first->second;
+ }
+
+ std::string sym_name = this->type_descriptor_var_name(gogo, nt) + "$gc";
+
+ // Build the contents of the gc symbol.
+ Expression* sym_init = this->gc_symbol_constructor(gogo);
+ Btype* sym_btype = sym_init->type()->get_backend(gogo);
+
+ // If the type descriptor for this type is defined somewhere else, so is the
+ // GC symbol.
+ const Package* dummy;
+ if (this->type_descriptor_defined_elsewhere(nt, &dummy))
+ {
+ this->gc_symbol_var_ =
+ gogo->backend()->implicit_variable_reference(sym_name, sym_btype);
+ if (phash != NULL)
+ *phash = this->gc_symbol_var_;
+ return;
+ }
+
+ // See if this gc symbol can appear in multiple packages.
+ bool is_common = false;
+ if (nt != NULL)
+ {
+ // We create the symbol for a builtin type whenever we need
+ // it.
+ is_common = nt->is_builtin();
+ }
+ else
+ {
+ // This is an unnamed type. The descriptor could be defined in
+ // any package where it is needed, and the linker will pick one
+ // descriptor to keep.
+ is_common = true;
+ }
+
+ // Since we are building the GC symbol in this package, we must create the
+ // variable before converting the initializer to its backend representation
+ // because the initializer may refer to the GC symbol for this type.
+ this->gc_symbol_var_ =
+ gogo->backend()->implicit_variable(sym_name, sym_btype, false, true, is_common, 0);
+ if (phash != NULL)
+ *phash = this->gc_symbol_var_;
+
+ Translate_context context(gogo, NULL, NULL, NULL);
+ context.set_is_const();
+ Bexpression* sym_binit = sym_init->get_backend(&context);
+ gogo->backend()->implicit_variable_set_init(this->gc_symbol_var_, sym_name,
+ sym_btype, false, true, is_common,
+ sym_binit);
+}
+
+// Return an array literal for the Garbage Collection information for this type.
+
+Expression*
+Type::gc_symbol_constructor(Gogo* gogo)
+{
+ Location bloc = Linemap::predeclared_location();
+
+ // The common GC Symbol data starts with the width of the type and ends
+ // with the GC Opcode GC_END.
+ // However, for certain types, the GC symbol may include extra information
+ // before the ending opcode, so we pass the expression list into
+ // Type::gc_symbol to allow it to add extra information as is necessary.
+ Expression_list* vals = new Expression_list;
+
+ Type* uintptr_t = Type::lookup_integer_type("uintptr");
+ // width
+ vals->push_back(Expression::make_type_info(this,
+ Expression::TYPE_INFO_SIZE));
+
+ mpz_t off;
+ mpz_init_set_ui(off, 0UL);
+ Expression* offset = Expression::make_integer(&off, uintptr_t, bloc);
+ mpz_clear(off);
+
+ this->do_gc_symbol(gogo, &vals, &offset, 0);
+
+ mpz_t end;
+ mpz_init_set_ui(end, GC_END);
+ vals->push_back(Expression::make_integer(&end, uintptr_t, bloc));
+ mpz_clear(end);
+
+ mpz_t lenval;
+ mpz_init_set_ui(lenval, vals->size() + 1);
+ Expression* len = Expression::make_integer(&lenval, NULL, bloc);
+ mpz_clear(lenval);
+
+ Array_type* gc_symbol_type = Type::make_array_type(uintptr_t, len);
+ return Expression::make_array_composite_literal(gc_symbol_type, vals, bloc);
+}
+
+// Advance the OFFSET of the GC symbol by this type's width.
+
+void
+Type::advance_gc_offset(Expression** offset)
+{
+ if (this->is_error_type())
+ return;
+
+ Location bloc = Linemap::predeclared_location();
+ Expression* width =
+ Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
+ *offset = Expression::make_binary(OPERATOR_PLUS, *offset, width, bloc);
+}
+
// Return a composite literal for the uncommon type information for
// this type. UNCOMMON_STRUCT_TYPE is the type of the uncommon type
// struct. If name is not NULL, it is the name of the type. If
do_reflection(Gogo*, std::string*) const
{ go_assert(saw_errors()); }
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+ { go_assert(saw_errors()); }
+
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('E'); }
do_reflection(Gogo*, std::string*) const
{ }
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+ { }
+
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('v'); }
do_reflection(Gogo*, std::string* ret) const
{ ret->append("bool"); }
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('b'); }
}
}
+// Update the offset of the GC symbol.
+
+void
+Boolean_type::do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
+{ this->advance_gc_offset(offset); }
+
Type*
Type::make_boolean_type()
{
ret->append("string");
}
+// Generate GC symbol for strings.
+
+void
+String_type::do_gc_symbol(Gogo*, Expression_list** vals,
+ Expression** offset, int)
+{
+ Location bloc = Linemap::predeclared_location();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ mpz_t opval;
+ mpz_init_set_ui(opval, GC_STRING);
+ (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+ mpz_clear(opval);
+ (*vals)->push_back(*offset);
+ this->advance_gc_offset(offset);
+}
+
// Mangled name of a string type.
void
do_reflection(Gogo*, std::string*) const
{ go_unreachable(); }
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+ { go_unreachable(); }
+
void
do_mangled_name(Gogo*, std::string*) const
{ go_unreachable(); }
}
}
+// Generate GC symbol for a function type.
+
+void
+Function_type::do_gc_symbol(Gogo*, Expression_list** vals,
+ Expression** offset, int)
+{
+ Location bloc = Linemap::predeclared_location();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+ // We use GC_APTR here because we do not currently have a way to describe the
+ // the type of the possible function closure. FIXME.
+ mpz_t opval;
+ mpz_init_set_ui(opval, GC_APTR);
+ (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+ mpz_clear(opval);
+ (*vals)->push_back(*offset);
+ this->advance_gc_offset(offset);
+}
+
// Mangled name.
void
this->append_reflection(this->to_type_, gogo, ret);
}
+// Generate GC symbol for pointer types.
+
+void
+Pointer_type::do_gc_symbol(Gogo*, Expression_list** vals,
+ Expression** offset, int)
+{
+ Location loc = Linemap::predeclared_location();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+ mpz_t opval;
+ mpz_init_set_ui(opval, this->to_type_->has_pointer() ? GC_PTR : GC_APTR);
+ (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, loc));
+ mpz_clear(opval);
+ (*vals)->push_back(*offset);
+
+ if (this->to_type_->has_pointer())
+ (*vals)->push_back(Expression::make_gc_symbol(this->to_type_));
+ this->advance_gc_offset(offset);
+}
+
// Mangled name.
void
do_reflection(Gogo*, std::string*) const
{ go_unreachable(); }
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+ { go_unreachable(); }
+
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('n'); }
do_reflection(Gogo*, std::string*) const
{ go_assert(saw_errors()); }
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+ { go_unreachable(); }
+
void
do_mangled_name(Gogo*, std::string*) const
{ go_assert(saw_errors()); }
ret->push_back('}');
}
+// Generate GC symbol for struct types.
+
+void
+Struct_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
+ Expression** offset, int stack_size)
+{
+ Location bloc = Linemap::predeclared_location();
+ const Struct_field_list* sfl = this->fields();
+ for (Struct_field_list::const_iterator p = sfl->begin();
+ p != sfl->end();
+ ++p)
+ {
+ Expression* field_offset =
+ Expression::make_struct_field_offset(this, &*p);
+ Expression* o =
+ Expression::make_binary(OPERATOR_PLUS, *offset, field_offset, bloc);
+ Type::gc_symbol(gogo, p->type(), vals, &o, stack_size);
+ }
+ this->advance_gc_offset(offset);
+}
+
// Mangled name.
void
this->append_reflection(this->element_type_, gogo, ret);
}
+// GC Symbol construction for array types.
+
+void
+Array_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
+ Expression** offset, int stack_size)
+{
+ if (this->length_ == NULL)
+ this->slice_gc_symbol(gogo, vals, offset, stack_size);
+ else
+ this->array_gc_symbol(gogo, vals, offset, stack_size);
+}
+
+// Generate the GC Symbol for a slice.
+
+void
+Array_type::slice_gc_symbol(Gogo* gogo, Expression_list** vals,
+ Expression** offset, int)
+{
+ Location bloc = Linemap::predeclared_location();
+
+ // Differentiate between slices with zero-length and non-zero-length values.
+ Type* element_type = this->element_type();
+ Btype* ebtype = element_type->get_backend(gogo);
+ size_t element_size = gogo->backend()->type_size(ebtype);
+
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ mpz_t opval;
+ mpz_init_set_ui(opval, element_size == 0 ? GC_APTR : GC_SLICE);
+ (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+ mpz_clear(opval);
+ (*vals)->push_back(*offset);
+
+ if (element_size != 0)
+ (*vals)->push_back(Expression::make_gc_symbol(element_type));
+ this->advance_gc_offset(offset);
+}
+
+// Generate the GC symbol for an array.
+
+void
+Array_type::array_gc_symbol(Gogo* gogo, Expression_list** vals,
+ Expression** offset, int stack_size)
+{
+ Location bloc = Linemap::predeclared_location();
+
+ Numeric_constant nc;
+ unsigned long bound;
+ if (!this->length_->numeric_constant_value(&nc)
+ || nc.to_unsigned_long(&bound) == Numeric_constant::NC_UL_NOTINT)
+ go_assert(saw_errors());
+
+ Btype* pbtype = gogo->backend()->pointer_type(gogo->backend()->void_type());
+ size_t pwidth = gogo->backend()->type_size(pbtype);
+ size_t iwidth = gogo->backend()->type_size(this->get_backend(gogo));
+
+ Type* element_type = this->element_type();
+ if (bound < 1 || !element_type->has_pointer())
+ this->advance_gc_offset(offset);
+ else if (bound == 1 || iwidth <= 4 * pwidth)
+ {
+ for (unsigned int i = 0; i < bound; ++i)
+ Type::gc_symbol(gogo, element_type, vals, offset, stack_size);
+ }
+ else
+ {
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+ mpz_t op;
+ if (stack_size < GC_STACK_CAPACITY)
+ {
+ mpz_init_set_ui(op, GC_ARRAY_START);
+ (*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
+ mpz_clear(op);
+ (*vals)->push_back(*offset);
+ Expression* uintptr_len =
+ Expression::make_cast(uintptr_type, this->length_, bloc);
+ (*vals)->push_back(uintptr_len);
+
+ Expression* width =
+ Expression::make_type_info(element_type,
+ Expression::TYPE_INFO_SIZE);
+ (*vals)->push_back(width);
+
+ mpz_t zero;
+ mpz_init_set_ui(zero, 0UL);
+ Expression* offset2 =
+ Expression::make_integer(&zero, uintptr_type, bloc);
+ mpz_clear(zero);
+
+ Type::gc_symbol(gogo, element_type, vals, &offset2, stack_size + 1);
+ mpz_init_set_ui(op, GC_ARRAY_NEXT);
+ (*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
+ }
+ else
+ {
+ mpz_init_set_ui(op, GC_REGION);
+ (*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
+ (*vals)->push_back(*offset);
+
+ Expression* width =
+ Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
+ (*vals)->push_back(width);
+ (*vals)->push_back(Expression::make_gc_symbol(this));
+ }
+ mpz_clear(op);
+ this->advance_gc_offset(offset);
+ }
+}
+
// Mangled name.
void
this->append_reflection(this->val_type_, gogo, ret);
}
+// Generate GC symbol for a map.
+
+void
+Map_type::do_gc_symbol(Gogo*, Expression_list** vals,
+ Expression** offset, int)
+{
+ // TODO(cmang): Generate GC data for the Map elements.
+ Location bloc = Linemap::predeclared_location();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+ mpz_t opval;
+ mpz_init_set_ui(opval, GC_APTR);
+ (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+ mpz_clear(opval);
+ (*vals)->push_back(*offset);
+ this->advance_gc_offset(offset);
+}
+
// Mangled name for a map.
void
this->append_reflection(this->element_type_, gogo, ret);
}
+// Generate GC symbol for channels.
+
+void
+Channel_type::do_gc_symbol(Gogo*, Expression_list** vals,
+ Expression** offset, int)
+{
+ Location bloc = Linemap::predeclared_location();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+ mpz_t opval;
+ mpz_init_set_ui(opval, GC_CHAN_PTR);
+ (*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
+ mpz_clear(opval);
+ (*vals)->push_back(*offset);
+
+ Type* unsafeptr_type = Type::make_pointer_type(Type::make_void_type());
+ Expression* type_descriptor =
+ Expression::make_type_descriptor(this, bloc);
+ type_descriptor =
+ Expression::make_unsafe_cast(unsafeptr_type, type_descriptor, bloc);
+ (*vals)->push_back(type_descriptor);
+ this->advance_gc_offset(offset);
+}
+
// Mangled name.
void
ret->append("}");
}
+// Generate GC symbol for interface types.
+
+void
+Interface_type::do_gc_symbol(Gogo*, Expression_list** vals,
+ Expression** offset, int)
+{
+ Location bloc = Linemap::predeclared_location();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+ mpz_t opval;
+ mpz_init_set_ui(opval, this->is_empty() ? GC_EFACE : GC_IFACE);
+ (*vals)->push_back(Expression::make_integer(&opval, uintptr_type,
+ bloc));
+ mpz_clear(opval);
+ (*vals)->push_back(*offset);
+ this->advance_gc_offset(offset);
+}
+
// Mangled name.
void
ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
}
+// Generate GC symbol for named types.
+
+void
+Named_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
+ Expression** offset, int stack)
+{
+ if (!this->seen_)
+ {
+ this->seen_ = true;
+ Type::gc_symbol(gogo, this->real_type(), vals, offset, stack);
+ this->seen_ = false;
+ }
+}
+
// Get the mangled name.
void
static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7);
+// GC instruction opcodes. These must match the values in libgo/runtime/mgc0.h.
+enum GC_Opcode
+{
+ GC_END = 0, // End of object, loop or subroutine.
+ GC_PTR, // A typed pointer.
+ GC_APTR, // Pointer to an arbitrary object.
+ GC_ARRAY_START, // Start an array with a fixed length.
+ GC_ARRAY_NEXT, // The next element of an array.
+ GC_CALL, // Call a subroutine.
+ GC_CHAN_PTR, // Go channel.
+ GC_STRING, // Go string.
+ GC_EFACE, // interface{}.
+ GC_IFACE, // interface{...}.
+ GC_SLICE, // Go slice.
+ GC_REGION, // A region/part of the current object.
+
+ GC_NUM_INSTR // Number of instruction opcodes
+};
+
+// The GC Stack Capacity must match the value in libgo/runtime/mgc0.h.
+static const int GC_STACK_CAPACITY = 8;
+
// To build the complete list of methods for a named type we need to
// gather all methods from anonymous fields. Those methods may
// require an arbitrary set of indirections and field offsets. There
Bexpression*
type_descriptor_pointer(Gogo* gogo, Location);
+ // Build the Garbage Collection symbol for this type. Return a pointer to it.
+ Bexpression*
+ gc_symbol_pointer(Gogo* gogo);
+
// Return the type reflection string for this type.
std::string
reflection(Gogo*) const;
virtual Expression*
do_type_descriptor(Gogo*, Named_type* name) = 0;
+ virtual void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int) = 0;
+
virtual void
do_reflection(Gogo*, std::string*) const = 0;
type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*,
const Methods*, bool only_value_methods);
+ // Generate the GC symbol for this TYPE. VALS is the data so far in this
+ // symbol; extra values will be appended in do_gc_symbol. OFFSET is the
+ // offset into the symbol where the GC data is located. STACK_SIZE is the
+ // size of the GC stack when dealing with array types.
+ static void
+ gc_symbol(Gogo*, Type* type, Expression_list** vals, Expression** offset,
+ int stack_size);
+
+ // Build a composite literal for the GC symbol of this type.
+ Expression*
+ gc_symbol_constructor(Gogo*);
+
+ // Advance the OFFSET of the GC symbol by the size of this type.
+ void
+ advance_gc_offset(Expression** offset);
+
// For the benefit of child class reflection string generation.
void
append_reflection(const Type* type, Gogo* gogo, std::string* ret) const
void
make_type_descriptor_var(Gogo*);
+ // Map unnamed types to type descriptor decls.
+ typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical,
+ Type_identical) GC_symbol_vars;
+
+ static GC_symbol_vars gc_symbol_vars;
+
+ // Build the GC symbol for this type.
+ void
+ make_gc_symbol_var(Gogo*);
+
// Return the name of the type descriptor variable. If NAME is not
// NULL, it is the name to use.
std::string
// The type descriptor for this type. This starts out as NULL and
// is filled in as needed.
Bvariable* type_descriptor_var_;
+ // The GC symbol for this type. This starts out as NULL and
+ // is filled in as needed.
+ Bvariable* gc_symbol_var_;
};
// Type hash table operations.
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
+ { this->advance_gc_offset(offset); }
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
+ { this->advance_gc_offset(offset); }
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
+ { this->advance_gc_offset(offset); }
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string* ret) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string*) const;
Expression*
slice_type_descriptor(Gogo*, Named_type*);
+ void
+ slice_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
+ array_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
// The type of elements of the array.
Type* element_type_;
// The number of elements. This may be NULL.
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
void
do_mangled_name(Gogo*, std::string*) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
+ int stack);
+
void
do_mangled_name(Gogo*, std::string* ret) const;
void
do_reflection(Gogo*, std::string*) const;
+ void
+ do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
+ int stack_size)
+ { Type::gc_symbol(gogo, this->real_type(), vals, offset, stack_size); }
+
void
do_mangled_name(Gogo*, std::string* ret) const;
hashfn uintptr // hash function code
equalfn uintptr // equality function code
+ gc unsafe.Pointer // garbage collection data
string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
p.elem = t
+ if t.kind&kindNoPointers != 0 {
+ p.gc = unsafe.Pointer(&ptrDataGCProg)
+ } else {
+ p.gc = unsafe.Pointer(&ptrGC{
+ width: p.size,
+ op: _GC_PTR,
+ off: 0,
+ elemgc: t.gc,
+ end: _GC_END,
+ })
+ }
+
q := canonicalize(&p.rtype)
p = (*ptrType)(unsafe.Pointer(q.(*rtype)))
ch.ptrToThis = nil
ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
+ ch.gc = unsafe.Pointer(&chanGC{
+ width: ch.size,
+ op: _GC_CHAN_PTR,
+ off: 0,
+ typ: &ch.rtype,
+ end: _GC_END,
+ })
+
// INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong.
- //ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
+ // ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
return cachePut(ckey, &ch.rtype)
}
// width: unsafe.Sizeof(uintptr(0)),
// op: _GC_PTR,
// off: 0,
- // elemgc: mt.hmap.gc,
+ // elemgc: nil,
// end: _GC_END,
// })
+ // TODO(cmang): Generate GC data for Map elements.
+ mt.gc = unsafe.Pointer(&ptrDataGCProg)
+
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
// fail when mt.gc is wrong.
//mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END})
// Take the GC program for "t" and append it to the GC program "gc".
func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
- // p := t.gc
- var p unsafe.Pointer
+ p := t.gc
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
loop:
for {
slice.ptrToThis = nil
slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
+ if typ.size == 0 {
+ slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
+ } else {
+ slice.gc = unsafe.Pointer(&sliceGC{
+ width: slice.size,
+ op: _GC_SLICE,
+ off: 0,
+ elemgc: typ.gc,
+ end: _GC_END,
+ })
+ }
+
// INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong.
- //slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
+ // slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
return cachePut(ckey, &slice.rtype)
}
import "unsafe"
type rtype struct {
- Kind uint8
+ kind uint8
align uint8
fieldAlign uint8
size uintptr
hashfn func(unsafe.Pointer, uintptr) uintptr
equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
+ gc unsafe.Pointer
string *string
*uncommonType
ptrToThis *rtype
#define GO_CODE_MASK 0x7f
/* For each Go type the compiler constructs one of these structures.
- This is used for type reflectin, interfaces, maps, and reference
+ This is used for type reflection, interfaces, maps, and reference
counting. */
struct __go_type_descriptor
size of this type, and returns whether the values are equal. */
_Bool (*__equalfn) (const void *, const void *, uintptr_t);
+ /* The garbage collection data. */
+ const uintptr *__gc;
+
/* A string describing this type. This is only used for
debugging. */
const struct String *__reflection;
#include "runtime.h"
#include "go-type.h"
+#include "mgc0.h"
/* A pointer with a zero value. */
static void *zero_pointer;
extern const struct __go_type_descriptor unsafe_Pointer
__asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer");
+extern const uintptr unsafe_Pointer_gc[]
+ __asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer$gc");
+
/* Used to determine the field alignment. */
struct field_align
{
sizeof REFLECTION - 1
};
+const uintptr unsafe_Pointer_gc[] = {8, GC_APTR, 0, GC_END};
+
const struct __go_type_descriptor unsafe_Pointer =
{
/* __code */
__go_type_hash_identity,
/* __equalfn */
__go_type_equal_identity,
+ /* __gc */
+ unsafe_Pointer_gc,
/* __reflection */
&reflection_string,
/* __uncommon */
__go_type_hash_identity,
/* __equalfn */
__go_type_equal_identity,
+ /* __gc */
+ unsafe_Pointer_gc,
/* __reflection */
&preflection_string,
/* __uncommon */
FuncVal *fn;
void *arg;
const struct __go_func_type *ft;
- const struct __go_ptr_type *ot;
+ const PtrType *ot;
};
typedef struct FinBlock FinBlock;
};
static BufferList bufferList[MaxGcproc];
-static Type *itabtype;
-
static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
// flushptrbuf moves data from the PtrTarget buffer to the work buffer.
// Program that scans the whole block and treats every block element as a potential pointer
static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR};
-#if 0
// Hchan program
static uintptr chanProg[2] = {0, GC_CHAN};
-#endif
// Local variables of a program fragment or loop
typedef struct Frame Frame;
struct Frame {
uintptr count, elemsize, b;
- uintptr *loop_or_ret;
+ const uintptr *loop_or_ret;
};
// Sanity check for the derived type info objti.
static void
checkptr(void *obj, uintptr objti)
{
- uintptr type, tisize, i, x;
+ uintptr *pc1, type, tisize, i, j, x;
+ const uintptr *pc2;
byte *objstart;
Type *t;
MSpan *s;
(runtime_strcmp((const char *)t->string->str, (const char*)"unsafe.Pointer") &&
// Runtime and gc think differently about closures.
runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) {
-#if 0
pc1 = (uintptr*)objti;
- pc2 = (uintptr*)t->gc;
+ pc2 = (const uintptr*)t->__gc;
// A simple best-effort check until first GC_END.
for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
if(pc1[j] != pc2[j]) {
runtime_throw("invalid gc type info");
}
}
-#endif
}
}
scanblock(Workbuf *wbuf, bool keepworking)
{
byte *b, *arena_start, *arena_used;
- uintptr n, i, end_b, elemsize, size, ti, objti, count, /* type, */ nobj;
- uintptr *pc, precise_type, nominal_size;
-#if 0
- uintptr *chan_ret, chancap;
-#endif
+ uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
+ uintptr precise_type, nominal_size;
+ const uintptr *pc, *chan_ret;
+ uintptr chancap;
void *obj;
const Type *t, *et;
Slice *sliceptr;
Scanbuf sbuf;
Eface *eface;
Iface *iface;
-#if 0
Hchan *chan;
- ChanType *chantype;
-#endif
+ const ChanType *chantype;
Obj *wp;
if(sizeof(Workbuf) % WorkbufSize != 0)
sbuf.nobj = nobj;
// (Silence the compiler)
-#if 0
chan = nil;
chantype = nil;
chan_ret = nil;
-#endif
goto next_block;
runtime_xadd64(&gcstats.obj.cnt, 1);
}
- if(ti != 0 && false) {
+ if(ti != 0) {
if(Debug > 1) {
runtime_printf("scanblock %p %D ti %p\n", b, (int64)n, ti);
}
runtime_throw("invalid gc type info");
}
}
- } else if(UseSpanType && false) {
+ } else if(UseSpanType) {
if(CollectStats)
runtime_xadd64(&gcstats.obj.notype, 1);
-#if 0
type = runtime_gettype(b);
if(type != 0) {
if(CollectStats)
t = (Type*)(type & ~(uintptr)(PtrSize-1));
switch(type & (PtrSize-1)) {
case TypeInfo_SingleObject:
- pc = (uintptr*)t->gc;
+ pc = (const uintptr*)t->__gc;
precise_type = true; // type information about 'b' is precise
stack_top.count = 1;
stack_top.elemsize = pc[0];
break;
case TypeInfo_Array:
- pc = (uintptr*)t->gc;
+ pc = (const uintptr*)t->__gc;
if(pc[0] == 0)
goto next_block;
precise_type = true; // type information about 'b' is precise
break;
case TypeInfo_Chan:
chan = (Hchan*)b;
- chantype = (ChanType*)t;
+ chantype = (const ChanType*)t;
chan_ret = nil;
pc = chanProg;
break;
if(Debug > 1)
runtime_printf("scanblock %p %D unknown type\n", b, (int64)n);
}
-#endif
} else {
pc = defaultProg;
if(Debug > 1)
// eface->__object
if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) {
- if(t->__size <= sizeof(void*)) {
+ if(__go_is_pointer_type(t)) {
if((t->__code & KindNoPointers))
continue;
// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
et = ((const PtrType*)t)->elem;
if(!(et->__code & KindNoPointers))
- // objti = (uintptr)((const PtrType*)t)->elem->gc;
- objti = 0;
+ objti = (uintptr)((const PtrType*)t)->elem->__gc;
}
} else {
obj = eface->__object;
- // objti = (uintptr)t->gc;
- objti = 0;
+ objti = (uintptr)t->__gc;
}
}
break;
// iface->tab
if((byte*)iface->tab >= arena_start && (byte*)iface->tab < arena_used) {
- *sbuf.ptr.pos++ = (PtrTarget){iface->tab, /* (uintptr)itabtype->gc */ 0};
+ *sbuf.ptr.pos++ = (PtrTarget){iface->tab, 0};
if(sbuf.ptr.pos == sbuf.ptr.end)
flushptrbuf(&sbuf);
}
// iface->data
if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) {
- // t = iface->tab->type;
- t = nil;
- if(t->__size <= sizeof(void*)) {
+ t = (const Type*)iface->tab[0];
+ if(__go_is_pointer_type(t)) {
if((t->__code & KindNoPointers))
continue;
// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
et = ((const PtrType*)t)->elem;
if(!(et->__code & KindNoPointers))
- // objti = (uintptr)((const PtrType*)t)->elem->gc;
- objti = 0;
+ objti = (uintptr)((const PtrType*)t)->elem->__gc;
}
} else {
obj = iface->__object;
- // objti = (uintptr)t->gc;
- objti = 0;
+ objti = (uintptr)t->__gc;
}
}
break;
// Stack push.
*stack_ptr-- = stack_top;
stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/};
- pc = (uintptr*)((byte*)pc + *(int32*)(pc+2)); // target of the CALL instruction
+ pc = (const uintptr*)((const byte*)pc + *(const int32*)(pc+2)); // target of the CALL instruction
continue;
case GC_REGION:
flushobjbuf(&sbuf);
continue;
-#if 0
case GC_CHAN_PTR:
chan = *(Hchan**)(stack_top.b + pc[1]);
if(Debug > 2 && chan != nil)
// in-use part of the circular buffer is scanned.
// (Channel routines zero the unused part, so the current
// code does not lead to leaks, it's just a little inefficient.)
- *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->size,
- (uintptr)chantype->elem->gc | PRECISE | LOOP};
+ *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->__size,
+ (uintptr)chantype->elem->__gc | PRECISE | LOOP};
if(sbuf.obj.pos == sbuf.obj.end)
flushobjbuf(&sbuf);
}
goto next_block;
pc = chan_ret;
continue;
-#endif
default:
runtime_printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
}
// State of background sweep.
-// Pretected by gclock.
+// Protected by gclock.
static struct
{
G* g;
work.markfor = runtime_parforalloc(MaxGcproc);
m->locks--;
- if(itabtype == nil) {
- // get C pointer to the Go type "itab"
- // runtime_gc_itab_ptr(&eface);
- // itabtype = ((PtrType*)eface.__type_descriptor)->elem;
- }
-
t1 = 0;
if(runtime_debug.gctrace)
t1 = runtime_nanotime();
enum
{
- UseSpanType = 0,
+ UseSpanType = 1,
};
#define runtime_setitimer setitimer