From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/go/gofrontend/export.cc | 439 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 439 insertions(+) create mode 100644 gcc/go/gofrontend/export.cc (limited to 'gcc/go/gofrontend/export.cc') diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc new file mode 100644 index 000000000..cbf24b840 --- /dev/null +++ b/gcc/go/gofrontend/export.cc @@ -0,0 +1,439 @@ +// 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" + +#ifndef ENABLE_BUILD_WITH_CXX +extern "C" +{ +#endif + +#include "machmode.h" +#include "output.h" +#include "target.h" + +#ifndef ENABLE_BUILD_WITH_CXX +} +#endif + +#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) +{ +} + +// 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& unique_prefix, + int package_priority, + const std::string& import_init_fn, + const std::set& 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 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 unique prefix. This prefix is used for all global symbols. + this->write_c_string("prefix "); + this->write_string(unique_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_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::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); +} + +// Write out the import control variables 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& imported_init_fns) +{ + if (import_init_fn.empty() && imported_init_fns.empty()) + return; + + this->write_c_string("import"); + + 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 v; + for (std::set::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::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"); +} + +// 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; + gcc_assert(index != 0); + char buf[30]; + snprintf(buf, sizeof buf, "", 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, "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. + gcc_assert(named_type->location() != BUILTINS_LOCATION + || (named_type->named_object()->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->unique_prefix(); + s += '.'; + s += package->name(); + s += '.'; + } + s += named_object->name(); + s += "\" "; + this->write_string(s); + + // 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); +} + +// 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); + gcc_assert(named_object != NULL && named_object->is_type()); + std::pair ins = + this->type_refs_.insert(std::make_pair(named_object->type_value(), code)); + gcc_assert(ins.second); + + // We also insert the underlying type. We can see the underlying + // type at least for string and bool. + Type* real_type = named_object->type_value()->real_type(); + ins = this->type_refs_.insert(std::make_pair(real_type, code)); + gcc_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() + : section_(NULL) +{ +} + +// Write data to a section. + +void +Stream_to_section::do_write(const char* bytes, size_t length) +{ + section* sec = (section*) this->section_; + if (sec == NULL) + { + gcc_assert(targetm.have_named_sections); + + sec = get_section(".go_export", SECTION_DEBUG, NULL); + this->section_ = (void*) sec; + } + + switch_to_section(sec); + assemble_string(bytes, length); +} -- cgit v1.2.3