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
This commit is contained in:
parent
cd754efa9a
commit
307e0d4036
@ -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.
|
||||
|
@ -106,11 +106,12 @@ class Collect_export_references : public Traverse
|
||||
{
|
||||
public:
|
||||
Collect_export_references(Export* exp,
|
||||
const std::map<std::string, Package*>& 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<std::string, Package*>& 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<std::string, Package*>::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
|
||||
|
@ -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*);
|
||||
|
@ -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, "<p%d>%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;
|
||||
|
@ -732,6 +732,10 @@ class Expression
|
||||
call_expression()
|
||||
{ return this->convert<Call_expression, EXPRESSION_CALL>(); }
|
||||
|
||||
const Call_expression*
|
||||
call_expression() const
|
||||
{ return this->convert<const Call_expression, EXPRESSION_CALL>(); }
|
||||
|
||||
// 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<const Builtin_call_expression*>(this)
|
||||
: NULL);
|
||||
}
|
||||
|
||||
// A single result from a call which returns multiple results.
|
||||
|
||||
class Call_result_expression : public Expression
|
||||
|
@ -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&);
|
||||
|
@ -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.
|
||||
|
@ -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_)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user