123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- // export.cc -- Export declarations in Go frontend.
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- #include "go-system.h"
- #include "sha1.h"
- #include "go-c.h"
- #include "gogo.h"
- #include "types.h"
- #include "statements.h"
- #include "export.h"
- // This file handles exporting global declarations.
- // Class Export.
- // Version 1 magic number.
- const int Export::v1_magic_len;
- const char Export::v1_magic[Export::v1_magic_len] =
- {
- 'v', '1', ';', '\n'
- };
- const int Export::v1_checksum_len;
- // Constructor.
- Export::Export(Stream* stream)
- : stream_(stream), type_refs_(), type_index_(1), packages_()
- {
- }
- // A functor to sort Named_object pointers by name.
- struct Sort_bindings
- {
- bool
- operator()(const Named_object* n1, const Named_object* n2) const
- { return n1->name() < n2->name(); }
- };
- // Return true if we should export NO.
- static bool
- should_export(Named_object* no)
- {
- // We only export objects which are locally defined.
- if (no->package() != NULL)
- return false;
- // We don't export packages.
- if (no->is_package())
- return false;
- // We don't export hidden names.
- 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))
- return false;
- // Methods are exported with the type, not here.
- if (no->is_function()
- && no->func_value()->type()->is_method())
- return false;
- if (no->is_function_declaration()
- && no->func_declaration_value()->type()->is_method())
- return false;
- // Don't export dummy global variables created for initializers when
- // used with sinks.
- if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.')
- return false;
- return true;
- }
- // Export those identifiers marked for exporting.
- void
- Export::export_globals(const std::string& package_name,
- const std::string& prefix,
- const std::string& pkgpath,
- int package_priority,
- const std::map<std::string, Package*>& packages,
- const std::map<std::string, Package*>& imports,
- const std::string& import_init_fn,
- const std::set<Import_init>& imported_init_fns,
- const Bindings* bindings)
- {
- // 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
- // mismatched types or other confusions.
- 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());
- for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
- p != bindings->end_definitions();
- ++p)
- if (should_export(*p))
- exports.push_back(*p);
- for (Bindings::const_declarations_iterator p =
- bindings->begin_declarations();
- p != bindings->end_declarations();
- ++p)
- {
- // We export a function declaration as it may be implemented in
- // supporting C code. We do not export type declarations.
- if (p->second->is_function_declaration()
- && should_export(p->second))
- exports.push_back(p->second);
- }
- std::sort(exports.begin(), exports.end(), Sort_bindings());
- // Although the export data is readable, at least this version is,
- // it is conceptually a binary format. Start with a four byte
- // verison number.
- this->write_bytes(Export::v1_magic, Export::v1_magic_len);
- // The package name.
- this->write_c_string("package ");
- this->write_string(package_name);
- this->write_c_string(";\n");
- // The prefix or package path, used for all global symbols.
- if (prefix.empty())
- {
- go_assert(!pkgpath.empty());
- this->write_c_string("pkgpath ");
- this->write_string(pkgpath);
- }
- else
- {
- this->write_c_string("prefix ");
- this->write_string(prefix);
- }
- this->write_c_string(";\n");
- // The package priority.
- char buf[100];
- snprintf(buf, sizeof buf, "priority %d;\n", package_priority);
- this->write_c_string(buf);
- this->write_packages(packages);
- this->write_imports(imports);
- this->write_imported_init_fns(package_name, package_priority, import_init_fn,
- imported_init_fns);
- // FIXME: It might be clever to add something about the processor
- // and ABI being used, although ideally any problems in that area
- // would be caught by the linker.
- for (std::vector<Named_object*>::const_iterator p = exports.begin();
- p != exports.end();
- ++p)
- (*p)->export_named_object(this);
- std::string checksum = this->stream_->checksum();
- std::string s = "checksum ";
- for (std::string::const_iterator p = checksum.begin();
- p != checksum.end();
- ++p)
- {
- unsigned char c = *p;
- unsigned int dig = c >> 4;
- s += dig < 10 ? '0' + dig : 'A' + dig - 10;
- dig = c & 0xf;
- s += dig < 10 ? '0' + dig : 'A' + dig - 10;
- }
- s += ";\n";
- this->stream_->write_checksum(s);
- }
- // Sort packages.
- static bool
- packages_compare(const Package* a, const Package* b)
- {
- return a->package_name() < b->package_name();
- }
- // Write out all the known packages whose pkgpath symbol is not a
- // simple transformation of the pkgpath, so that the importing code
- // can reliably know it.
- void
- Export::write_packages(const std::map<std::string, Package*>& packages)
- {
- // Sort for consistent output.
- std::vector<Package*> out;
- for (std::map<std::string, Package*>::const_iterator p = packages.begin();
- p != packages.end();
- ++p)
- {
- if (p->second->pkgpath_symbol()
- != Gogo::pkgpath_for_symbol(p->second->pkgpath()))
- out.push_back(p->second);
- }
- std::sort(out.begin(), out.end(), packages_compare);
- for (std::vector<Package*>::const_iterator p = out.begin();
- p != out.end();
- ++p)
- {
- this->write_c_string("package ");
- this->write_string((*p)->package_name());
- this->write_c_string(" ");
- this->write_string((*p)->pkgpath());
- this->write_c_string(" ");
- this->write_string((*p)->pkgpath_symbol());
- this->write_c_string(";\n");
- }
- }
- // Sort imported packages.
- static bool
- import_compare(const std::pair<std::string, Package*>& a,
- const std::pair<std::string, Package*>& b)
- {
- return a.first < b.first;
- }
- // Write out the imported packages.
- void
- Export::write_imports(const std::map<std::string, Package*>& imports)
- {
- // Sort the imports for more consistent output.
- std::vector<std::pair<std::string, Package*> > imp;
- for (std::map<std::string, Package*>::const_iterator p = imports.begin();
- p != imports.end();
- ++p)
- imp.push_back(std::make_pair(p->first, p->second));
- std::sort(imp.begin(), imp.end(), import_compare);
- for (std::vector<std::pair<std::string, Package*> >::const_iterator p =
- imp.begin();
- p != imp.end();
- ++p)
- {
- this->write_c_string("import ");
- this->write_string(p->second->package_name());
- this->write_c_string(" ");
- this->write_string(p->second->pkgpath());
- this->write_c_string(" \"");
- this->write_string(p->first);
- this->write_c_string("\";\n");
- this->packages_.insert(p->second);
- }
- }
- // Write out the initialization functions which need to run for this
- // package.
- void
- Export::write_imported_init_fns(
- const std::string& package_name,
- int priority,
- const std::string& import_init_fn,
- const std::set<Import_init>& imported_init_fns)
- {
- if (import_init_fn.empty() && imported_init_fns.empty())
- return;
- this->write_c_string("init");
- if (!import_init_fn.empty())
- {
- this->write_c_string(" ");
- this->write_string(package_name);
- this->write_c_string(" ");
- this->write_string(import_init_fn);
- char buf[100];
- snprintf(buf, sizeof buf, " %d", priority);
- this->write_c_string(buf);
- }
- if (!imported_init_fns.empty())
- {
- // Sort the list of functions for more consistent output.
- std::vector<Import_init> v;
- for (std::set<Import_init>::const_iterator p = imported_init_fns.begin();
- p != imported_init_fns.end();
- ++p)
- v.push_back(*p);
- std::sort(v.begin(), v.end());
- for (std::vector<Import_init>::const_iterator p = v.begin();
- p != v.end();
- ++p)
- {
- this->write_c_string(" ");
- this->write_string(p->package_name());
- this->write_c_string(" ");
- this->write_string(p->init_name());
- char buf[100];
- snprintf(buf, sizeof buf, " %d", p->priority());
- this->write_c_string(buf);
- }
- }
- this->write_c_string(";\n");
- }
- // Write a name to the export stream.
- void
- Export::write_name(const std::string& name)
- {
- if (name.empty())
- this->write_c_string("?");
- else
- this->write_string(Gogo::message_name(name));
- }
- // 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.
- 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_;
- char buf[30];
- 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;
- }
- type->export_type(this);
- this->write_c_string(">");
- if (named_type == NULL)
- this->type_refs_[type] = index;
- }
- // Add the builtin types to the export table.
- void
- Export::register_builtin_types(Gogo* gogo)
- {
- this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
- this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
- this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
- this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
- this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
- this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
- this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
- this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
- this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
- this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
- this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
- this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
- this->register_builtin_type(gogo, "int", BUILTIN_INT);
- this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
- this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
- this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
- this->register_builtin_type(gogo, "string", BUILTIN_STRING);
- this->register_builtin_type(gogo, "error", BUILTIN_ERROR);
- this->register_builtin_type(gogo, "byte", BUILTIN_BYTE);
- this->register_builtin_type(gogo, "rune", BUILTIN_RUNE);
- }
- // Register one builtin type in the export table.
- void
- Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
- {
- 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));
- 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);
- }
- }
- // Class Export::Stream.
- Export::Stream::Stream()
- {
- this->checksum_ = new sha1_ctx;
- memset(this->checksum_, 0, sizeof(sha1_ctx));
- sha1_init_ctx(this->checksum_);
- }
- Export::Stream::~Stream()
- {
- }
- // Write bytes to the stream. This keeps a checksum of bytes as they
- // go by.
- void
- Export::Stream::write_and_sum_bytes(const char* bytes, size_t length)
- {
- sha1_process_bytes(bytes, length, this->checksum_);
- this->do_write(bytes, length);
- }
- // Get the checksum.
- std::string
- Export::Stream::checksum()
- {
- // Use a union to provide the required alignment.
- union
- {
- char checksum[Export::v1_checksum_len];
- long align;
- } u;
- sha1_finish_ctx(this->checksum_, u.checksum);
- return std::string(u.checksum, Export::v1_checksum_len);
- }
- // Write the checksum string to the export data.
- void
- Export::Stream::write_checksum(const std::string& s)
- {
- this->do_write(s.data(), s.length());
- }
- // Class Stream_to_section.
- Stream_to_section::Stream_to_section()
- {
- }
- // Write data to a section.
- void
- Stream_to_section::do_write(const char* bytes, size_t length)
- {
- go_write_export_data (bytes, length);
- }
|