Mercurial > hg > CbC > CbC_gcc
diff gcc/go/gofrontend/export.cc @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
line wrap: on
line diff
--- a/gcc/go/gofrontend/export.cc Thu Oct 25 07:37:49 2018 +0900 +++ b/gcc/go/gofrontend/export.cc Thu Feb 13 11:34:05 2020 +0900 @@ -6,14 +6,14 @@ #include "go-system.h" +#include "go-c.h" +#include "go-diagnostics.h" #include "go-sha1.h" -#include "go-c.h" - #include "gogo.h" #include "types.h" +#include "expressions.h" #include "statements.h" #include "export.h" - #include "go-linemap.h" #include "backend.h" @@ -41,14 +41,6 @@ const int Export::checksum_len; -// Constructor. - -Export::Export(Stream* stream) - : stream_(stream), type_index_(1), packages_() -{ - go_assert(Export::checksum_len == Go_sha1_helper::checksum_len); -} - // Type hash table operations, treating aliases as distinct. class Type_hash_alias_identical @@ -60,6 +52,7 @@ return type->hash_for_method(NULL, (Type::COMPARE_ERRORS | Type::COMPARE_TAGS + | Type::COMPARE_EMBEDDED_INTERFACES | Type::COMPARE_ALIASES)); } }; @@ -73,28 +66,382 @@ return Type::are_identical(t1, t2, (Type::COMPARE_ERRORS | Type::COMPARE_TAGS + | Type::COMPARE_EMBEDDED_INTERFACES | Type::COMPARE_ALIASES), NULL); } }; -// Mapping from Type objects to a constant index. This would be nicer -// as a field in Export, but then export.h would have to #include -// types.h. +// Mapping from Type objects to a constant index. +typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical, + Type_alias_identical) Type_refs; + +// Implementation object for class Export. Hidden implementation avoids +// having to #include types.h in export.h, or use a static map. + +struct Export_impl { + Type_refs type_refs; +}; + +// Constructor. + +Export::Export(Stream* stream) + : stream_(stream), type_index_(1), packages_(), impl_(new Export_impl) +{ + go_assert(Export::checksum_len == Go_sha1_helper::checksum_len); +} + +// Destructor. + +Export::~Export() +{ + delete this->impl_; +} + +// A traversal class to collect functions and global variables +// referenced by inlined functions, and also to gather up +// referenced types that need to be included in the exports. + +class Collect_export_references : public Traverse +{ + public: + Collect_export_references(Export* exp, + Unordered_set(Named_object*)* exports, + Unordered_set(const Package*)* imports) + : Traverse(traverse_expressions + | traverse_types), + exp_(exp), exports_(exports), imports_(imports), + inline_fcn_worklist_(NULL), exports_finalized_(false) + { } + + // Initial entry point; performs a walk to expand the exports set. + void + expand_exports(std::vector<Named_object*>* inlinable_functions); + + // Second entry point (called after the method above), to find + // all types referenced by exports. + void + prepare_types(const std::vector<Named_object*>& sorted_exports); + + protected: + // Override of parent class method. + int + expression(Expression**); + + // Override of parent class method. + int + type(Type* type); + + // Traverse the components of a function type. + void + traverse_function_type(Function_type*); + + // Traverse the methods of a named type, and register its package. + void + traverse_named_type(Named_type*); + + private: + + // Add a named object to the exports set (during expand_exports()). + // Returns TRUE if a new object was added to the exports set, + // FALSE otherwise. + bool + add_to_exports(Named_object*); + + // The exporter. + Export* exp_; + // The set of named objects to export. + Unordered_set(Named_object*)* exports_; + // Set containing all directly and indirectly imported packages. + Unordered_set(const Package*)* imports_; + // Functions we've already traversed and don't need to visit again. + Unordered_set(Named_object*) checked_functions_; + // Worklist of functions we are exporting with inline bodies that need + // to be checked. + std::vector<Named_object*>* inline_fcn_worklist_; + // Set to true if expand_exports() has been called and is complete. + bool exports_finalized_; +}; -typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical, - Type_alias_identical) Type_refs; +void +Collect_export_references::expand_exports(std::vector<Named_object*>* fcns) +{ + this->inline_fcn_worklist_ = fcns; + while (!this->inline_fcn_worklist_->empty()) + { + Named_object* no = this->inline_fcn_worklist_->back(); + this->inline_fcn_worklist_->pop_back(); + std::pair<Unordered_set(Named_object*)::iterator, bool> ins = + this->checked_functions_.insert(no); + if (ins.second) + { + // This traversal may add new objects to this->exports_ and new + // functions to this->inline_fcn_worklist_. + no->func_value()->block()->traverse(this); + } + } + this->inline_fcn_worklist_ = NULL; + this->exports_finalized_ = true; +} + +bool +Collect_export_references::add_to_exports(Named_object* no) +{ + std::pair<Unordered_set(Named_object*)::iterator, bool> ins = + this->exports_->insert(no); + // If the export list has been finalized, then we should not be + // adding anything new to the exports set. + go_assert(!this->exports_finalized_ || !ins.second); + return ins.second; +} + +int +Collect_export_references::expression(Expression** pexpr) +{ + const Expression* expr = *pexpr; + + const Var_expression* ve = expr->var_expression(); + if (ve != NULL) + { + Named_object* no = ve->named_object(); + if (no->is_variable() && no->var_value()->is_global()) + { + const Package* var_package = no->package(); + if (var_package != NULL) + this->imports_->insert(var_package); -static Type_refs type_refs; + this->add_to_exports(no); + no->var_value()->set_is_referenced_by_inline(); + } + return TRAVERSE_CONTINUE; + } + + const Func_expression* fe = expr->func_expression(); + if (fe != NULL) + { + Named_object* no = fe->named_object(); + + const Package* func_package = fe->named_object()->package(); + if (func_package != NULL) + this->imports_->insert(func_package); + + if (no->is_function_declaration() + && no->func_declaration_value()->type()->is_builtin()) + return TRAVERSE_CONTINUE; + + if (this->inline_fcn_worklist_ != NULL) + { + bool added = this->add_to_exports(no); + + if (no->is_function()) + no->func_value()->set_is_referenced_by_inline(); + + // If 'added' is false then this object was already in + // exports_, in which case it was already added to + // check_inline_refs_ the first time we added it to exports_, so + // we don't need to add it again. + if (added + && no->is_function() + && no->func_value()->export_for_inlining()) + this->inline_fcn_worklist_->push_back(no); + } + + return TRAVERSE_CONTINUE; + } + + const Named_object* nco = expr->named_constant(); + if (nco != 0) + { + const Named_constant *nc = nco->const_value(); + Type::traverse(nc->type(), this); + return TRAVERSE_CONTINUE; + } -// A functor to sort Named_object pointers by name. + return TRAVERSE_CONTINUE; +} + +// Collect up the set of types mentioned in things we're exporting, and collect +// all the packages encountered during type traversal, to make sure we can +// declare things referered to indirectly (for example, in the body of an +// exported inline function from another package). + +void +Collect_export_references::prepare_types(const std::vector<Named_object*>& sorted_exports) +{ + // Iterate through the exported objects and traverse any types encountered. + for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin(); + p != sorted_exports.end(); + ++p) + { + Named_object* no = *p; + switch (no->classification()) + { + case Named_object::NAMED_OBJECT_CONST: + { + Type* t = no->const_value()->type(); + if (t != NULL && !t->is_abstract()) + Type::traverse(t, this); + } + break; -struct Sort_bindings + case Named_object::NAMED_OBJECT_TYPE: + Type::traverse(no->type_value()->real_type(), this); + this->traverse_named_type(no->type_value()); + break; + + case Named_object::NAMED_OBJECT_VAR: + Type::traverse(no->var_value()->type(), this); + break; + + case Named_object::NAMED_OBJECT_FUNC: + { + Function* fn = no->func_value(); + this->traverse_function_type(fn->type()); + if (fn->export_for_inlining()) + fn->block()->traverse(this); + } + break; + + case Named_object::NAMED_OBJECT_FUNC_DECLARATION: + this->traverse_function_type(no->func_declaration_value()->type()); + break; + + default: + // We shouldn't see anything else. If we do we'll give an + // error later when we try to actually export it. + break; + } + } +} + +// Record referenced type, record package imports, and make sure we traverse +// methods of named types. + +int +Collect_export_references::type(Type* type) { - bool - operator()(const Named_object* n1, const Named_object* n2) const - { return n1->name() < n2->name(); } -}; + // Skip forwarders; don't try to give them a type index. + if (type->forward_declaration_type() != NULL) + return TRAVERSE_CONTINUE; + + // Skip the void type, which we'll see when exporting + // unsafe.Pointer. The void type is not itself exported, because + // Pointer_type::do_export checks for it. + if (type->is_void_type()) + return TRAVERSE_SKIP_COMPONENTS; + + // Skip the nil type, turns up in function bodies. + if (type->is_nil_type()) + return TRAVERSE_SKIP_COMPONENTS; + + // Skip abstract types. We should never see these in real code, + // only in things like const declarations. + if (type->is_abstract()) + return TRAVERSE_SKIP_COMPONENTS; + + // For interfaces make sure that embedded methods are sorted, since the + // comparison function we use for indexing types relies on it (this call has + // to happen before the record_type call below). + if (type->classification() == Type::TYPE_INTERFACE) + { + Interface_type* it = type->interface_type(); + if (it != NULL) + it->sort_embedded(); + } + + if (!this->exp_->record_type(type)) + { + // We've already seen this type. + return TRAVERSE_SKIP_COMPONENTS; + } + + // At this stage of compilation traversing interface types traverses + // the final list of methods, but we export the locally defined + // methods. If there is an embedded interface type we need to make + // sure to export that. Check classification, rather than calling + // the interface_type method, because we want to handle named types + // below. + if (type->classification() == Type::TYPE_INTERFACE) + { + Interface_type* it = type->interface_type(); + const Typed_identifier_list* methods = it->local_methods(); + if (methods != NULL) + { + for (Typed_identifier_list::const_iterator p = methods->begin(); + p != methods->end(); + ++p) + { + if (p->name().empty()) + Type::traverse(p->type(), this); + else + this->traverse_function_type(p->type()->function_type()); + } + } + return TRAVERSE_SKIP_COMPONENTS; + } + + Named_type* nt = type->named_type(); + if (nt != NULL) + this->traverse_named_type(nt); + + return TRAVERSE_CONTINUE; +} + +void +Collect_export_references::traverse_named_type(Named_type* nt) +{ + const Package* package = nt->named_object()->package(); + if (package != NULL) + this->imports_->insert(package); + + // We have to traverse the methods of named types, because we are + // going to export them. This is not done by ordinary type + // traversal. + const Bindings* methods = nt->local_methods(); + if (methods != NULL) + { + for (Bindings::const_definitions_iterator pm = + methods->begin_definitions(); + pm != methods->end_definitions(); + ++pm) + { + Function* fn = (*pm)->func_value(); + this->traverse_function_type(fn->type()); + if (fn->export_for_inlining()) + fn->block()->traverse(this); + } + + for (Bindings::const_declarations_iterator pm = + methods->begin_declarations(); + pm != methods->end_declarations(); + ++pm) + { + Named_object* mno = pm->second; + if (mno->is_function_declaration()) + this->traverse_function_type(mno->func_declaration_value()->type()); + } + } +} + +// Traverse the types in a function type. We don't need the function +// type itself, just the receiver, parameter, and result types. + +void +Collect_export_references::traverse_function_type(Function_type* type) +{ + go_assert(type != NULL); + if (this->remember_type(type)) + return; + const Typed_identifier* receiver = type->receiver(); + if (receiver != NULL) + Type::traverse(receiver->type(), this); + const Typed_identifier_list* parameters = type->parameters(); + if (parameters != NULL) + parameters->traverse(this); + const Typed_identifier_list* results = type->results(); + if (results != NULL) + results->traverse(this); +} // Return true if we should export NO. @@ -133,6 +480,54 @@ return true; } +// A functor to sort Named_object pointers by name. + +struct Sort_bindings +{ + bool + operator()(const Named_object* n1, const Named_object* n2) const + { + if (n1->package() != n2->package()) + { + if (n1->package() == NULL) + return true; + if (n2->package() == NULL) + return false; + return n1->package()->pkgpath() < n2->package()->pkgpath(); + } + + return n1->name() < n2->name(); + } +}; + +// A functor to sort types for export. + +struct Sort_types +{ + bool + operator()(const Type* t1, const Type* t2) const + { + const Named_type* nt1 = t1->named_type(); + const Named_type* nt2 = t2->named_type(); + if (nt1 != NULL) + { + if (nt2 != NULL) + { + Sort_bindings sb; + return sb(nt1->named_object(), nt2->named_object()); + } + else + return true; + } + else if (nt2 != NULL) + return false; + if (t1->classification() != t2->classification()) + return t1->classification() < t2->classification(); + Gogo* gogo = go_get_gogo(); + return gogo->type_descriptor_name(t1, NULL).compare(gogo->type_descriptor_name(t2, NULL)) < 0; + } +}; + // Export those identifiers marked for exporting. void @@ -143,7 +538,8 @@ const std::map<std::string, Package*>& imports, const std::string& import_init_fn, const Import_init_set& imported_init_fns, - const Bindings* bindings) + const Bindings* bindings, + Unordered_set(Named_object*)* functions_marked_inline) { // If there have been any errors so far, don't try to export // anything. That way the export code doesn't have to worry about @@ -151,17 +547,28 @@ if (saw_errors()) return; - // Export the symbols in sorted order. That will reduce cases where - // irrelevant changes to the source code affect the exported - // interface. - std::vector<Named_object*> exports; - exports.reserve(bindings->size_definitions()); + // EXPORTS is the set of objects to export. CHECK_INLINE_REFS is a + // list of exported function with inline bodies that need to be + // checked for references to other objects. Every function on + // CHECK_INLINE_REFS is also on EXPORTS. + Unordered_set(Named_object*) exports; + std::vector<Named_object*> check_inline_refs; + check_inline_refs.reserve(functions_marked_inline->size()); + + // Add all functions/methods from the "marked inlined" set to the + // CHECK_INLINE_REFS worklist. + for (Unordered_set(Named_object*)::const_iterator p = functions_marked_inline->begin(); + p != functions_marked_inline->end(); + ++p) + check_inline_refs.push_back(*p); for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); p != bindings->end_definitions(); ++p) - if (should_export(*p)) - exports.push_back(*p); + { + if (should_export(*p)) + exports.insert(*p); + } for (Bindings::const_declarations_iterator p = bindings->begin_declarations(); @@ -172,15 +579,45 @@ // supporting C code. We do not export type declarations. if (p->second->is_function_declaration() && should_export(p->second)) - exports.push_back(p->second); + exports.insert(p->second); } - std::sort(exports.begin(), exports.end(), Sort_bindings()); + // Track all imported packages mentioned in export data. + Unordered_set(const Package*) all_imports; + + Collect_export_references collect(this, &exports, &all_imports); + + // Walk the set of inlinable routine bodies collected above. This + // can potentially expand the exports set. + collect.expand_exports(&check_inline_refs); + + // Export the symbols in sorted order. That will reduce cases where + // irrelevant changes to the source code affect the exported + // interface. + std::vector<Named_object*> sorted_exports; + sorted_exports.reserve(exports.size()); + + for (Unordered_set(Named_object*)::const_iterator p = exports.begin(); + p != exports.end(); + ++p) + { + sorted_exports.push_back(*p); + + const Package* pkg = (*p)->package(); + if (pkg != NULL) + all_imports.insert(pkg); + } + + std::sort(sorted_exports.begin(), sorted_exports.end(), Sort_bindings()); + + // Collect up the set of types mentioned in things we're exporting, + // and any packages that may be referred to indirectly. + collect.prepare_types(sorted_exports); // Assign indexes to all exported types and types referenced by - // exported types, and collect all packages mentioned. - Unordered_set(const Package*) type_imports; - int unexported_type_index = this->prepare_types(&exports, &type_imports); + // things we're exporting. Return value is index of first non-exported + // type. + int unexported_type_index = this->assign_type_indices(sorted_exports); // Although the export data is readable, at least this version is, // it is conceptually a binary format. Start with a four byte @@ -208,7 +645,7 @@ this->write_packages(packages); - this->write_imports(imports, type_imports); + this->write_imports(imports, all_imports); this->write_imported_init_fns(package_name, import_init_fn, imported_init_fns); @@ -221,8 +658,8 @@ this->write_types(unexported_type_index); // Write out the non-type export data. - for (std::vector<Named_object*>::const_iterator p = exports.begin(); - p != exports.end(); + for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin(); + p != sorted_exports.end(); ++p) { if (!(*p)->is_type()) @@ -245,233 +682,88 @@ this->stream_->write_checksum(s); } -// Traversal class to find referenced types. - -class Find_types_to_prepare : public Traverse -{ - public: - Find_types_to_prepare(Export* exp, - Unordered_set(const Package*)* imports) - : Traverse(traverse_types), - exp_(exp), imports_(imports) - { } - - int - type(Type* type); - - // Traverse the components of a function type. - void - traverse_function(Function_type*); - - // Traverse the methods of a named type, and register its package. - void - traverse_named_type(Named_type*); - - private: - // Exporters. - Export* exp_; - // List of packages we are building. - Unordered_set(const Package*)* imports_; -}; - -// Set type index of referenced type, record package imports, and make -// sure we traverse methods of named types. - -int -Find_types_to_prepare::type(Type* type) -{ - // Skip forwarders; don't try to give them a type index. - if (type->forward_declaration_type() != NULL) - return TRAVERSE_CONTINUE; - - // Skip the void type, which we'll see when exporting - // unsafe.Pointer. The void type is not itself exported, because - // Pointer_type::do_export checks for it. - if (type->is_void_type()) - return TRAVERSE_SKIP_COMPONENTS; - - if (!this->exp_->set_type_index(type)) - { - // We've already seen this type. - return TRAVERSE_SKIP_COMPONENTS; - } - - // At this stage of compilation traversing interface types traverses - // the final list of methods, but we export the locally defined - // methods. If there is an embedded interface type we need to make - // sure to export that. Check classification, rather than calling - // the interface_type method, because we want to handle named types - // below. - if (type->classification() == Type::TYPE_INTERFACE) - { - Interface_type* it = type->interface_type(); - const Typed_identifier_list* methods = it->local_methods(); - if (methods != NULL) - { - for (Typed_identifier_list::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - { - if (p->name().empty()) - Type::traverse(p->type(), this); - else - this->traverse_function(p->type()->function_type()); - } - } - return TRAVERSE_SKIP_COMPONENTS; - } - - Named_type* nt = type->named_type(); - if (nt != NULL) - this->traverse_named_type(nt); - - return TRAVERSE_CONTINUE; -} - -// Traverse the types in a function type. We don't need the function -// type itself, just the receiver, parameter, and result types. - -void -Find_types_to_prepare::traverse_function(Function_type* type) -{ - go_assert(type != NULL); - if (this->remember_type(type)) - return; - const Typed_identifier* receiver = type->receiver(); - if (receiver != NULL) - Type::traverse(receiver->type(), this); - const Typed_identifier_list* parameters = type->parameters(); - if (parameters != NULL) - parameters->traverse(this); - const Typed_identifier_list* results = type->results(); - if (results != NULL) - results->traverse(this); -} - -// Traverse the methods of a named type, and record its package. - -void -Find_types_to_prepare::traverse_named_type(Named_type* nt) -{ - const Package* package = nt->named_object()->package(); - if (package != NULL) - this->imports_->insert(package); - - // We have to traverse the methods of named types, because we are - // going to export them. This is not done by ordinary type - // traversal. - const Bindings* methods = nt->local_methods(); - if (methods != NULL) - { - for (Bindings::const_definitions_iterator pm = - methods->begin_definitions(); - pm != methods->end_definitions(); - ++pm) - this->traverse_function((*pm)->func_value()->type()); - - for (Bindings::const_declarations_iterator pm = - methods->begin_declarations(); - pm != methods->end_declarations(); - ++pm) - { - Named_object* mno = pm->second; - if (mno->is_function_declaration()) - this->traverse_function(mno->func_declaration_value()->type()); - } - } -} - -// Prepare to export types by assigning a type index to every exported -// type and every type referenced by an exported type. Also collect -// all the packages we see in types, so that if we refer to any types -// from indirectly imported packages we can tell the importer about -// the package. This returns the number of exported types. - -int -Export::prepare_types(const std::vector<Named_object*>* exports, - Unordered_set(const Package*)* imports) -{ - // Assign indexes to all the exported types. - for (std::vector<Named_object*>::const_iterator p = exports->begin(); - p != exports->end(); - ++p) - { - if (!(*p)->is_type()) - continue; - this->set_type_index((*p)->type_value()); - } - - int ret = this->type_index_; - - // Use a single instance of the traversal class because traversal - // classes keep track of which types they've already seen. That - // lets us avoid type reference loops. - Find_types_to_prepare find(this, imports); - - // Traverse all the exported objects and assign indexes to all types. - for (std::vector<Named_object*>::const_iterator p = exports->begin(); - p != exports->end(); - ++p) - { - Named_object* no = *p; - switch (no->classification()) - { - case Named_object::NAMED_OBJECT_CONST: - { - Type* t = no->const_value()->type(); - if (t != NULL && !t->is_abstract()) - Type::traverse(t, &find); - } - break; - - case Named_object::NAMED_OBJECT_TYPE: - Type::traverse(no->type_value()->real_type(), &find); - find.traverse_named_type(no->type_value()); - break; - - case Named_object::NAMED_OBJECT_VAR: - Type::traverse(no->var_value()->type(), &find); - break; - - case Named_object::NAMED_OBJECT_FUNC: - find.traverse_function(no->func_value()->type()); - break; - - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - find.traverse_function(no->func_declaration_value()->type()); - break; - - default: - // We shouldn't see anything else. If we do we'll give an - // error later when we try to actually export it. - break; - } - } - - return ret; -} - -// Give a type an index if it doesn't already have one. Return true -// if we set the type index, false if it was already known. +// Record a type in the "to be indexed" set. Return true if the type +// was not already in the set, false otherwise. bool -Export::set_type_index(Type* type) +Export::record_type(Type* type) { type = type->forwarded(); std::pair<Type_refs::iterator, bool> ins = - type_refs.insert(std::make_pair(type, 0)); + this->impl_->type_refs.insert(std::make_pair(type, 0)); if (!ins.second) { // We've already seen this type. return false; } + ins.first->second = 0; + return true; +} + +// Assign the specified type an index. + +void +Export::set_type_index(const Type* type) +{ + type = type->forwarded(); + std::pair<Type_refs::iterator, bool> ins = + this->impl_->type_refs.insert(std::make_pair(type, 0)); + go_assert(!ins.second); int index = this->type_index_; ++this->type_index_; + go_assert(ins.first->second == 0); ins.first->second = index; +} + +// This helper assigns type indices to all types mentioned directly or +// indirectly in the things we're exporting. Actual exported types are given +// indices according to where the appear on the sorted exports list; all other +// types appear afterwards. Return value is the total number of exported types +// plus 1, e.g. the index of the 1st non-exported type. - return true; +int +Export::assign_type_indices(const std::vector<Named_object*>& sorted_exports) +{ + // Assign indexes to all the exported types. + for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin(); + p != sorted_exports.end(); + ++p) + { + if (!(*p)->is_type()) + continue; + Interface_type* it = (*p)->type_value()->interface_type(); + if (it != NULL) + it->sort_embedded(); + this->record_type((*p)->type_value()); + this->set_type_index((*p)->type_value()); + } + int ret = this->type_index_; + + // Collect export-referenced, non-builtin types. + std::vector<const Type*> types; + types.reserve(this->impl_->type_refs.size()); + for (Type_refs::const_iterator p = this->impl_->type_refs.begin(); + p != this->impl_->type_refs.end(); + ++p) + { + const Type* t = p->first; + if (p->second != 0) + continue; + types.push_back(t); + } + + // Sort the types. + std::sort(types.begin(), types.end(), Sort_types()); + + // Assign numbers to the sorted list. + for (std::vector<const Type *>::const_iterator p = types.begin(); + p != types.end(); + ++p) + this->set_type_index((*p)); + + return ret; } // Sort packages. @@ -479,7 +771,24 @@ static bool packages_compare(const Package* a, const Package* b) { - return a->package_name() < b->package_name(); + if (a->package_name() < b->package_name()) + return true; + else if (a->package_name() > b->package_name()) + return false; + + if (a->pkgpath() < b->pkgpath()) + return true; + else if (a->pkgpath() > b->pkgpath()) + return false; + + // In principle if we get here then a == b. Try to do something sensible + // even if the import information is inconsistent. + if (a->pkgpath_symbol() < b->pkgpath_symbol()) + return true; + else if (a->pkgpath_symbol() > b->pkgpath_symbol()) + return false; + + return a < b; } // Write out all the known packages whose pkgpath symbol is not a @@ -529,7 +838,7 @@ void Export::write_imports(const std::map<std::string, Package*>& imports, - const Unordered_set(const Package*)& type_imports) + const Unordered_set(const Package*)& all_imports) { // Sort the imports for more consistent output. Unordered_set(const Package*) seen; @@ -544,6 +853,7 @@ std::sort(sorted_imports.begin(), sorted_imports.end(), import_compare); + int package_index = 1; for (std::vector<std::pair<std::string, Package*> >::const_iterator p = sorted_imports.begin(); p != sorted_imports.end(); @@ -557,14 +867,15 @@ this->write_string(p->first); this->write_c_string("\"\n"); - this->packages_.insert(p->second); + this->packages_[p->second] = package_index; + package_index++; } // Write out a separate list of indirectly imported packages. std::vector<const Package*> indirect_imports; for (Unordered_set(const Package*)::const_iterator p = - type_imports.begin(); - p != type_imports.end(); + all_imports.begin(); + p != all_imports.end(); ++p) { if (seen.find(*p) == seen.end()) @@ -584,6 +895,9 @@ this->write_c_string(" "); this->write_string((*p)->pkgpath()); this->write_c_string("\n"); + + this->packages_[*p] = package_index; + package_index++; } } @@ -614,6 +928,8 @@ ++p) { const Import_init* ii = *p; + if (ii->is_dummy()) + continue; std::map<std::string, unsigned>::const_iterator srcit = init_idx.find(ii->init_name()); go_assert(srcit != init_idx.end()); @@ -712,7 +1028,7 @@ // Now add edges from the local init function to each of the // imported fcns. - if (!import_init_fn.empty()) + if (!import_init_fn.empty() && import_init_fn[0] != '~') { unsigned src = 0; go_assert(init_idx[import_init_fn] == 0); @@ -721,6 +1037,8 @@ ++p) { const Import_init* ii = *p; + if (ii->is_dummy()) + continue; unsigned sink = init_idx[ii->init_name()]; add_init_graph_edge(&init_graph, src, sink); } @@ -814,8 +1132,8 @@ { // Map from type index to type. std::vector<const Type*> types(static_cast<size_t>(this->type_index_)); - for (Type_refs::const_iterator p = type_refs.begin(); - p != type_refs.end(); + for (Type_refs::const_iterator p = this->impl_->type_refs.begin(); + p != this->impl_->type_refs.end(); ++p) { if (p->second >= 0) @@ -913,7 +1231,7 @@ if (name.empty()) this->write_c_string("?"); else - this->write_string(Gogo::message_name(name)); + this->write_string(Gogo::unpack_hidden_name(name)); } // Write an integer value to the export stream. @@ -936,21 +1254,54 @@ this->write_c_string(buf); } +// Return the index of a package. + +int +Export::package_index(const Package* pkg) const +{ + Unordered_map(const Package *, int)::const_iterator p = + this->packages_.find(pkg); + go_assert(p != this->packages_.end()); + int index = p->second; + go_assert(index != 0); + return index; +} + +// Return the index of a type. + +int +Export::type_index(const Type* type) +{ + type = type->forwarded(); + Type_refs::const_iterator p = this->impl_->type_refs.find(type); + go_assert(p != this->impl_->type_refs.end()); + int index = p->second; + go_assert(index != 0); + return index; +} + // Export a type. void Export::write_type(const Type* type) { - type = type->forwarded(); - Type_refs::const_iterator p = type_refs.find(type); - go_assert(p != type_refs.end()); - int index = p->second; - go_assert(index != 0); + int index = this->type_index(type); char buf[30]; snprintf(buf, sizeof buf, "<type %d>", index); this->write_c_string(buf); } +// Export a type to a function body. + +void +Export::write_type_to(const Type* type, Export_function_body* efb) +{ + int index = this->type_index(type); + char buf[30]; + snprintf(buf, sizeof buf, "<type %d>", index); + efb->write_c_string(buf); +} + // Export escape note. void @@ -1001,7 +1352,7 @@ Named_object* named_object = gogo->lookup_global(name); go_assert(named_object != NULL && named_object->is_type()); std::pair<Type_refs::iterator, bool> ins = - type_refs.insert(std::make_pair(named_object->type_value(), code)); + this->impl_->type_refs.insert(std::make_pair(named_object->type_value(), code)); go_assert(ins.second); // We also insert the underlying type. We can see the underlying @@ -1009,7 +1360,7 @@ // fails--we expect duplications here, and it doesn't matter when // they occur. Type* real_type = named_object->type_value()->real_type(); - type_refs.insert(std::make_pair(real_type, code)); + this->impl_->type_refs.insert(std::make_pair(real_type, code)); } // Class Export::Stream. @@ -1066,3 +1417,56 @@ { this->backend_->write_export_data (bytes, length); } + +// Class Export_function_body. + +// Record a temporary statement. + +unsigned int +Export_function_body::record_temporary(const Temporary_statement* temp) +{ + unsigned int ret = this->next_temporary_index_; + if (ret > 0x7fffffff) + go_error_at(temp->location(), + "too many temporary statements in export data"); + ++this->next_temporary_index_; + std::pair<const Temporary_statement*, unsigned int> val(temp, ret); + std::pair<Unordered_map(const Temporary_statement*, unsigned int)::iterator, + bool> ins = this->temporary_indexes_.insert(val); + go_assert(ins.second); + return ret; +} + +// Return the index of a temporary statement. + +unsigned int +Export_function_body::temporary_index(const Temporary_statement* temp) +{ + Unordered_map(const Temporary_statement*, unsigned int)::const_iterator p = + this->temporary_indexes_.find(temp); + go_assert(p != this->temporary_indexes_.end()); + return p->second; +} + +// Return the index of an unnamed label. If it doesn't already have +// an index, give it one. + +unsigned int +Export_function_body::unnamed_label_index(const Unnamed_label* label) +{ + unsigned int next = this->next_label_index_; + std::pair<const Unnamed_label*, unsigned int> val(label, next); + std::pair<Unordered_map(const Unnamed_label*, unsigned int)::iterator, + bool> ins = + this->label_indexes_.insert(val); + if (!ins.second) + return ins.first->second; + else + { + if (next > 0x7fffffff) + go_error_at(label->location(), + "too many unnamed labels in export data"); + ++this->next_label_index_; + return next; + } +}