diff options
author | Chris Manghane <cmang@google.com> | 2014-09-03 22:56:09 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-09-03 22:56:09 +0000 |
commit | f1d2ac4f84b4b5354779b3b0a0e125b8302ebb49 (patch) | |
tree | ba1dd2b0b5d5bd16e9bc5c7dce503f320e8a896a /gcc/go/gofrontend | |
parent | d2e4feca24b91fd1a3e4e42f8ef82b19d0df5853 (diff) | |
download | gcc-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.h | 55 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 88 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 10 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 12 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 470 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 109 |
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 |