diff options
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r-- | gcc/go/gofrontend/backend.h | 46 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 21 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 194 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 1 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 38 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 182 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 31 |
7 files changed, 261 insertions, 252 deletions
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 5ece2e6..b18c18c 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -361,6 +361,52 @@ class Backend bool address_is_taken, source_location location, Bstatement** pstatement) = 0; + // Create a named immutable initialized data structure. This is + // used for type descriptors and map descriptors. This returns a + // Bvariable because it corresponds to an initialized const global + // variable in C. + // + // NAME is the name to use for the initialized global variable which + // this call will create. + // + // IS_COMMON is true if NAME may be defined by several packages, and + // the linker should merge all such definitions. If IS_COMMON is + // false, NAME should be defined in only one file. In general + // IS_COMMON will be true for the type descriptor of an unnamed type + // or a builtin type. + // + // TYPE will be a struct type; the type of the returned expression + // must be a pointer to this struct type. + // + // We must create the named structure before we know its + // initializer, because the initializer refer to its own address. + // After calling this the frontend will call + // set_immutable_struct_initializer. + virtual Bvariable* + immutable_struct(const std::string& name, bool is_common, Btype* type, + source_location) = 0; + + // Set the initial value of a variable created by immutable_struct. + // The NAME, IS_COMMON, TYPE, and location parameters are the same + // ones passed to immutable_struct. INITIALIZER will be a composite + // literal of type TYPE. It will not contain any function calls or + // anything else which can not be put into a read-only data section. + // It may contain the address of variables created by + // immutable_struct. + virtual void + immutable_struct_set_init(Bvariable*, const std::string& name, + bool is_common, Btype* type, source_location, + Bexpression* initializer) = 0; + + // Create a reference to a named immutable initialized data + // structure defined in some other package. This will be a + // structure created by a call to immutable_struct_expression with + // the same NAME and TYPE and with IS_COMMON passed as false. This + // corresponds to an extern const global variable in C. + virtual Bvariable* + immutable_struct_reference(const std::string& name, Btype* type, + source_location) = 0; + // Labels. // Create a new label. NAME will be empty if this is a label diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index f656acb..00af296 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -335,7 +335,7 @@ Expression::convert_type_to_interface(Translate_context* context, // Otherwise it is the interface method table for RHS_TYPE. tree first_field_value; if (lhs_is_empty) - first_field_value = rhs_type->type_descriptor_pointer(gogo); + first_field_value = rhs_type->type_descriptor_pointer(gogo, location); else { // Build the interface method table for this interface and this @@ -492,7 +492,8 @@ Expression::convert_interface_to_interface(Translate_context* context, if (for_type_guard) { // A type assertion fails when converting a nil interface. - tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo); + tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo, + location); static tree assert_interface_decl; tree call = Gogo::call_builtin(&assert_interface_decl, location, @@ -524,7 +525,8 @@ Expression::convert_interface_to_interface(Translate_context* context, // type assertion converting nil will always succeed. go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0); - tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo); + tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo, + location); static tree convert_interface_decl; tree call = Gogo::call_builtin(&convert_interface_decl, location, @@ -578,7 +580,7 @@ Expression::convert_interface_to_type(Translate_context* context, // will panic with an appropriate runtime type error if the type is // not valid. - tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo); + tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo, location); if (!DECL_P(rhs_tree)) rhs_tree = save_expr(rhs_tree); @@ -587,7 +589,8 @@ Expression::convert_interface_to_type(Translate_context* context, Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree, location); - tree rhs_inter_descriptor = rhs_type->type_descriptor_pointer(gogo); + tree rhs_inter_descriptor = rhs_type->type_descriptor_pointer(gogo, + location); static tree check_interface_type_decl; tree call = Gogo::call_builtin(&check_interface_type_decl, @@ -6400,7 +6403,8 @@ Expression::comparison_tree(Translate_context* context, Operator op, } arg = fold_convert_loc(location, ptr_type_node, arg); - tree descriptor = right_type->type_descriptor_pointer(context->gogo()); + tree descriptor = right_type->type_descriptor_pointer(context->gogo(), + location); if (left_type->interface_type()->is_empty()) { @@ -12588,7 +12592,10 @@ class Type_descriptor_expression : public Expression tree do_get_tree(Translate_context* context) - { return this->type_->type_descriptor_pointer(context->gogo()); } + { + return this->type_->type_descriptor_pointer(context->gogo(), + this->location()); + } private: // The type for which this is the descriptor. diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 8c41f74..0c5cb67 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -959,9 +959,9 @@ Named_object::get_tree(Gogo* gogo, Named_object* function) // descriptor, even though we don't do anything with it. if (this->package_ == NULL) { - named_type->type_descriptor_pointer(gogo); + named_type->type_descriptor_pointer(gogo, BUILTINS_LOCATION); Type* pn = Type::make_pointer_type(named_type); - pn->type_descriptor_pointer(gogo); + pn->type_descriptor_pointer(gogo, BUILTINS_LOCATION); } } } @@ -2053,7 +2053,7 @@ Gogo::map_descriptor(Map_type* maptype) constructor_elt* elt = VEC_quick_push(constructor_elt, descriptor, NULL); elt->index = map_descriptor_field; - elt->value = maptype->type_descriptor_pointer(this); + elt->value = maptype->type_descriptor_pointer(this, BUILTINS_LOCATION); elt = VEC_quick_push(constructor_elt, descriptor, NULL); elt->index = entry_size_field; @@ -2109,190 +2109,6 @@ Gogo::map_descriptor_type() sizetype); } -// Return the name to use for a type descriptor decl for TYPE. This -// is used when TYPE does not have a name. - -std::string -Gogo::unnamed_type_descriptor_decl_name(const Type* type) -{ - return "__go_td_" + type->mangled_name(this); -} - -// Return the name to use for a type descriptor decl for a type named -// NAME, defined in the function IN_FUNCTION. IN_FUNCTION will -// normally be NULL. - -std::string -Gogo::type_descriptor_decl_name(const Named_object* no, - const Named_object* in_function) -{ - std::string ret = "__go_tdn_"; - if (no->type_value()->is_builtin()) - go_assert(in_function == NULL); - else - { - const std::string& unique_prefix(no->package() == NULL - ? this->unique_prefix() - : no->package()->unique_prefix()); - const std::string& package_name(no->package() == NULL - ? this->package_name() - : no->package()->name()); - ret.append(unique_prefix); - ret.append(1, '.'); - ret.append(package_name); - ret.append(1, '.'); - if (in_function != NULL) - { - ret.append(Gogo::unpack_hidden_name(in_function->name())); - ret.append(1, '.'); - } - } - ret.append(no->name()); - return ret; -} - -// Where a type descriptor decl should be defined. - -Gogo::Type_descriptor_location -Gogo::type_descriptor_location(const Type* type) -{ - const Named_type* name = type->named_type(); - if (name != NULL) - { - if (name->named_object()->package() != NULL) - { - // This is a named type defined in a different package. The - // descriptor should be defined in that package. - return TYPE_DESCRIPTOR_UNDEFINED; - } - else if (name->is_builtin()) - { - // We create the descriptor for a builtin type whenever we - // need it. - return TYPE_DESCRIPTOR_COMMON; - } - else - { - // This is a named type defined in this package. The - // descriptor should be defined here. - return TYPE_DESCRIPTOR_DEFINED; - } - } - else - { - if (type->points_to() != NULL - && type->points_to()->named_type() != NULL - && type->points_to()->named_type()->named_object()->package() != NULL) - { - // This is an unnamed pointer to a named type defined in a - // different package. The descriptor should be defined in - // that package. - return TYPE_DESCRIPTOR_UNDEFINED; - } - 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. - return TYPE_DESCRIPTOR_COMMON; - } - } -} - -// Build a type descriptor decl for TYPE. INITIALIZER is a struct -// composite literal which initializers the type descriptor. - -void -Gogo::build_type_descriptor_decl(const Type* type, Expression* initializer, - tree* pdecl) -{ - const Named_type* name = type->named_type(); - - // We can have multiple instances of unnamed types, but we only want - // to emit the type descriptor once. We use a hash table to handle - // this. This is not necessary for named types, as they are unique, - // and we store the type descriptor decl in the type itself. - tree* phash = NULL; - if (name == NULL) - { - if (this->type_descriptor_decls_ == NULL) - this->type_descriptor_decls_ = new Type_descriptor_decls(10); - - std::pair<Type_descriptor_decls::iterator, bool> ins = - this->type_descriptor_decls_->insert(std::make_pair(type, NULL_TREE)); - if (!ins.second) - { - // We've already built a type descriptor for this type. - *pdecl = ins.first->second; - return; - } - phash = &ins.first->second; - } - - std::string decl_name; - if (name == NULL) - decl_name = this->unnamed_type_descriptor_decl_name(type); - else - decl_name = this->type_descriptor_decl_name(name->named_object(), - name->in_function()); - tree id = get_identifier_from_string(decl_name); - Type* init_type = initializer->type(); - tree descriptor_type_tree = type_to_tree(init_type->get_backend(this)); - if (descriptor_type_tree == error_mark_node) - { - *pdecl = error_mark_node; - return; - } - tree decl = build_decl(name == NULL ? BUILTINS_LOCATION : name->location(), - VAR_DECL, id, - build_qualified_type(descriptor_type_tree, - TYPE_QUAL_CONST)); - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - - go_preserve_from_gc(decl); - if (phash != NULL) - *phash = decl; - - // We store the new DECL now because we may need to refer to it when - // expanding INITIALIZER. - *pdecl = decl; - - // If appropriate, just refer to the exported type identifier. - Gogo::Type_descriptor_location type_descriptor_location = - this->type_descriptor_location(type); - if (type_descriptor_location == TYPE_DESCRIPTOR_UNDEFINED) - { - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - return; - } - - TREE_STATIC(decl) = 1; - TREE_USED(decl) = 1; - - Translate_context context(this, NULL, NULL, NULL); - context.set_is_const(); - tree constructor = initializer->get_tree(&context); - - if (constructor == error_mark_node) - go_assert(saw_errors()); - - DECL_INITIAL(decl) = constructor; - - if (type_descriptor_location == TYPE_DESCRIPTOR_DEFINED) - TREE_PUBLIC(decl) = 1; - else - { - go_assert(type_descriptor_location == TYPE_DESCRIPTOR_COMMON); - make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); - resolve_unique_section(decl, 1, 0); - } - - rest_of_decl_compilation(decl, 1, 0); -} - // Build an interface method table for a type: a list of function // pointers, one for each interface method. This is used for // interfaces. @@ -2353,8 +2169,8 @@ Gogo::interface_method_table_for_type(const Interface_type* interface, td_type = type; else td_type = Type::make_pointer_type(type); - elt->value = fold_convert(const_ptr_type_node, - td_type->type_descriptor_pointer(this)); + tree tdp = td_type->type_descriptor_pointer(this, BUILTINS_LOCATION); + elt->value = fold_convert(const_ptr_type_node, tdp); size_t i = 1; for (Typed_identifier_list::const_iterator p = interface_methods->begin(); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index c3c014e..484d1a1 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -30,7 +30,6 @@ Gogo::Gogo(Backend* backend, int int_type_size, int pointer_size) imported_unsafe_(false), packages_(), map_descriptors_(NULL), - type_descriptor_decls_(NULL), init_functions_(), need_init_fn_(false), init_fn_name_(), diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index ed9d1eb..972369f 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -483,12 +483,6 @@ class Gogo tree map_descriptor_type(); - // Build a type descriptor for TYPE using INITIALIZER as the type - // descriptor. This builds a new decl stored in *PDECL. - void - build_type_descriptor_decl(const Type*, Expression* initializer, - tree* pdecl); - // Build required interface method tables. void build_interface_method_tables(); @@ -592,32 +586,6 @@ class Gogo tree ptr_go_string_constant_tree(const std::string&); - // Return the name to use for a type descriptor decl for an unnamed - // type. - std::string - unnamed_type_descriptor_decl_name(const Type* type); - - // Return the name to use for a type descriptor decl for a type - // named NO, defined in IN_FUNCTION. - std::string - type_descriptor_decl_name(const Named_object* no, - const Named_object* in_function); - - // Where a type descriptor should be defined. - enum Type_descriptor_location - { - // Defined in this file. - TYPE_DESCRIPTOR_DEFINED, - // Defined in some other file. - TYPE_DESCRIPTOR_UNDEFINED, - // Common definition which may occur in multiple files. - TYPE_DESCRIPTOR_COMMON - }; - - // Return where the decl for TYPE should be defined. - Type_descriptor_location - type_descriptor_location(const Type* type); - // Return the type of a trampoline. static tree trampoline_type_tree(); @@ -635,10 +603,6 @@ class Gogo typedef Unordered_map_hash(const Map_type*, tree, Type_hash_identical, Type_identical) Map_descriptors; - // Map unnamed types to type descriptor decls. - typedef Unordered_map_hash(const Type*, tree, Type_hash_identical, - Type_identical) Type_descriptor_decls; - // The backend generator. Backend* backend_; // The package we are compiling. @@ -657,8 +621,6 @@ class Gogo Packages packages_; // Mapping from map types to map descriptors. Map_descriptors* map_descriptors_; - // Mapping from unnamed types to type descriptor decls. - Type_descriptor_decls* type_descriptor_decls_; // The functions named "init", if there are any. std::vector<Named_object*> init_functions_; // Whether we need a magic initialization function. diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 37cca83..15e35c2 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -37,8 +37,7 @@ extern "C" // Class Type. Type::Type(Type_classification classification) - : classification_(classification), btype_(NULL), - type_descriptor_decl_(NULL_TREE) + : classification_(classification), btype_(NULL), type_descriptor_var_(NULL) { } @@ -926,20 +925,179 @@ Type::do_make_expression_tree(Translate_context*, Expression_list*, // Return a pointer to the type descriptor for this type. tree -Type::type_descriptor_pointer(Gogo* gogo) +Type::type_descriptor_pointer(Gogo* gogo, source_location location) { Type* t = this->forwarded(); - if (t->type_descriptor_decl_ == NULL_TREE) + if (t->type_descriptor_var_ == NULL) { - Expression* e = t->do_type_descriptor(gogo, NULL); - gogo->build_type_descriptor_decl(t, e, &t->type_descriptor_decl_); - go_assert(t->type_descriptor_decl_ != NULL_TREE - && (t->type_descriptor_decl_ == error_mark_node - || DECL_P(t->type_descriptor_decl_))); + t->make_type_descriptor_var(gogo); + go_assert(t->type_descriptor_var_ != NULL); } - if (t->type_descriptor_decl_ == error_mark_node) + tree var_tree = var_to_tree(t->type_descriptor_var_); + if (var_tree == error_mark_node) return error_mark_node; - return build_fold_addr_expr(t->type_descriptor_decl_); + return build_fold_addr_expr_loc(location, var_tree); +} + +// A mapping from unnamed types to type descriptor variables. + +Type::Type_descriptor_vars Type::type_descriptor_vars; + +// Build the type descriptor for this type. + +void +Type::make_type_descriptor_var(Gogo* gogo) +{ + go_assert(this->type_descriptor_var_ == NULL); + + Named_type* nt = this->named_type(); + + // We can have multiple instances of unnamed types, but we only want + // to emit the type descriptor once. We use a hash table. This is + // not necessary for named types, as they are unique, and we store + // the type descriptor in the type itself. + Bvariable** phash = NULL; + if (nt == NULL) + { + Bvariable* bvnull = NULL; + std::pair<Type_descriptor_vars::iterator, bool> ins = + Type::type_descriptor_vars.insert(std::make_pair(this, bvnull)); + if (!ins.second) + { + // We've already build a type descriptor for this type. + this->type_descriptor_var_ = ins.first->second; + return; + } + phash = &ins.first->second; + } + + std::string var_name; + if (nt == NULL) + var_name = this->unnamed_type_descriptor_var_name(gogo); + else + var_name = this->type_descriptor_var_name(gogo); + + // Build the contents of the type descriptor. + Expression* initializer = this->do_type_descriptor(gogo, NULL); + + Btype* initializer_btype = initializer->type()->get_backend(gogo); + + // See if this type descriptor is defined in a different package. + bool is_defined_elsewhere = false; + if (nt != NULL) + { + if (nt->named_object()->package() != NULL) + { + // This is a named type defined in a different package. The + // type descriptor should be defined in that package. + is_defined_elsewhere = true; + } + } + else + { + if (this->points_to() != NULL + && this->points_to()->named_type() != NULL + && this->points_to()->named_type()->named_object()->package() != NULL) + { + // This is an unnamed pointer to a named type defined in a + // different package. The descriptor should be defined in + // that package. + is_defined_elsewhere = true; + } + } + + source_location loc = nt == NULL ? BUILTINS_LOCATION : nt->location(); + + if (is_defined_elsewhere) + { + this->type_descriptor_var_ = + gogo->backend()->immutable_struct_reference(var_name, + initializer_btype, + loc); + if (phash != NULL) + *phash = this->type_descriptor_var_; + return; + } + + // See if this type descriptor can appear in multiple packages. + bool is_common = false; + if (nt != NULL) + { + // We create the descriptor 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; + } + + // We are going to build the type descriptor in this package. We + // must create the variable before we convert the initializer to the + // backend representation, because the initializer may refer to the + // type descriptor of this type. By setting type_descriptor_var_ we + // ensure that type_descriptor_pointer will work if called while + // converting INITIALIZER. + + this->type_descriptor_var_ = + gogo->backend()->immutable_struct(var_name, is_common, initializer_btype, + loc); + if (phash != NULL) + *phash = this->type_descriptor_var_; + + Translate_context context(gogo, NULL, NULL, NULL); + context.set_is_const(); + Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context)); + + gogo->backend()->immutable_struct_set_init(this->type_descriptor_var_, + var_name, is_common, + initializer_btype, loc, + binitializer); +} + +// Return the name of the type descriptor variable for an unnamed +// type. + +std::string +Type::unnamed_type_descriptor_var_name(Gogo* gogo) +{ + return "__go_td_" + this->mangled_name(gogo); +} + +// Return the name of the type descriptor variable for a named type. + +std::string +Type::type_descriptor_var_name(Gogo* gogo) +{ + Named_type* nt = this->named_type(); + Named_object* no = nt->named_object(); + const Named_object* in_function = nt->in_function(); + std::string ret = "__go_tdn_"; + if (nt->is_builtin()) + go_assert(in_function == NULL); + else + { + const std::string& unique_prefix(no->package() == NULL + ? gogo->unique_prefix() + : no->package()->unique_prefix()); + const std::string& package_name(no->package() == NULL + ? gogo->package_name() + : no->package()->name()); + ret.append(unique_prefix); + ret.append(1, '.'); + ret.append(package_name); + ret.append(1, '.'); + if (in_function != NULL) + { + ret.append(Gogo::unpack_hidden_name(in_function->name())); + ret.append(1, '.'); + } + } + ret.append(no->name()); + return ret; } // Return a composite literal for a type descriptor. @@ -5114,7 +5272,7 @@ Channel_type::do_make_expression_tree(Translate_context* context, Type* ptdt = Type::make_type_descriptor_ptr_type(); tree element_type_descriptor = - this->element_type_->type_descriptor_pointer(gogo); + this->element_type_->type_descriptor_pointer(gogo, location); tree bad_index = NULL_TREE; diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 23e29dc..fc35431 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -44,6 +44,7 @@ class Export; class Import; class Btype; class Bexpression; +class Bvariable; // Type codes used in type descriptors. These must match the values // in libgo/runtime/go-type.h. They also match the values in the gc @@ -832,9 +833,10 @@ class Type { return this->do_make_expression_tree(context, args, location); } // Build a type descriptor entry for this type. Return a pointer to - // it. + // it. The location is the location which causes us to need the + // entry. tree - type_descriptor_pointer(Gogo* gogo); + type_descriptor_pointer(Gogo* gogo, source_location); // Return the type reflection string for this type. std::string @@ -1010,6 +1012,25 @@ class Type are_assignable_check_hidden(const Type* lhs, const Type* rhs, bool check_hidden_fields, std::string* reason); + // Map unnamed types to type descriptor decls. + typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical, + Type_identical) Type_descriptor_vars; + + static Type_descriptor_vars type_descriptor_vars; + + // Build the type descriptor variable for this type. + void + make_type_descriptor_var(Gogo*); + + // Return the name of the type descriptor variable for an unnamed + // type. + std::string + unnamed_type_descriptor_var_name(Gogo*); + + // Return the name of the type descriptor variable for a named type. + std::string + type_descriptor_var_name(Gogo*); + // Get the hash and equality functions for a type. void type_functions(const char** hash_fn, const char** equal_fn) const; @@ -1101,9 +1122,9 @@ class Type // The backend representation of the type, once it has been // determined. Btype* btype_; - // The decl for the type descriptor for this type. This starts out - // as NULL and is filled in as needed. - tree type_descriptor_decl_; + // The type descriptor for this type. This starts out as NULL and + // is filled in as needed. + Bvariable* type_descriptor_var_; }; // Type hash table operations. |