aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend
diff options
context:
space:
mode:
authorChris Manghane <cmang@google.com>2014-09-03 22:56:09 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2014-09-03 22:56:09 +0000
commitf1d2ac4f84b4b5354779b3b0a0e125b8302ebb49 (patch)
treeba1dd2b0b5d5bd16e9bc5c7dce503f320e8a896a /gcc/go/gofrontend
parentd2e4feca24b91fd1a3e4e42f8ef82b19d0df5853 (diff)
downloadgcc-f1d2ac4f84b4b5354779b3b0a0e125b8302ebb49.zip
gcc-f1d2ac4f84b4b5354779b3b0a0e125b8302ebb49.tar.gz
gcc-f1d2ac4f84b4b5354779b3b0a0e125b8302ebb49.tar.bz2
compiler: Add precise type information on the heap.
* 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. From-SVN: r214894
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r--gcc/go/gofrontend/backend.h55
-rw-r--r--gcc/go/gofrontend/expressions.cc88
-rw-r--r--gcc/go/gofrontend/expressions.h10
-rw-r--r--gcc/go/gofrontend/gogo.cc12
-rw-r--r--gcc/go/gofrontend/types.cc470
-rw-r--r--gcc/go/gofrontend/types.h109
6 files changed, 723 insertions, 21 deletions
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index 323ac2e..98c36c1 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -545,24 +545,55 @@ class Backend
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
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 6414136..df1650a1 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -3440,6 +3440,9 @@ class Unsafe_type_conversion_expression : public Expression
int
do_traverse(Traverse* traverse);
+ bool
+ do_is_immutable() const;
+
Type*
do_type()
{ return this->type_; }
@@ -3480,6 +3483,27 @@ Unsafe_type_conversion_expression::do_traverse(Traverse* traverse)
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*
@@ -4115,8 +4139,11 @@ Unary_expression::do_get_backend(Translate_context* context)
&& !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()
@@ -13987,6 +14014,65 @@ Expression::make_type_descriptor(Type* type, Location location)
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
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 0ce6f22..77153db 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -103,6 +103,7 @@ class Expression
EXPRESSION_HEAP,
EXPRESSION_RECEIVE,
EXPRESSION_TYPE_DESCRIPTOR,
+ EXPRESSION_GC_SYMBOL,
EXPRESSION_TYPE_INFO,
EXPRESSION_SLICE_INFO,
EXPRESSION_SLICE_VALUE,
@@ -349,6 +350,11 @@ class Expression
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.
@@ -1513,6 +1519,10 @@ class Binary_expression : public Expression
{ 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;
bool
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 654b6c3..dcc2ae6 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -655,9 +655,13 @@ Gogo::backend_zero_value()
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
@@ -6837,8 +6841,10 @@ Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls,
{
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;
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 395b5e5..302faee 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -36,7 +36,8 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
// 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)
{
}
@@ -1236,7 +1237,7 @@ Type::make_type_descriptor_var(Gogo* gogo)
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;
}
@@ -1405,6 +1406,18 @@ Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name)
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.
@@ -1519,14 +1532,15 @@ Type::make_type_descriptor_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",
@@ -1973,7 +1987,7 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
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));
@@ -2019,6 +2033,10 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
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
? name->reflection(gogo)
@@ -2067,6 +2085,160 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
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
@@ -2498,6 +2670,10 @@ class Error_type : public Type
{ 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'); }
};
@@ -2536,6 +2712,10 @@ class Void_type : public Type
{ }
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+ { }
+
+ void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('v'); }
};
@@ -2574,6 +2754,9 @@ class Boolean_type : public Type
{ 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'); }
};
@@ -2593,6 +2776,12 @@ Boolean_type::do_type_descriptor(Gogo* gogo, Named_type* name)
}
}
+// 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()
{
@@ -3102,6 +3291,22 @@ String_type::do_reflection(Gogo*, std::string* ret) const
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
@@ -3173,6 +3378,10 @@ class Sink_type : public Type
{ go_unreachable(); }
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
+ { go_unreachable(); }
+
+ void
do_mangled_name(Gogo*, std::string*) const
{ go_unreachable(); }
};
@@ -3754,6 +3963,25 @@ Function_type::do_reflection(Gogo* gogo, std::string* ret) const
}
}
+// 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
@@ -4156,6 +4384,26 @@ Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const
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
@@ -4236,6 +4484,10 @@ class Nil_type : public Type
{ 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'); }
};
@@ -4293,6 +4545,10 @@ class Call_multiple_result_type : public Type
{ 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()); }
@@ -5319,6 +5575,27 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
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
@@ -6204,6 +6481,115 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
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
@@ -6513,6 +6899,24 @@ Map_type::do_reflection(Gogo* gogo, std::string* ret) const
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
@@ -6686,6 +7090,30 @@ Channel_type::do_reflection(Gogo* gogo, std::string* ret) const
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
@@ -7574,6 +8002,24 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
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
@@ -8810,6 +9256,20 @@ Named_type::do_reflection(Gogo* gogo, std::string* ret) const
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
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 6fa6513..447861c 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -83,6 +83,28 @@ static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
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
@@ -911,6 +933,10 @@ class Type
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;
@@ -996,6 +1022,9 @@ class Type
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;
virtual void
@@ -1050,6 +1079,22 @@ class Type
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
@@ -1126,6 +1171,16 @@ class Type
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
@@ -1253,6 +1308,9 @@ class Type
// 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.
@@ -1507,6 +1565,10 @@ protected:
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;
private:
@@ -1584,6 +1646,10 @@ class Float_type : public Type
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;
private:
@@ -1653,6 +1719,10 @@ class Complex_type : public Type
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;
private:
@@ -1702,6 +1772,9 @@ class String_type : public Type
do_reflection(Gogo*, std::string*) const;
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
do_mangled_name(Gogo*, std::string* ret) const;
private:
@@ -1837,6 +1910,9 @@ class Function_type : public Type
do_reflection(Gogo*, std::string*) const;
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
do_mangled_name(Gogo*, std::string*) const;
void
@@ -1953,6 +2029,9 @@ class Pointer_type : public Type
do_reflection(Gogo*, std::string*) const;
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
do_mangled_name(Gogo*, std::string*) const;
void
@@ -2251,6 +2330,9 @@ class Struct_type : public Type
do_reflection(Gogo*, std::string*) const;
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
do_mangled_name(Gogo*, std::string*) const;
void
@@ -2393,6 +2475,9 @@ class Array_type : public Type
do_reflection(Gogo*, std::string*) const;
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
do_mangled_name(Gogo*, std::string*) const;
void
@@ -2408,6 +2493,12 @@ class Array_type : public Type
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.
@@ -2485,6 +2576,9 @@ class Map_type : public Type
do_reflection(Gogo*, std::string*) const;
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
do_mangled_name(Gogo*, std::string*) const;
void
@@ -2571,6 +2665,9 @@ class Channel_type : public Type
do_reflection(Gogo*, std::string*) const;
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
do_mangled_name(Gogo*, std::string*) const;
void
@@ -2704,6 +2801,9 @@ class Interface_type : public Type
do_reflection(Gogo*, std::string*) const;
void
+ do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
+
+ void
do_mangled_name(Gogo*, std::string*) const;
void
@@ -2989,6 +3089,10 @@ class Named_type : public Type
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
@@ -3133,6 +3237,11 @@ class Forward_declaration_type : public Type
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;
void