Commit 9add86be by Ian Lance Taylor Committed by Ian Lance Taylor

compiler: centralize all symbol name handling

    
    Consolidate all symbol name handling into the new file names.cc.  This
    is intended to define all the names that will appear in the generated
    assembly code.  Names that will not appear in the assembly code, such
    as local variable names or label names, remain where they are.
    
    This consolidation is not intended to change any of the existing
    symbol names.  Tested by building without and without this patch and
    comparing the libgo symbol table.
    
    Reviewed-on: https://go-review.googlesource.com/68310

	* Make-lang.in (GO_OBJS): Add go/names.o.

From-SVN: r253458
parent a978e26b
2017-10-05 Ian Lance Taylor <iant@golang.org>
* Make-lang.in (GO_OBJS): Add go/names.o.
2017-08-30 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
......
......@@ -68,6 +68,7 @@ GO_OBJS = \
go/import.o \
go/import-archive.o \
go/lex.o \
go/names.o \
go/parse.o \
go/runtime.o \
go/statements.o \
......
5989ef1cd0add98f107839759a5bc57f34354d39
048914caa26b34eebabd0423ed48ee3ac34c919c
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
......@@ -575,7 +575,7 @@ debug_function_name(Named_object* fn)
// Extract #.
std::string name = Gogo::unpack_hidden_name(fn->name());
int closure_num = (int)strtol(name.substr(6).c_str(), NULL, 0);
int closure_num = Gogo::nested_function_num(fn->name());
closure_num++;
name = Gogo::unpack_hidden_name(enclosing->name());
......
......@@ -1299,28 +1299,12 @@ Func_descriptor_expression::do_get_backend(Translate_context* context)
return context->backend()->var_expression(this->dvar_, VE_rvalue, loc);
Gogo* gogo = context->gogo();
std::string var_name;
std::string var_name(gogo->function_descriptor_name(no));
bool is_descriptor = false;
if (no->is_function_declaration()
&& !no->func_declaration_value()->asm_name().empty()
&& Linemap::is_predeclared_location(no->location()))
{
if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.")
var_name = no->func_declaration_value()->asm_name() + "_descriptor";
else
var_name = no->func_declaration_value()->asm_name() + "$descriptor";
is_descriptor = true;
}
else
{
if (no->package() == NULL)
var_name = gogo->pkgpath_symbol();
else
var_name = no->package()->pkgpath_symbol();
var_name.push_back('.');
var_name.append(Gogo::unpack_hidden_name(no->name()));
var_name.append("$descriptor");
}
is_descriptor = true;
Btype* btype = this->type()->get_backend(gogo);
......@@ -4348,27 +4332,23 @@ Unary_expression::do_get_backend(Translate_context* context)
}
}
static unsigned int counter;
char buf[100];
if (this->is_gc_root_ || this->is_slice_init_)
{
std::string var_name;
bool copy_to_heap = false;
if (this->is_gc_root_)
{
// Build a decl for a GC root variable. GC roots are mutable, so
// they cannot be represented as an immutable_struct in the
// backend.
static unsigned int root_counter;
snprintf(buf, sizeof buf, "gc%u", root_counter);
++root_counter;
var_name = gogo->gc_root_name();
}
else
{
// Build a decl for a slice value initializer. An immutable slice
// value initializer may have to be copied to the heap if it
// contains pointers in a non-constant context.
snprintf(buf, sizeof buf, "C%u", counter);
++counter;
var_name = gogo->initializer_name();
Array_type* at = this->expr_->type()->array_type();
go_assert(at != NULL);
......@@ -4379,12 +4359,12 @@ Unary_expression::do_get_backend(Translate_context* context)
// read-only, because the program is permitted to change it.
copy_to_heap = context->function() != NULL;
}
std::string asm_name(go_selectively_encode_id(buf));
std::string asm_name(go_selectively_encode_id(var_name));
Bvariable* implicit =
gogo->backend()->implicit_variable(buf, asm_name,
gogo->backend()->implicit_variable(var_name, asm_name,
btype, true, copy_to_heap,
false, 0);
gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
gogo->backend()->implicit_variable_set_init(implicit, var_name, btype,
true, copy_to_heap, false,
bexpr);
bexpr = gogo->backend()->var_expression(implicit, VE_rvalue, loc);
......@@ -4407,16 +4387,13 @@ Unary_expression::do_get_backend(Translate_context* context)
|| this->expr_->string_expression() != NULL)
&& this->expr_->is_static_initializer())
{
// Build a decl for a constant constructor.
snprintf(buf, sizeof buf, "C%u", counter);
++counter;
std::string asm_name(go_selectively_encode_id(buf));
std::string var_name(gogo->initializer_name());
std::string asm_name(go_selectively_encode_id(var_name));
Bvariable* decl =
gogo->backend()->immutable_struct(buf, asm_name,
gogo->backend()->immutable_struct(var_name, asm_name,
true, false, btype, loc);
gogo->backend()->immutable_struct_set_init(decl, buf, true, false,
btype, loc, bexpr);
gogo->backend()->immutable_struct_set_init(decl, var_name, true,
false, btype, loc, bexpr);
bexpr = gogo->backend()->var_expression(decl, VE_rvalue, loc);
}
......@@ -15403,10 +15380,9 @@ Interface_mtable_expression::do_get_backend(Translate_context* context)
const Typed_identifier_list* interface_methods = this->itype_->methods();
go_assert(!interface_methods->empty());
std::string mangled_name = ((this->is_pointer_ ? "__go_pimt__" : "__go_imt_")
+ this->itype_->mangled_name(gogo)
+ "__"
+ this->type_->mangled_name(gogo));
std::string mangled_name =
gogo->interface_method_table_name(this->itype_, this->type_,
this->is_pointer_);
// Set is_public if we are converting a named type to an interface
// type that is defined in the same package as the named type, and
......
......@@ -868,32 +868,6 @@ Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
init_stmts.push_back(this->backend()->expression_statement(init_bfn, bcall));
}
// Get the name to use for the import control function. If there is a
// global function or variable, then we know that that name must be
// unique in the link, and we use it as the basis for our name.
const std::string&
Gogo::get_init_fn_name()
{
if (this->init_fn_name_.empty())
{
go_assert(this->package_ != NULL);
if (this->is_main_package())
{
// Use a name which the runtime knows.
this->init_fn_name_ = "__go_init_main";
}
else
{
std::string s = this->pkgpath_symbol();
s.append("..import");
this->init_fn_name_ = s;
}
}
return this->init_fn_name_;
}
// Build the decl for the initialization function.
Named_object*
......@@ -1774,11 +1748,7 @@ Gogo::start_function(const std::string& name, Function_type* type,
"func init must have no arguments and no return values");
// There can be multiple "init" functions, so give them each a
// different name.
static int init_count;
char buf[30];
snprintf(buf, sizeof buf, ".$init%d", init_count);
++init_count;
nested_name = buf;
nested_name = this->init_function_name();
pname = &nested_name;
is_init = true;
}
......@@ -1787,22 +1757,15 @@ Gogo::start_function(const std::string& name, Function_type* type,
else
{
// Invent a name for a nested function.
static int nested_count;
char buf[30];
snprintf(buf, sizeof buf, ".$nested%d", nested_count);
++nested_count;
nested_name = buf;
nested_name = this->nested_function_name();
pname = &nested_name;
}
Named_object* ret;
if (Gogo::is_sink_name(*pname))
{
static int sink_count;
char buf[30];
snprintf(buf, sizeof buf, ".$sink%d", sink_count);
++sink_count;
ret = Named_object::make_function(buf, NULL, function);
std::string sname(this->sink_function_name());
ret = Named_object::make_function(sname, NULL, function);
ret->func_value()->set_is_sink();
if (!type->is_method())
......@@ -1845,11 +1808,8 @@ Gogo::start_function(const std::string& name, Function_type* type,
{
// Redefinition error. Invent a name to avoid knockon
// errors.
static int redefinition_count;
char buf[30];
snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count);
++redefinition_count;
ret = this->package_->bindings()->add_function(buf, NULL, function);
std::string rname(this->redefined_function_name());
ret = this->package_->bindings()->add_function(rname, NULL, function);
}
}
else
......@@ -2274,47 +2234,6 @@ Gogo::record_interface_type(Interface_type* itype)
this->interface_types_.push_back(itype);
}
// Return an erroneous name that indicates that an error has already
// been reported.
std::string
Gogo::erroneous_name()
{
static int erroneous_count;
char name[50];
snprintf(name, sizeof name, "$erroneous%d", erroneous_count);
++erroneous_count;
return name;
}
// Return whether a name is an erroneous name.
bool
Gogo::is_erroneous_name(const std::string& name)
{
return name.compare(0, 10, "$erroneous") == 0;
}
// Return a name for a thunk object.
std::string
Gogo::thunk_name()
{
static int thunk_count;
char thunk_name[50];
snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count);
++thunk_count;
return thunk_name;
}
// Return whether a function is a thunk.
bool
Gogo::is_thunk(const Named_object* no)
{
return no->name().compare(0, 6, "$thunk") == 0;
}
// Define the global names. We do this only after parsing all the
// input files, because the program might define the global names
// itself.
......@@ -4195,10 +4114,10 @@ Build_recover_thunks::function(Named_object* orig_no)
if (orig_fntype->is_varargs())
new_fntype->set_is_varargs();
std::string name = orig_no->name();
Type* rtype = NULL;
if (orig_fntype->is_method())
name += "$" + orig_fntype->receiver()->type()->mangled_name(gogo);
name += "$recover";
rtype = orig_fntype->receiver()->type();
std::string name(gogo->recover_thunk_name(orig_no->name(), rtype));
Named_object *new_no = gogo->start_function(name, new_fntype, false,
location);
Function *new_func = new_no->func_value();
......@@ -5449,29 +5368,10 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
{
if (!this->is_unnamed_type_stub_method_)
is_visible = true;
std::string pkgpath = gogo->pkgpath_symbol();
if (this->type_->is_method()
&& Gogo::is_hidden_name(no->name())
&& Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
{
// This is a method we created for an unexported
// method of an imported embedded type. We need to
// use the pkgpath of the imported package to avoid
// a possible name collision. See bug478 for a test
// case.
std::string p = Gogo::hidden_name_pkgpath(no->name());
pkgpath = gogo->pkgpath_symbol_for_package(p);
}
asm_name = pkgpath;
asm_name.append(1, '.');
asm_name.append(Gogo::unpack_hidden_name(no->name()));
if (this->type_->is_method())
{
asm_name.append(1, '.');
Type* rtype = this->type_->receiver()->type();
asm_name.append(rtype->mangled_name(gogo));
}
Type* rtype = NULL;
if (this->type_->is_method())
rtype = this->type_->receiver()->type();
asm_name = gogo->function_asm_name(no->name(), NULL, rtype);
}
if (!this->asm_name_.empty())
......@@ -5510,8 +5410,8 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
disable_split_stack = true;
// Encode name if asm_name not already set at this point
if (asm_name.empty() && go_id_needs_encoding(no->get_id(gogo)))
asm_name = go_encode_id(no->get_id(gogo));
if (asm_name.empty())
asm_name = gogo->unexported_function_asm_name(no->name());
// This should go into a unique section if that has been
// requested elsewhere, or if this is a nointerface function.
......@@ -5553,30 +5453,12 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
std::string asm_name;
if (this->asm_name_.empty())
{
asm_name = (no->package() == NULL
? gogo->pkgpath_symbol()
: no->package()->pkgpath_symbol());
if (this->fntype_->is_method()
&& Gogo::is_hidden_name(no->name())
&& Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
{
// This is a method created for an unexported method of
// an imported embedded type. Use the pkgpath of the
// imported package. This matches code in
// Function::get_or_make_decl, above.
std::string p = Gogo::hidden_name_pkgpath(no->name());
asm_name = gogo->pkgpath_symbol_for_package(p);
}
asm_name.append(1, '.');
asm_name.append(Gogo::unpack_hidden_name(no->name()));
if (this->fntype_->is_method())
{
asm_name.append(1, '.');
Type* rtype = this->fntype_->receiver()->type();
asm_name.append(rtype->mangled_name(gogo));
}
}
{
Type* rtype = NULL;
if (this->fntype_->is_method())
rtype = this->fntype_->receiver()->type();
asm_name = gogo->function_asm_name(no->name(), no->package(), rtype);
}
else if (go_id_needs_encoding(no->get_id(gogo)))
asm_name = go_encode_id(no->get_id(gogo));
......@@ -6815,18 +6697,8 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function,
: gogo->package_name());
var_name.push_back('.');
var_name.append(n);
std::string asm_name;
if (Gogo::is_hidden_name(name))
asm_name = var_name;
else
{
asm_name = package != NULL
? package->pkgpath_symbol()
: gogo->pkgpath_symbol();
asm_name.push_back('.');
asm_name.append(n);
}
asm_name = go_encode_id(asm_name);
std::string asm_name(gogo->global_var_asm_name(name, package));
bool is_hidden = Gogo::is_hidden_name(name);
// Hack to export runtime.writeBarrier. FIXME.
......@@ -7416,23 +7288,18 @@ Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
go_unreachable();
}
// Return the external identifier for this object.
std::string
Named_object::get_id(Gogo* gogo)
{
go_assert(!this->is_variable() && !this->is_result_variable());
go_assert(!this->is_variable()
&& !this->is_result_variable()
&& !this->is_type());
std::string decl_name;
if (this->is_function_declaration()
&& !this->func_declaration_value()->asm_name().empty())
decl_name = this->func_declaration_value()->asm_name();
else if (this->is_type()
&& Linemap::is_predeclared_location(this->type_value()->location()))
{
// We don't need the package name for builtin types.
decl_name = Gogo::unpack_hidden_name(this->name_);
}
else
{
std::string package_name;
......@@ -7466,22 +7333,6 @@ Named_object::get_id(Gogo* gogo)
decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
}
}
if (this->is_type())
{
unsigned int index;
const Named_object* in_function = this->type_value()->in_function(&index);
if (in_function != NULL)
{
decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
if (index > 0)
{
char buf[30];
snprintf(buf, sizeof buf, "%u", index);
decl_name += '$';
decl_name += buf;
}
}
}
return decl_name;
}
......
......@@ -506,26 +506,6 @@ class Gogo
void
mark_locals_used();
// Return a name to use for an error case. This should only be used
// after reporting an error, and is used to avoid useless knockon
// errors.
static std::string
erroneous_name();
// Return whether the name indicates an error.
static bool
is_erroneous_name(const std::string&);
// Return a name to use for a thunk function. A thunk function is
// one we create during the compilation, for a go statement or a
// defer statement or a method expression.
static std::string
thunk_name();
// Return whether an object is a thunk.
static bool
is_thunk(const Named_object*);
// Note that we've seen an interface type. This is used to build
// all required interface method tables.
void
......@@ -781,10 +761,112 @@ class Gogo
Expression*
allocate_memory(Type *type, Location);
// Return the assembler name to use for an exported function, a
// method, or a function/method declaration.
std::string
function_asm_name(const std::string& go_name, const Package*,
const Type* receiver);
// Return the assembler name to use for an unexported function.
std::string
unexported_function_asm_name(const std::string& go_name);
// Return the name to use for a function descriptor.
std::string
function_descriptor_name(Named_object*);
// Return the name to use for a generated stub method.
std::string
stub_method_name(const std::string& method_name);
// Return the names of the hash and equality functions for TYPE.
void
specific_type_function_names(const Type*, const Named_type*,
std::string* hash_name,
std::string* equal_name);
// Return the assembler name to use for a global variable.
std::string
global_var_asm_name(const std::string& go_name, const Package*);
// Return a name to use for an error case. This should only be used
// after reporting an error, and is used to avoid useless knockon
// errors.
static std::string
erroneous_name();
// Return whether the name indicates an error.
static bool
is_erroneous_name(const std::string&);
// Return a name to use for a thunk function. A thunk function is
// one we create during the compilation, for a go statement or a
// defer statement or a method expression.
static std::string
thunk_name();
// Return whether an object is a thunk.
static bool
is_thunk(const Named_object*);
// Return the name to use for an init function.
std::string
init_function_name();
// Return the name to use for a nested function.
static std::string
nested_function_name();
// Return the index of a nested function name.
static int
nested_function_num(const std::string&);
// Return the name to use for a sink funciton.
std::string
sink_function_name();
// Return the name to use for an (erroneous) redefined function.
std::string
redefined_function_name();
// Return the name for use for a recover thunk.
std::string
recover_thunk_name(const std::string& name, const Type* rtype);
// Return the name to use for the GC root variable.
std::string
gc_root_name();
// Return the name to use for a composite literal or string
// initializer.
std::string
initializer_name();
// Return the name of the variable used to represent the zero value
// of a map.
std::string
map_zero_value_name();
// Get the name of the magic initialization function.
const std::string&
get_init_fn_name();
// Return the name for a type descriptor symbol.
std::string
type_descriptor_name(Type*, Named_type*);
// Return the assembler name for the GC symbol for a type.
std::string
gc_symbol_name(Type*);
// Return the assembler name for a ptrmask variable.
std::string
ptrmask_symbol_name(const std::string& ptrmask_sym_name);
// Return the name to use for an interface method table.
std::string
interface_method_table_name(Interface_type*, Type*, bool is_pointer);
private:
// During parsing, we keep a stack of functions. Each function on
// the stack is one that we are currently parsing. For each
......
......@@ -1213,11 +1213,6 @@ class Type
void
make_gc_symbol_var(Gogo*);
// Return the name of the type descriptor variable. If NAME is not
// NULL, it is the name to use.
std::string
type_descriptor_var_name(Gogo*, Named_type* name);
// Return true if the type descriptor for this type should be
// defined in some other package. If NAME is not NULL, it is the
// name of this type. If this returns true it sets *PACKAGE to the
......@@ -1558,6 +1553,92 @@ class Typed_identifier_list
std::vector<Typed_identifier> entries_;
};
// A type used to indicate a parsing error. This exists to simplify
// later error detection.
class Error_type : public Type
{
public:
Error_type()
: Type(TYPE_ERROR)
{ }
protected:
bool
do_compare_is_identity(Gogo*)
{ return false; }
Btype*
do_get_backend(Gogo* gogo);
Expression*
do_type_descriptor(Gogo*, Named_type*);
void
do_reflection(Gogo*, std::string*) const;
void
do_mangled_name(Gogo*, std::string* ret) const;
};
// The void type.
class Void_type : public Type
{
public:
Void_type()
: Type(TYPE_VOID)
{ }
protected:
bool
do_compare_is_identity(Gogo*)
{ return false; }
Btype*
do_get_backend(Gogo* gogo);
Expression*
do_type_descriptor(Gogo*, Named_type*)
{ go_unreachable(); }
void
do_reflection(Gogo*, std::string*) const
{ }
void
do_mangled_name(Gogo*, std::string* ret) const;
};
// The boolean type.
class Boolean_type : public Type
{
public:
Boolean_type()
: Type(TYPE_BOOLEAN)
{ }
protected:
bool
do_compare_is_identity(Gogo*)
{ return true; }
Btype*
do_get_backend(Gogo* gogo);
Expression*
do_type_descriptor(Gogo*, Named_type* name);
// We should not be asked for the reflection string of a basic type.
void
do_reflection(Gogo*, std::string* ret) const
{ ret->append("bool"); }
void
do_mangled_name(Gogo*, std::string* ret) const;
};
// The type of an integer.
class Integer_type : public Type
......@@ -2143,6 +2224,37 @@ class Pointer_type : public Type
Type* to_type_;
};
// The nil type. We use a special type for nil because it is not the
// same as any other type. In C term nil has type void*, but there is
// no such type in Go.
class Nil_type : public Type
{
public:
Nil_type()
: Type(TYPE_NIL)
{ }
protected:
bool
do_compare_is_identity(Gogo*)
{ return false; }
Btype*
do_get_backend(Gogo* gogo);
Expression*
do_type_descriptor(Gogo*, Named_type*)
{ go_unreachable(); }
void
do_reflection(Gogo*, std::string*) const
{ go_unreachable(); }
void
do_mangled_name(Gogo*, std::string* ret) const;
};
// The type of a field in a struct.
class Struct_field
......
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