From 307e0d40367996031e9b734ba0ab44ff0b290c79 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 6 Aug 2021 12:01:04 -0700 Subject: [PATCH] compiler: support export/import of unsafe.Add/Slice For golang/go#19367 For golang/go#40481 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/340549 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/export.cc | 44 +++++++++++++++++++++- gcc/go/gofrontend/export.h | 10 +++++ gcc/go/gofrontend/expressions.cc | 8 ++++ gcc/go/gofrontend/expressions.h | 21 +++++++++-- gcc/go/gofrontend/gogo.h | 4 ++ gcc/go/gofrontend/import.cc | 6 +++ gcc/go/gofrontend/unsafe.cc | 64 ++++++++++++++++++++------------ 8 files changed, 130 insertions(+), 29 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 9ed527f7eb4..b983fdab35c 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -747f3a2d78c073e9b03dd81914d0edb7ddc5be14 +d5d51242efc432fa62d4e9b141b01c280af32d19 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index e99c680f709..3d11334884d 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -106,11 +106,12 @@ class Collect_export_references : public Traverse { public: Collect_export_references(Export* exp, + const std::map& packages, Unordered_set(Named_object*)* exports, Unordered_set(const Package*)* imports) : Traverse(traverse_expressions | traverse_types), - exp_(exp), exports_(exports), imports_(imports), + exp_(exp), packages_(packages), exports_(exports), imports_(imports), inline_fcn_worklist_(NULL), exports_finalized_(false) { } @@ -150,6 +151,8 @@ class Collect_export_references : public Traverse // The exporter. Export* exp_; + // The list of packages known to this compilation. + const std::map& packages_; // The set of named objects to export. Unordered_set(Named_object*)* exports_; // Set containing all directly and indirectly imported packages. @@ -257,6 +260,24 @@ Collect_export_references::expression(Expression** pexpr) return TRAVERSE_CONTINUE; } + const Call_expression* call = expr->call_expression(); + if (call != NULL) + { + const Builtin_call_expression* bce = call->builtin_call_expression(); + if (bce != NULL + && (bce->code() == Builtin_call_expression::BUILTIN_ADD + || bce->code() == Builtin_call_expression::BUILTIN_SLICE)) + { + // This is a reference to unsafe.Add or unsafe.Slice. Make + // sure we list the "unsafe" package in the imports and give + // it a package index. + const std::map::const_iterator p = + this->packages_.find("unsafe"); + go_assert(p != this->packages_.end()); + this->imports_->insert(p->second); + } + } + return TRAVERSE_CONTINUE; } @@ -589,7 +610,7 @@ Export::export_globals(const std::string& package_name, // Track all imported packages mentioned in export data. Unordered_set(const Package*) all_imports; - Collect_export_references collect(this, &exports, &all_imports); + Collect_export_references collect(this, packages, &exports, &all_imports); // Walk the set of inlinable routine bodies collected above. This // can potentially expand the exports set. @@ -1274,6 +1295,25 @@ Export::package_index(const Package* pkg) const return index; } +// Return the index of the "unsafe" package. + +int +Export::unsafe_package_index() const +{ + for (Unordered_map(const Package*, int)::const_iterator p = + this->packages_.begin(); + p != this->packages_.end(); + ++p) + { + if (p->first->pkgpath() == "unsafe") + { + go_assert(p->second != 0); + return p->second; + } + } + go_unreachable(); +} + // Return the index of a type. int diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index c93bced4eb4..1f613434cab 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -216,6 +216,11 @@ class Export : public String_dump int package_index(const Package* p) const; + // Return the index of the "unsafe" package, which must be one of + // the exported packages. + int + unsafe_package_index() const; + private: Export(const Export&); Export& operator=(const Export&); @@ -377,6 +382,11 @@ class Export_function_body : public String_dump package_index(const Package* p) const { return this->exp_->package_index(p); } + // Return the index of the "unsafe" package. + int + unsafe_package_index() const + { return this->exp_->unsafe_package_index(); } + // Record a temporary statement and return its index. unsigned int record_temporary(const Temporary_statement*); diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 33177a709ab..f462b0e2a34 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -11039,6 +11039,14 @@ Builtin_call_expression::do_export(Export_function_body* efb) const // A trailing space lets us reliably identify the end of the number. efb->write_c_string(" "); } + else if (this->code_ == BUILTIN_ADD || this->code_ == BUILTIN_SLICE) + { + char buf[50]; + snprintf(buf, sizeof buf, "%s", efb->unsafe_package_index(), + (this->code_ == BUILTIN_ADD ? "Add" : "Slice")); + efb->write_c_string(buf); + this->export_arguments(efb); + } else { const char *s = NULL; diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 79a8785b69d..9f8f4e9255b 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -732,6 +732,10 @@ class Expression call_expression() { return this->convert(); } + const Call_expression* + call_expression() const + { return this->convert(); } + // If this is a call_result expression, return the Call_result_expression // structure. Otherwise, return NULL. This is a controlled dynamic // cast. @@ -2460,13 +2464,16 @@ class Call_expression : public Expression // Whether this is a call to builtin function. virtual bool - is_builtin() + is_builtin() const { return false; } // Convert to a Builtin_call_expression, or return NULL. inline Builtin_call_expression* builtin_call_expression(); + inline const Builtin_call_expression* + builtin_call_expression() const; + protected: int do_traverse(Traverse*); @@ -2625,12 +2632,12 @@ class Builtin_call_expression : public Call_expression }; Builtin_function_code - code() + code() const { return this->code_; } // This overrides Call_expression::is_builtin. bool - is_builtin() + is_builtin() const { return true; } // Return whether EXPR, of array type, is a constant if passed to @@ -2726,6 +2733,14 @@ Call_expression::builtin_call_expression() : NULL); } +inline const Builtin_call_expression* +Call_expression::builtin_call_expression() const +{ + return (this->is_builtin() + ? static_cast(this) + : NULL); +} + // A single result from a call which returns multiple results. class Call_result_expression : public Expression diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index c49bc92b3e0..9ffd120290d 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -533,6 +533,10 @@ class Gogo register_package(const std::string& pkgpath, const std::string& pkgpath_symbol, Location); + // Add the unsafe bindings to the unsafe package. + void + add_unsafe_bindings(Package*); + // Look up a package by pkgpath, and return its pkgpath_symbol. std::string pkgpath_symbol_for_package(const std::string&); diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index f671416a423..6a5491be949 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -497,6 +497,9 @@ Import::read_one_import() p->set_package_name(package_name, this->location()); this->packages_.push_back(p); + + if (pkgpath == "unsafe") + this->gogo_->add_unsafe_bindings(p); } // Read an indirectimport line. @@ -515,6 +518,9 @@ Import::read_one_indirect_import() p->set_package_name(package_name, this->location()); this->packages_.push_back(p); + + if (pkgpath == "unsafe") + this->gogo_->add_unsafe_bindings(p); } // Read the list of import control functions and/or init graph. diff --git a/gcc/go/gofrontend/unsafe.cc b/gcc/go/gofrontend/unsafe.cc index 18bd99eca15..c4a9346ca3e 100644 --- a/gcc/go/gofrontend/unsafe.cc +++ b/gcc/go/gofrontend/unsafe.cc @@ -10,15 +10,12 @@ #include "types.h" #include "gogo.h" -// Set up the builtin unsafe package. This should probably be driven -// by a table. +// Set up the builtin unsafe package. void Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, Location location) { - Location bloc = Linemap::predeclared_location(); - bool add_to_globals; Package* package = this->add_imported_package("unsafe", local_name, is_local_name_exported, @@ -34,10 +31,40 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, package->set_location(location); this->imports_.insert(std::make_pair("unsafe", package)); + this->add_unsafe_bindings(package); + + Named_object* pointer_no = package->bindings()->lookup_local("Pointer"); + pointer_no->type_value()->set_is_visible(); + + if (add_to_globals) + { + Bindings* bindings = package->bindings(); + for (Bindings::const_declarations_iterator p = + bindings->begin_declarations(); + p != bindings->end_declarations(); + ++p) + this->add_dot_import_object(p->second); + } +} + +// Add the unsafe bindings to the Package object. This should +// probably be driven by a table. + +void +Gogo::add_unsafe_bindings(Package* package) +{ Bindings* bindings = package->bindings(); + if (bindings->lookup_local("Sizeof") != NULL) + { + // Already done by an earlier import. + return; + } + + Location bloc = Linemap::predeclared_location(); + // The type may have already been created by an import. - Named_object* no = package->bindings()->lookup("Pointer"); + Named_object* no = bindings->lookup("Pointer"); if (no == NULL) { Type* type = Type::make_pointer_type(Type::make_void_type()); @@ -49,11 +76,12 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, go_assert(no->package() == package); go_assert(no->is_type()); go_assert(no->type_value()->is_unsafe_pointer_type()); - no->type_value()->set_is_visible(); } Named_type* pointer_type = no->type_value(); - if (add_to_globals) - this->add_named_type(pointer_type); + + // This may be called during an import, so the type may not be + // visible yet. + pointer_type->clear_is_visible(); Type* uintptr_type = Type::lookup_integer_type("uintptr"); @@ -62,9 +90,7 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, results->push_back(Typed_identifier("", uintptr_type, bloc)); Function_type* fntype = Type::make_function_type(NULL, NULL, results, bloc); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Sizeof", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Sizeof", package, fntype, bloc); // Offsetof. results = new Typed_identifier_list; @@ -72,9 +98,7 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, fntype = Type::make_function_type(NULL, NULL, results, bloc); fntype->set_is_varargs(); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Offsetof", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Offsetof", package, fntype, bloc); // Alignof. results = new Typed_identifier_list; @@ -82,25 +106,19 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, fntype = Type::make_function_type(NULL, NULL, results, bloc); fntype->set_is_varargs(); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Alignof", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Alignof", package, fntype, bloc); // Add. results = new Typed_identifier_list; results->push_back(Typed_identifier("", pointer_type, bloc)); fntype = Type::make_function_type(NULL, NULL, results, bloc); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Add", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Add", package, fntype, bloc); // Slice. fntype = Type::make_function_type(NULL, NULL, NULL, bloc); fntype->set_is_builtin(); - no = bindings->add_function_declaration("Slice", package, fntype, bloc); - if (add_to_globals) - this->add_dot_import_object(no); + bindings->add_function_declaration("Slice", package, fntype, bloc); if (!this->imported_unsafe_) {