Commit c0ccddb4 by Ian Lance Taylor

compiler: revamp scheme for ordering calls to import init fcns.

    
    Switch to a new method for determining the order in which import init
    functions are invoked: build an init fcn dependence DAG and walk the DAG
    to rewrite/adjust priorities to account for discrepancies introduced by
    "go test".
    
    This patch includes a change to the export data format generated
    by gccgo. Older versions of gccgo will not be able to read object files
    produced by a newer gccgo, but the new gcc will still be able to read
    old object files.
    
    Fixes golang/go#15738.
    
    Reviewed-on: https://go-review.googlesource.com/25301

From-SVN: r239708
parent 9f589786
0476944600d456b2616981fff90c77be5e06edd5 0e505f5d191182abd8beb9b4c8232174bc116f97
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -15,6 +15,7 @@ class Import_init; ...@@ -15,6 +15,7 @@ class Import_init;
class Bindings; class Bindings;
class Type; class Type;
class Package; class Package;
class Import_init_set;
// Codes used for the builtin types. These are all negative to make // Codes used for the builtin types. These are all negative to make
// them easily distinct from the codes assigned by Export::write_type. // them easily distinct from the codes assigned by Export::write_type.
...@@ -47,6 +48,17 @@ enum Builtin_code ...@@ -47,6 +48,17 @@ enum Builtin_code
SMALLEST_BUILTIN_CODE = -21 SMALLEST_BUILTIN_CODE = -21
}; };
// Export data version number. New export data is written with the
// "current" version, but there is support for reading files with
// older version export data (at least for now).
enum Export_data_version {
EXPORT_FORMAT_UNKNOWN = 0,
EXPORT_FORMAT_V1 = 1,
EXPORT_FORMAT_V2 = 2,
EXPORT_FORMAT_CURRENT = EXPORT_FORMAT_V2
};
// This class manages exporting Go declarations. It handles the main // This class manages exporting Go declarations. It handles the main
// loop of exporting. A pointer to this class is also passed to the // loop of exporting. A pointer to this class is also passed to the
// various specific export implementations. // various specific export implementations.
...@@ -103,12 +115,15 @@ class Export : public String_dump ...@@ -103,12 +115,15 @@ class Export : public String_dump
Export(Stream*); Export(Stream*);
// The magic code for version 1 export data. // Size of export data magic string (which includes version number).
static const int v1_magic_len = 4; static const int magic_len = 4;
static const char v1_magic[v1_magic_len];
// The length of the v1 checksum string. // Magic strings (current version and older v1 version).
static const int v1_checksum_len = 20; static const char cur_magic[magic_len];
static const char v1_magic[magic_len];
// The length of the checksum string.
static const int checksum_len = 20;
// Register the builtin types. // Register the builtin types.
void void
...@@ -119,7 +134,6 @@ class Export : public String_dump ...@@ -119,7 +134,6 @@ class Export : public String_dump
// is nothing to export, this->stream_->write will not be called. // is nothing to export, this->stream_->write will not be called.
// PREFIX is the package prefix. PKGPATH is the package path. // PREFIX is the package prefix. PKGPATH is the package path.
// Only one of PREFIX and PKGPATH will be non-empty. // Only one of PREFIX and PKGPATH will be non-empty.
// PACKAGE_PRIORITY is the priority to use for this package.
// PACKAGES is all the packages we have seen. // PACKAGES is all the packages we have seen.
// IMPORTS is the explicitly imported packages. // IMPORTS is the explicitly imported packages.
// IMPORT_INIT_FN is the name of the import initialization function // IMPORT_INIT_FN is the name of the import initialization function
...@@ -130,11 +144,10 @@ class Export : public String_dump ...@@ -130,11 +144,10 @@ class Export : public String_dump
export_globals(const std::string& package_name, export_globals(const std::string& package_name,
const std::string& prefix, const std::string& prefix,
const std::string& pkgpath, const std::string& pkgpath,
int package_priority,
const std::map<std::string, Package*>& packages, const std::map<std::string, Package*>& packages,
const std::map<std::string, Package*>& imports, const std::map<std::string, Package*>& imports,
const std::string& import_init_fn, const std::string& import_init_fn,
const std::set<Import_init>& imported_init_fns, const Import_init_set& imported_init_fns,
const Bindings* bindings); const Bindings* bindings);
// Write a string to the export stream. // Write a string to the export stream.
...@@ -166,6 +179,14 @@ class Export : public String_dump ...@@ -166,6 +179,14 @@ class Export : public String_dump
void void
write_escape(std::string* note); write_escape(std::string* note);
// Write an integer value.
void
write_int(int);
// Write an unsigned value.
void
write_unsigned(unsigned);
private: private:
Export(const Export&); Export(const Export&);
Export& operator=(const Export&); Export& operator=(const Export&);
...@@ -174,14 +195,24 @@ class Export : public String_dump ...@@ -174,14 +195,24 @@ class Export : public String_dump
void void
write_packages(const std::map<std::string, Package*>& packages); write_packages(const std::map<std::string, Package*>& packages);
typedef std::map<unsigned, std::set<unsigned> > Init_graph;
static void
add_init_graph_edge(Init_graph* init_graph, unsigned src, unsigned sink);
static void
populate_init_graph(Init_graph* init_graph,
const Import_init_set& imported_init_fns,
const std::map<std::string, unsigned>& init_idx);
// Write out the imported packages. // Write out the imported packages.
void void
write_imports(const std::map<std::string, Package*>& imports); write_imports(const std::map<std::string, Package*>& imports);
// Write out the imported initialization functions. // Write out the imported initialization functions and init graph.
void void
write_imported_init_fns(const std::string& package_name, int priority, write_imported_init_fns(const std::string& package_name,
const std::string&, const std::set<Import_init>&); const std::string&, const Import_init_set&);
// Register one builtin type. // Register one builtin type.
void void
......
...@@ -513,40 +513,49 @@ Gogo::import_package(const std::string& filename, ...@@ -513,40 +513,49 @@ Gogo::import_package(const std::string& filename,
delete stream; delete stream;
} }
Import_init *
Gogo::lookup_init(const std::string& init_name)
{
Import_init tmp("", init_name, -1);
Import_init_set::iterator it = this->imported_init_fns_.find(&tmp);
return (it != this->imported_init_fns_.end()) ? *it : NULL;
}
// Add an import control function for an imported package to the list. // Add an import control function for an imported package to the list.
void void
Gogo::add_import_init_fn(const std::string& package_name, Gogo::add_import_init_fn(const std::string& package_name,
const std::string& init_name, int prio) const std::string& init_name, int prio)
{ {
for (std::set<Import_init>::const_iterator p = for (Import_init_set::iterator p =
this->imported_init_fns_.begin(); this->imported_init_fns_.begin();
p != this->imported_init_fns_.end(); p != this->imported_init_fns_.end();
++p) ++p)
{ {
if (p->init_name() == init_name) Import_init *ii = (*p);
if (ii->init_name() == init_name)
{ {
// If a test of package P1, built as part of package P1, // If a test of package P1, built as part of package P1,
// imports package P2, and P2 imports P1 (perhaps // imports package P2, and P2 imports P1 (perhaps
// indirectly), then we will see the same import name with // indirectly), then we will see the same import name with
// different import priorities. That is OK, so don't give // different import priorities. That is OK, so don't give
// an error about it. // an error about it.
if (p->package_name() != package_name) if (ii->package_name() != package_name)
{ {
error("duplicate package initialization name %qs", error("duplicate package initialization name %qs",
Gogo::message_name(init_name).c_str()); Gogo::message_name(init_name).c_str());
inform(UNKNOWN_LOCATION, "used by package %qs at priority %d", inform(UNKNOWN_LOCATION, "used by package %qs",
Gogo::message_name(p->package_name()).c_str(), Gogo::message_name(ii->package_name()).c_str());
p->priority()); inform(UNKNOWN_LOCATION, " and by package %qs",
inform(UNKNOWN_LOCATION, " and by package %qs at priority %d", Gogo::message_name(package_name).c_str());
Gogo::message_name(package_name).c_str(), prio);
} }
return; ii->set_priority(prio);
return;
} }
} }
this->imported_init_fns_.insert(Import_init(package_name, init_name, Import_init* nii = new Import_init(package_name, init_name, prio);
prio)); this->imported_init_fns_.insert(nii);
} }
// Return whether we are at the global binding level. // Return whether we are at the global binding level.
...@@ -581,6 +590,62 @@ Gogo::current_bindings() const ...@@ -581,6 +590,62 @@ Gogo::current_bindings() const
return this->globals_; return this->globals_;
} }
void
Gogo::update_init_priority(Import_init* ii,
std::set<const Import_init *>* visited)
{
visited->insert(ii);
int succ_prior = -1;
for (std::set<std::string>::const_iterator pci =
ii->precursors().begin();
pci != ii->precursors().end();
++pci)
{
Import_init* succ = this->lookup_init(*pci);
if (visited->find(succ) == visited->end())
update_init_priority(succ, visited);
succ_prior = std::max(succ_prior, succ->priority());
}
if (ii->priority() <= succ_prior)
ii->set_priority(succ_prior + 1);
}
void
Gogo::recompute_init_priorities()
{
std::set<Import_init *> nonroots;
for (Import_init_set::const_iterator p =
this->imported_init_fns_.begin();
p != this->imported_init_fns_.end();
++p)
{
const Import_init *ii = *p;
for (std::set<std::string>::const_iterator pci =
ii->precursors().begin();
pci != ii->precursors().end();
++pci)
{
Import_init* ii = this->lookup_init(*pci);
nonroots.insert(ii);
}
}
// Recursively update priorities starting at roots.
std::set<const Import_init*> visited;
for (Import_init_set::iterator p =
this->imported_init_fns_.begin();
p != this->imported_init_fns_.end();
++p)
{
Import_init* ii = *p;
if (nonroots.find(ii) != nonroots.end())
continue;
update_init_priority(ii, &visited);
}
}
// Add statements to INIT_STMTS which run the initialization // Add statements to INIT_STMTS which run the initialization
// functions for imported packages. This is only used for the "main" // functions for imported packages. This is only used for the "main"
// package. // package.
...@@ -598,23 +663,27 @@ Gogo::init_imports(std::vector<Bstatement*>& init_stmts) ...@@ -598,23 +663,27 @@ Gogo::init_imports(std::vector<Bstatement*>& init_stmts)
Type::make_function_type(NULL, NULL, NULL, unknown_loc); Type::make_function_type(NULL, NULL, NULL, unknown_loc);
Btype* fntype = func_type->get_backend_fntype(this); Btype* fntype = func_type->get_backend_fntype(this);
// Recompute init priorities based on a walk of the init graph.
recompute_init_priorities();
// We must call them in increasing priority order. // We must call them in increasing priority order.
std::vector<Import_init> v; std::vector<const Import_init*> v;
for (std::set<Import_init>::const_iterator p = for (Import_init_set::const_iterator p =
this->imported_init_fns_.begin(); this->imported_init_fns_.begin();
p != this->imported_init_fns_.end(); p != this->imported_init_fns_.end();
++p) ++p)
v.push_back(*p); v.push_back(*p);
std::sort(v.begin(), v.end()); std::sort(v.begin(), v.end(), priority_compare);
// We build calls to the init functions, which take no arguments. // We build calls to the init functions, which take no arguments.
std::vector<Bexpression*> empty_args; std::vector<Bexpression*> empty_args;
for (std::vector<Import_init>::const_iterator p = v.begin(); for (std::vector<const Import_init*>::const_iterator p = v.begin();
p != v.end(); p != v.end();
++p) ++p)
{ {
std::string user_name = p->package_name() + ".init"; const Import_init* ii = *p;
const std::string& init_name(p->init_name()); std::string user_name = ii->package_name() + ".init";
const std::string& init_name(ii->init_name());
Bfunction* pfunc = this->backend()->function(fntype, user_name, init_name, Bfunction* pfunc = this->backend()->function(fntype, user_name, init_name,
true, true, true, false, true, true, true, false,
...@@ -4326,21 +4395,6 @@ Gogo::check_return_statements() ...@@ -4326,21 +4395,6 @@ Gogo::check_return_statements()
this->traverse(&traverse); this->traverse(&traverse);
} }
// Work out the package priority. It is one more than the maximum
// priority of an imported package.
int
Gogo::package_priority() const
{
int priority = 0;
for (Packages::const_iterator p = this->packages_.begin();
p != this->packages_.end();
++p)
if (p->second->priority() > priority)
priority = p->second->priority();
return priority + 1;
}
// Export identifiers as requested. // Export identifiers as requested.
void void
...@@ -4368,7 +4422,6 @@ Gogo::do_exports() ...@@ -4368,7 +4422,6 @@ Gogo::do_exports()
exp.export_globals(this->package_name(), exp.export_globals(this->package_name(),
prefix, prefix,
pkgpath, pkgpath,
this->package_priority(),
this->packages_, this->packages_,
this->imports_, this->imports_,
(this->need_init_fn_ && !this->is_main_package() (this->need_init_fn_ && !this->is_main_package()
...@@ -7595,11 +7648,10 @@ Unnamed_label::get_goto(Translate_context* context, Location location) ...@@ -7595,11 +7648,10 @@ Unnamed_label::get_goto(Translate_context* context, Location location)
Package::Package(const std::string& pkgpath, Package::Package(const std::string& pkgpath,
const std::string& pkgpath_symbol, Location location) const std::string& pkgpath_symbol, Location location)
: pkgpath_(pkgpath), pkgpath_symbol_(pkgpath_symbol), : pkgpath_(pkgpath), pkgpath_symbol_(pkgpath_symbol),
package_name_(), bindings_(new Bindings(NULL)), priority_(0), package_name_(), bindings_(new Bindings(NULL)),
location_(location) location_(location)
{ {
go_assert(!pkgpath.empty()); go_assert(!pkgpath.empty());
} }
// Set the package name. // Set the package name.
...@@ -7640,16 +7692,6 @@ Package::set_pkgpath_symbol(const std::string& pkgpath_symbol) ...@@ -7640,16 +7692,6 @@ Package::set_pkgpath_symbol(const std::string& pkgpath_symbol)
go_assert(this->pkgpath_symbol_ == pkgpath_symbol); go_assert(this->pkgpath_symbol_ == pkgpath_symbol);
} }
// Set the priority. We may see multiple priorities for an imported
// package; we want to use the largest one.
void
Package::set_priority(int priority)
{
if (priority > this->priority_)
this->priority_ = priority;
}
// Note that symbol from this package was and qualified by ALIAS. // Note that symbol from this package was and qualified by ALIAS.
void void
......
...@@ -78,33 +78,64 @@ class Import_init ...@@ -78,33 +78,64 @@ class Import_init
init_name() const init_name() const
{ return this->init_name_; } { return this->init_name_; }
// The priority of the initialization function. Functions with a // Older V1 export data uses a priority scheme to order
// lower priority number must be run first. // initialization functions; functions with a lower priority number
// must be run first. This value will be set to -1 for current
// generation objects, and will take on a non-negative value only
// when importing a V1-vintage object.
int int
priority() const priority() const
{ return this->priority_; } { return this->priority_; }
// Reset priority.
void
set_priority(int new_priority)
{ this->priority_ = new_priority; }
// Record the fact that some other init fcn must be run before this init fcn.
void
record_precursor_fcn(std::string init_fcn_name)
{ this->precursor_functions_.insert(init_fcn_name); }
// Return the list of precursor fcns for this fcn (must be run before it).
const std::set<std::string>&
precursors() const
{ return this->precursor_functions_; }
private: private:
// The name of the package being imported. // The name of the package being imported.
std::string package_name_; std::string package_name_;
// The name of the package's init function. // The name of the package's init function.
std::string init_name_; std::string init_name_;
// The priority. // Names of init functions that must be run before this fcn.
std::set<std::string> precursor_functions_;
// Priority for this function. See note above on obsolescence.
int priority_; int priority_;
}; };
// For sorting purposes. // For sorting purposes.
struct Import_init_lt {
bool operator()(const Import_init* i1, const Import_init* i2)
{
return i1->init_name() < i2->init_name();
}
};
// Set of import init objects.
class Import_init_set : public std::set<Import_init*, Import_init_lt> {
};
inline bool inline bool
operator<(const Import_init& i1, const Import_init& i2) priority_compare(const Import_init* i1, const Import_init* i2)
{ {
if (i1.priority() < i2.priority()) if (i1->priority() < i2->priority())
return true; return true;
if (i1.priority() > i2.priority()) if (i1->priority() > i2->priority())
return false; return false;
if (i1.package_name() != i2.package_name()) if (i1->package_name() != i2->package_name())
return i1.package_name() < i2.package_name(); return i1->package_name() < i2->package_name();
return i1.init_name() < i2.init_name(); return i1->init_name() < i2->init_name();
} }
// The holder for the internal representation of the entire // The holder for the internal representation of the entire
...@@ -249,12 +280,6 @@ class Gogo ...@@ -249,12 +280,6 @@ class Gogo
set_debug_escape_level(int level) set_debug_escape_level(int level)
{ this->debug_escape_level_ = level; } { this->debug_escape_level_ = level; }
// Return the priority to use for the package we are compiling.
// This is two more than the largest priority of any package we
// import.
int
package_priority() const;
// Import a package. FILENAME is the file name argument, LOCAL_NAME // Import a package. FILENAME is the file name argument, LOCAL_NAME
// is the local name to give to the package. If LOCAL_NAME is empty // is the local name to give to the package. If LOCAL_NAME is empty
// the declarations are added to the global scope. // the declarations are added to the global scope.
...@@ -609,6 +634,10 @@ class Gogo ...@@ -609,6 +634,10 @@ class Gogo
add_import_init_fn(const std::string& package_name, add_import_init_fn(const std::string& package_name,
const std::string& init_name, int prio); const std::string& init_name, int prio);
// Return the Import_init for a given init name.
Import_init*
lookup_init(const std::string& init_name);
// Turn short-cut operators (&&, ||) into explicit if statements. // Turn short-cut operators (&&, ||) into explicit if statements.
void void
remove_shortcuts(); remove_shortcuts();
...@@ -754,6 +783,15 @@ class Gogo ...@@ -754,6 +783,15 @@ class Gogo
{ } { }
}; };
// Recompute init priorities.
void
recompute_init_priorities();
// Recursive helper used by the routine above.
void
update_init_priority(Import_init* ii,
std::set<const Import_init *>* visited);
// The backend generator. // The backend generator.
Backend* backend_; Backend* backend_;
// The object used to keep track of file names and line numbers. // The object used to keep track of file names and line numbers.
...@@ -787,7 +825,7 @@ class Gogo ...@@ -787,7 +825,7 @@ class Gogo
// The name of the magic initialization function. // The name of the magic initialization function.
std::string init_fn_name_; std::string init_fn_name_;
// A list of import control variables for packages that we import. // A list of import control variables for packages that we import.
std::set<Import_init> imported_init_fns_; Import_init_set imported_init_fns_;
// The package path used for reflection data. // The package path used for reflection data.
std::string pkgpath_; std::string pkgpath_;
// The package path to use for a symbol name. // The package path to use for a symbol name.
...@@ -2875,17 +2913,6 @@ class Package ...@@ -2875,17 +2913,6 @@ class Package
return this->package_name_; return this->package_name_;
} }
// The priority of this package. The init function of packages with
// lower priority must be run before the init function of packages
// with higher priority.
int
priority() const
{ return this->priority_; }
// Set the priority.
void
set_priority(int priority);
// Return the bindings. // Return the bindings.
Bindings* Bindings*
bindings() bindings()
...@@ -2977,10 +3004,6 @@ class Package ...@@ -2977,10 +3004,6 @@ class Package
std::string package_name_; std::string package_name_;
// The names in this package. // The names in this package.
Bindings* bindings_; Bindings* bindings_;
// The priority of this package. A package has a priority higher
// than the priority of all of the packages that it imports. This
// is used to run init functions in the right order.
int priority_;
// The location of the most recent import statement. // The location of the most recent import statement.
Location location_; Location location_;
// The set of aliases associated with this package. // The set of aliases associated with this package.
......
...@@ -200,8 +200,7 @@ Import::try_suffixes(std::string* pfilename) ...@@ -200,8 +200,7 @@ Import::try_suffixes(std::string* pfilename)
// Look for export data in the file descriptor FD. // Look for export data in the file descriptor FD.
Import::Stream* Import::Stream*
Import::find_export_data(const std::string& filename, int fd, Import::find_export_data(const std::string& filename, int fd, Location location)
Location location)
{ {
// See if we can read this as an object file. // See if we can read this as an object file.
Import::Stream* stream = Import::find_object_export_data(filename, fd, 0, Import::Stream* stream = Import::find_object_export_data(filename, fd, 0,
...@@ -209,7 +208,7 @@ Import::find_export_data(const std::string& filename, int fd, ...@@ -209,7 +208,7 @@ Import::find_export_data(const std::string& filename, int fd,
if (stream != NULL) if (stream != NULL)
return stream; return stream;
const int len = MAX(Export::v1_magic_len, Import::archive_magic_len); const int len = MAX(Export::magic_len, Import::archive_magic_len);
if (lseek(fd, 0, SEEK_SET) < 0) if (lseek(fd, 0, SEEK_SET) < 0)
{ {
...@@ -223,7 +222,8 @@ Import::find_export_data(const std::string& filename, int fd, ...@@ -223,7 +222,8 @@ Import::find_export_data(const std::string& filename, int fd,
return NULL; return NULL;
// Check for a file containing nothing but Go export data. // Check for a file containing nothing but Go export data.
if (memcmp(buf, Export::v1_magic, Export::v1_magic_len) == 0) if (memcmp(buf, Export::cur_magic, Export::magic_len) == 0 ||
memcmp(buf, Export::v1_magic, Export::magic_len) == 0)
return new Stream_from_file(fd); return new Stream_from_file(fd);
// See if we can read this as an archive. // See if we can read this as an archive.
...@@ -270,7 +270,7 @@ Import::Import(Stream* stream, Location location) ...@@ -270,7 +270,7 @@ Import::Import(Stream* stream, Location location)
: gogo_(NULL), stream_(stream), location_(location), package_(NULL), : gogo_(NULL), stream_(stream), location_(location), package_(NULL),
add_to_globals_(false), add_to_globals_(false),
builtin_types_((- SMALLEST_BUILTIN_CODE) + 1), builtin_types_((- SMALLEST_BUILTIN_CODE) + 1),
types_() types_(), version_(EXPORT_FORMAT_UNKNOWN)
{ {
} }
...@@ -293,8 +293,26 @@ Import::import(Gogo* gogo, const std::string& local_name, ...@@ -293,8 +293,26 @@ Import::import(Gogo* gogo, const std::string& local_name,
// The vector of types is package specific. // The vector of types is package specific.
this->types_.clear(); this->types_.clear();
stream->require_bytes(this->location_, Export::v1_magic, // Check magic string / version number.
Export::v1_magic_len); if (stream->match_bytes(Export::cur_magic, Export::magic_len))
{
stream->require_bytes(this->location_, Export::cur_magic,
Export::magic_len);
this->version_ = EXPORT_FORMAT_CURRENT;
}
else if (stream->match_bytes(Export::v1_magic, Export::magic_len))
{
stream->require_bytes(this->location_, Export::v1_magic,
Export::magic_len);
this->version_ = EXPORT_FORMAT_V1;
}
else
{
error_at(this->location_,
("error in import data at %d: invalid magic string"),
stream->pos());
return NULL;
}
this->require_c_string("package "); this->require_c_string("package ");
std::string package_name = this->read_identifier(); std::string package_name = this->read_identifier();
...@@ -330,13 +348,16 @@ Import::import(Gogo* gogo, const std::string& local_name, ...@@ -330,13 +348,16 @@ Import::import(Gogo* gogo, const std::string& local_name,
return NULL; return NULL;
} }
this->require_c_string("priority "); // Read and discard priority if older V1 export data format.
std::string priority_string = this->read_identifier(); if (version() == EXPORT_FORMAT_V1)
int prio; {
if (!this->string_to_int(priority_string, false, &prio)) this->require_c_string("priority ");
return NULL; std::string priority_string = this->read_identifier();
this->package_->set_priority(prio); int prio;
this->require_c_string(";\n"); if (!this->string_to_int(priority_string, false, &prio))
return NULL;
this->require_c_string(";\n");
}
while (stream->match_c_string("package")) while (stream->match_c_string("package"))
this->read_one_package(); this->read_one_package();
...@@ -377,7 +398,7 @@ Import::import(Gogo* gogo, const std::string& local_name, ...@@ -377,7 +398,7 @@ Import::import(Gogo* gogo, const std::string& local_name,
// verify that the checksum matches at link time or at dynamic // verify that the checksum matches at link time or at dynamic
// load time. // load time.
this->require_c_string("checksum "); this->require_c_string("checksum ");
stream->advance(Export::v1_checksum_len * 2); stream->advance(Export::checksum_len * 2);
this->require_c_string(";\n"); this->require_c_string(";\n");
} }
...@@ -423,26 +444,88 @@ Import::read_one_import() ...@@ -423,26 +444,88 @@ Import::read_one_import()
p->set_package_name(package_name, this->location()); p->set_package_name(package_name, this->location());
} }
// Read the list of import control functions. // Read the list of import control functions and/or init graph.
void void
Import::read_import_init_fns(Gogo* gogo) Import::read_import_init_fns(Gogo* gogo)
{ {
this->require_c_string("init"); this->require_c_string("init");
// Maps init function to index in the "init" clause; needed
// to read the init_graph section.
std::map<std::string, unsigned> init_idx;
while (!this->match_c_string(";")) while (!this->match_c_string(";"))
{ {
int priority = -1;
this->require_c_string(" "); this->require_c_string(" ");
std::string package_name = this->read_identifier(); std::string package_name = this->read_identifier();
this->require_c_string(" "); this->require_c_string(" ");
std::string init_name = this->read_identifier(); std::string init_name = this->read_identifier();
this->require_c_string(" "); if (this->version_ == EXPORT_FORMAT_V1)
std::string prio_string = this->read_identifier(); {
int prio; // Older version 1 init fcn export data format is:
if (!this->string_to_int(prio_string, false, &prio)) //
return; // <packname> <fcn> <priority>
gogo->add_import_init_fn(package_name, init_name, prio); this->require_c_string(" ");
std::string prio_string = this->read_identifier();
if (!this->string_to_int(prio_string, false, &priority))
return;
}
gogo->add_import_init_fn(package_name, init_name, priority);
// Record the index of this init fcn so that we can look it
// up by index in the subsequent init_graph section.
unsigned idx = init_idx.size();
init_idx[init_name] = idx;
} }
this->require_c_string(";\n"); this->require_c_string(";\n");
if (this->match_c_string("init_graph"))
{
this->require_c_string("init_graph");
// Build a vector mapping init fcn slot to Import_init pointer.
go_assert(init_idx.size() > 0);
std::vector<Import_init*> import_initvec;
import_initvec.resize(init_idx.size());
for (std::map<std::string, unsigned>::const_iterator it =
init_idx.begin();
it != init_idx.end(); ++it)
{
const std::string& init_name = it->first;
Import_init* ii = gogo->lookup_init(init_name);
import_initvec[it->second] = ii;
}
// Init graph format is:
//
// init_graph <src1> <sink1> <src2> <sink2> ... ;
//
// where src + sink are init functions indices.
while (!this->match_c_string(";"))
{
this->require_c_string(" ");
std::string src_string = this->read_identifier();
unsigned src;
if (!this->string_to_unsigned(src_string, &src)) return;
this->require_c_string(" ");
std::string sink_string = this->read_identifier();
unsigned sink;
if (!this->string_to_unsigned(sink_string, &sink)) return;
go_assert(src < import_initvec.size());
Import_init* ii_src = import_initvec[src];
go_assert(sink < import_initvec.size());
Import_init* ii_sink = import_initvec[sink];
ii_src->record_precursor_fcn(ii_sink->init_name());
}
this->require_c_string(";\n");
}
} }
// Import a constant. // Import a constant.
......
...@@ -232,7 +232,7 @@ class Import ...@@ -232,7 +232,7 @@ class Import
void void
read_one_import(); read_one_import();
// Read the import control functions. // Read the import control functions and init graph.
void void
read_import_init_fns(Gogo*); read_import_init_fns(Gogo*);
...@@ -260,6 +260,21 @@ class Import ...@@ -260,6 +260,21 @@ class Import
bool bool
string_to_int(const std::string&, bool is_neg_ok, int* ret); string_to_int(const std::string&, bool is_neg_ok, int* ret);
// Get an unsigned integer from a string.
bool
string_to_unsigned(const std::string& s, unsigned* ret)
{
int ivalue;
if (!this->string_to_int(s, false, &ivalue))
return false;
*ret = static_cast<unsigned>(ivalue);
return true;
}
// Return the version number of the export data we're reading.
Export_data_version
version() const { return this->version_; }
// The general IR. // The general IR.
Gogo* gogo_; Gogo* gogo_;
// The stream from which to read import data. // The stream from which to read import data.
...@@ -275,6 +290,8 @@ class Import ...@@ -275,6 +290,8 @@ class Import
std::vector<Named_type*> builtin_types_; std::vector<Named_type*> builtin_types_;
// Mapping from exported type codes to Type structures. // Mapping from exported type codes to Type structures.
std::vector<Type*> types_; std::vector<Type*> types_;
// Version of export data we're reading.
Export_data_version version_;
}; };
// Read import data from a string. // Read import data from a string.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment