Mercurial > hg > CbC > CbC_gcc
diff gcc/go/gofrontend/export.cc @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/go/gofrontend/export.cc Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/go/gofrontend/export.cc Thu Oct 25 07:37:49 2018 +0900 @@ -26,25 +26,67 @@ // Current version magic string. const char Export::cur_magic[Export::magic_len] = { - 'v', '2', ';', '\n' + 'v', '3', ';', '\n' }; -// Magic string for previous version (still supported) +// Magic strings for previous versions (still supported). const char Export::v1_magic[Export::magic_len] = { 'v', '1', ';', '\n' }; +const char Export::v2_magic[Export::magic_len] = + { + 'v', '2', ';', '\n' + }; const int Export::checksum_len; // Constructor. Export::Export(Stream* stream) - : stream_(stream), type_refs_(), type_index_(1), packages_() + : 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 +{ + public: + unsigned int + operator()(const Type* type) const + { + return type->hash_for_method(NULL, + (Type::COMPARE_ERRORS + | Type::COMPARE_TAGS + | Type::COMPARE_ALIASES)); + } +}; + +class Type_alias_identical +{ + public: + bool + operator()(const Type* t1, const Type* t2) const + { + return Type::are_identical(t1, t2, + (Type::COMPARE_ERRORS + | Type::COMPARE_TAGS + | 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. + +typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical, + Type_alias_identical) Type_refs; + +static Type_refs type_refs; + // A functor to sort Named_object pointers by name. struct Sort_bindings @@ -71,12 +113,8 @@ if (Gogo::is_hidden_name(no->name())) return false; - // We don't export nested functions. - if (no->is_function() && no->func_value()->enclosing() != NULL) - return false; - - // We don't export thunks. - if (no->is_function() && Gogo::is_thunk(no)) + // We don't export various special functions. + if (Gogo::is_special_name(no->name())) return false; // Methods are exported with the type, not here. @@ -139,6 +177,11 @@ std::sort(exports.begin(), exports.end(), Sort_bindings()); + // 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); + // Although the export data is readable, at least this version is, // it is conceptually a binary format. Start with a four byte // version number. @@ -147,7 +190,7 @@ // The package name. this->write_c_string("package "); this->write_string(package_name); - this->write_c_string(";\n"); + this->write_c_string("\n"); // The prefix or package path, used for all global symbols. if (prefix.empty()) @@ -161,11 +204,11 @@ this->write_c_string("prefix "); this->write_string(prefix); } - this->write_c_string(";\n"); + this->write_c_string("\n"); this->write_packages(packages); - this->write_imports(imports); + this->write_imports(imports, type_imports); this->write_imported_init_fns(package_name, import_init_fn, imported_init_fns); @@ -174,10 +217,17 @@ // and ABI being used, although ideally any problems in that area // would be caught by the linker. + // Write out all the types, both exported and not. + 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(); ++p) - (*p)->export_named_object(this); + { + if (!(*p)->is_type()) + (*p)->export_named_object(this); + } std::string checksum = this->stream_->checksum(); std::string s = "checksum "; @@ -191,10 +241,239 @@ dig = c & 0xf; s += dig < 10 ? '0' + dig : 'A' + dig - 10; } - s += ";\n"; + s += "\n"; 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. + +bool +Export::set_type_index(Type* type) +{ + type = type->forwarded(); + + std::pair<Type_refs::iterator, bool> ins = + type_refs.insert(std::make_pair(type, 0)); + if (!ins.second) + { + // We've already seen this type. + return false; + } + + int index = this->type_index_; + ++this->type_index_; + ins.first->second = index; + + return true; +} + // Sort packages. static bool @@ -233,7 +512,7 @@ this->write_string((*p)->pkgpath()); this->write_c_string(" "); this->write_string((*p)->pkgpath_symbol()); - this->write_c_string(";\n"); + this->write_c_string("\n"); } } @@ -249,14 +528,19 @@ // Write out the imported packages. void -Export::write_imports(const std::map<std::string, Package*>& imports) +Export::write_imports(const std::map<std::string, Package*>& imports, + const Unordered_set(const Package*)& type_imports) { // Sort the imports for more consistent output. + Unordered_set(const Package*) seen; std::vector<std::pair<std::string, Package*> > sorted_imports; for (std::map<std::string, Package*>::const_iterator p = imports.begin(); p != imports.end(); ++p) - sorted_imports.push_back(std::make_pair(p->first, p->second)); + { + sorted_imports.push_back(std::make_pair(p->first, p->second)); + seen.insert(p->second); + } std::sort(sorted_imports.begin(), sorted_imports.end(), import_compare); @@ -271,10 +555,36 @@ this->write_string(p->second->pkgpath()); this->write_c_string(" \""); this->write_string(p->first); - this->write_c_string("\";\n"); + this->write_c_string("\"\n"); this->packages_.insert(p->second); } + + // 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(); + ++p) + { + if (seen.find(*p) == seen.end()) + indirect_imports.push_back(*p); + } + + std::sort(indirect_imports.begin(), indirect_imports.end(), + packages_compare); + + for (std::vector<const Package*>::const_iterator p = + indirect_imports.begin(); + p != indirect_imports.end(); + ++p) + { + this->write_c_string("indirectimport "); + this->write_string((*p)->package_name()); + this->write_c_string(" "); + this->write_string((*p)->pkgpath()); + this->write_c_string("\n"); + } } void @@ -347,7 +657,7 @@ if (imported_init_fns.empty()) { - this->write_c_string(";\n"); + this->write_c_string("\n"); return; } @@ -394,7 +704,7 @@ it->second.push_back(ii->init_name()); } } - this->write_c_string(";\n"); + this->write_c_string("\n"); // Create the init graph. Start by populating the graph with // all the edges we inherited from imported packages. @@ -494,7 +804,105 @@ this->write_unsigned(sink); } } - this->write_c_string(";\n"); + this->write_c_string("\n"); +} + +// Write the types to the export stream. + +void +Export::write_types(int unexported_type_index) +{ + // 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(); + ++p) + { + if (p->second >= 0) + types.at(p->second) = p->first; + } + + // Write the type information to a buffer. + Stream_to_string type_data; + Export::Stream* orig_stream = this->stream_; + this->stream_ = &type_data; + + std::vector<size_t> type_sizes(static_cast<size_t>(this->type_index_)); + type_sizes[0] = 0; + + // Start at 1 because type index 0 is not used. + size_t start_size = 0; + for (int i = 1; i < this->type_index_; ++i) + { + this->write_type_definition(types[i], i); + + size_t cur_size = type_data.string().size(); + type_sizes[i] = cur_size - start_size; + start_size = cur_size; + } + + // Back to original stream. + this->stream_ = orig_stream; + + // The line "types MAXP1 EXPORTEDP1 SIZES..." appears before the + // types. MAXP1 is one more than the maximum type index used; that + // is, it is the size of the array we need to allocate to hold all + // the values. Indexes 1 up to but not including EXPORTEDP1 are the + // exported types. The other types are not exported. SIZES... is a + // list of MAXP1-1 entries listing the size of the type definition + // for each type, starting at index 1. + char buf[100]; + snprintf(buf, sizeof buf, "types %d %d", this->type_index_, + unexported_type_index); + this->write_c_string(buf); + + // Start at 1 because type index 0 is not used. + for (int i = 1; i < this->type_index_; ++i) + { + snprintf(buf, sizeof buf, " %lu", + static_cast<unsigned long>(type_sizes[i])); + this->write_c_string(buf); + } + this->write_c_string("\n"); + this->write_string(type_data.string()); +} + +// Write a single type to the export stream. + +void +Export::write_type_definition(const Type* type, int index) +{ + this->write_c_string("type "); + + char buf[30]; + snprintf(buf, sizeof buf, "%d ", index); + this->write_c_string(buf); + + const Named_type* nt = type->named_type(); + if (nt != NULL) + { + const Named_object* no = nt->named_object(); + const Package* package = no->package(); + + this->write_c_string("\""); + if (package != NULL && !Gogo::is_hidden_name(no->name())) + { + this->write_string(package->pkgpath()); + this->write_c_string("."); + } + this->write_string(nt->named_object()->name()); + this->write_c_string("\" "); + + if (nt->is_alias()) + this->write_c_string("= "); + } + + type->export_type(this); + + // Type::export_type will print a newline for a named type, but not + // otherwise. + if (nt == NULL) + this->write_c_string("\n"); } // Write a name to the export stream. @@ -528,104 +936,19 @@ this->write_c_string(buf); } -// Export a type. We have to ensure that on import we create a single -// Named_type node for each named type. We do this by keeping a hash -// table mapping named types to reference numbers. The first time we -// see a named type we assign it a reference number by making an entry -// in the hash table. If we see it again, we just refer to the -// reference number. - -// Named types are, of course, associated with packages. Note that we -// may see a named type when importing one package, and then later see -// the same named type when importing a different package. The home -// package may or may not be imported during this compilation. The -// reference number scheme has to get this all right. Basic approach -// taken from "On the Linearization of Graphs and Writing Symbol -// Files" by Robert Griesemer. +// Export a type. void Export::write_type(const Type* type) { - // We don't want to assign a reference number to a forward - // declaration to a type which was defined later. type = type->forwarded(); - - Type_refs::const_iterator p = this->type_refs_.find(type); - if (p != this->type_refs_.end()) - { - // This type was already in the table. - int index = p->second; - go_assert(index != 0); - char buf[30]; - snprintf(buf, sizeof buf, "<type %d>", index); - this->write_c_string(buf); - return; - } - - const Named_type* named_type = type->named_type(); - const Forward_declaration_type* forward = type->forward_declaration_type(); - - int index = this->type_index_; - ++this->type_index_; - + Type_refs::const_iterator p = type_refs.find(type); + go_assert(p != type_refs.end()); + int index = p->second; + go_assert(index != 0); char buf[30]; - snprintf(buf, sizeof buf, "<type %d ", index); + snprintf(buf, sizeof buf, "<type %d>", index); this->write_c_string(buf); - - if (named_type != NULL || forward != NULL) - { - const Named_object* named_object; - if (named_type != NULL) - { - // The builtin types should have been predefined. - go_assert(!Linemap::is_predeclared_location(named_type->location()) - || (named_type->named_object()->package()->package_name() - == "unsafe")); - named_object = named_type->named_object(); - } - else - named_object = forward->named_object(); - - const Package* package = named_object->package(); - - std::string s = "\""; - if (package != NULL && !Gogo::is_hidden_name(named_object->name())) - { - s += package->pkgpath(); - s += '.'; - } - s += named_object->name(); - s += "\" "; - this->write_string(s); - - // It is possible that this type was imported indirectly, and is - // not in a package in the import list. If we have not - // mentioned this package before, write out the package name - // here so that any package importing this one will know it. - if (package != NULL - && this->packages_.find(package) == this->packages_.end()) - { - this->write_c_string("\""); - this->write_string(package->package_name()); - this->packages_.insert(package); - this->write_c_string("\" "); - } - - // We must add a named type to the table now, since the - // definition of the type may refer to the named type via a - // pointer. - this->type_refs_[type] = index; - - if (named_type != NULL && named_type->is_alias()) - this->write_c_string("= "); - } - - type->export_type(this); - - this->write_c_string(">"); - - if (named_type == NULL) - this->type_refs_[type] = index; } // Export escape note. @@ -678,18 +1001,15 @@ Named_object* named_object = gogo->lookup_global(name); go_assert(named_object != NULL && named_object->is_type()); std::pair<Type_refs::iterator, bool> ins = - this->type_refs_.insert(std::make_pair(named_object->type_value(), code)); + 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 - // type at least for string and bool. We skip the type aliases byte - // and rune here. - if (code != BUILTIN_BYTE && code != BUILTIN_RUNE) - { - Type* real_type = named_object->type_value()->real_type(); - ins = this->type_refs_.insert(std::make_pair(real_type, code)); - go_assert(ins.second); - } + // type at least for string and bool. It's OK if this insert + // 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)); } // Class Export::Stream.