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
This commit is contained in:
Ian Lance Taylor 2017-10-05 17:20:30 +00:00 committed by Ian Lance Taylor
parent a978e26b83
commit 9add86be80
10 changed files with 1145 additions and 806 deletions

View File

@ -1,3 +1,7 @@
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>

View File

@ -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 \

View File

@ -1,4 +1,4 @@
5989ef1cd0add98f107839759a5bc57f34354d39
048914caa26b34eebabd0423ed48ee3ac34c919c
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -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());

View File

@ -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

View File

@ -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;
}

View File

@ -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

825
gcc/go/gofrontend/names.cc Normal file
View File

@ -0,0 +1,825 @@
// names.cc -- Names used by gofrontend generated code.
// Copyright 2017 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 "gogo.h"
#include "go-encode-id.h"
#include "types.h"
#include "expressions.h"
// This file contains functions that generate names that appear in the
// assembly code. This is not used for names that appear only in the
// debug info.
// Return the assembler name to use for an exported function, a
// method, or a function/method declaration. This is not called if
// the function has been given an explicit name via a magic //extern
// or //go:linkname comment. GO_NAME is the name that appears in the
// Go code. PACKAGE is the package where the function is defined, and
// is NULL for the package being compiled. For a method, RTYPE is
// the method's receiver type; for a function, RTYPE is NULL.
std::string
Gogo::function_asm_name(const std::string& go_name, const Package* package,
const Type* rtype)
{
std::string ret = (package == NULL
? this->pkgpath_symbol()
: package->pkgpath_symbol());
if (rtype != NULL
&& Gogo::is_hidden_name(go_name)
&& Gogo::hidden_name_pkgpath(go_name) != this->pkgpath())
{
// This is a method created for an unexported method of an
// imported embedded type. Use the pkgpath of the imported
// package.
std::string p = Gogo::hidden_name_pkgpath(go_name);
ret = this->pkgpath_symbol_for_package(p);
}
ret.append(1, '.');
ret.append(Gogo::unpack_hidden_name(go_name));
if (rtype != NULL)
{
ret.append(1, '.');
ret.append(rtype->mangled_name(this));
}
return go_encode_id(ret);
}
// Return the assembler name to use for an unexported function.
// FIXME: This should probably be removed and the callers changed to
// simply call function_name.
std::string
Gogo::unexported_function_asm_name(const std::string& go_name)
{
std::string ret = this->package_name();
ret.append(1, '.');
ret.append(Gogo::unpack_hidden_name(go_name));
return go_encode_id(ret);
}
// Return the name to use for a function descriptor. These symbols
// are globally visible.
std::string
Gogo::function_descriptor_name(Named_object* no)
{
std::string var_name;
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";
}
else
{
if (no->package() == NULL)
var_name = this->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");
}
return var_name;
}
// Return the name to use for a generated stub method. MNAME is the
// method name. These functions are globally visible. Note that this
// is the function name that corresponds to the name used for the
// method in Go source code, if this stub method were written in Go.
// The assembler name will be generated by Gogo::function_asm_name,
// and because this is a method that name will include the receiver
// type.
std::string
Gogo::stub_method_name(const std::string& mname)
{
return mname + "$stub";
}
// Return the names of the hash and equality functions for TYPE. If
// NAME is not NULL it is the name of the type. Set *HASH_NAME and
// *EQUAL_NAME.
void
Gogo::specific_type_function_names(const Type* type, const Named_type* name,
std::string *hash_name,
std::string *equal_name)
{
std::string base_name;
if (name == NULL)
{
// Mangled names can have '.' if they happen to refer to named
// types in some way. That's fine if this is simply a named
// type, but otherwise it will confuse the code that builds
// function identifiers. Remove '.' when necessary.
base_name = type->mangled_name(this);
size_t i;
while ((i = base_name.find('.')) != std::string::npos)
base_name[i] = '$';
base_name = this->pack_hidden_name(base_name, false);
}
else
{
// This name is already hidden or not as appropriate.
base_name = name->name();
unsigned int index;
const Named_object* in_function = name->in_function(&index);
if (in_function != NULL)
{
base_name.append(1, '$');
const Typed_identifier* rcvr =
in_function->func_value()->type()->receiver();
if (rcvr != NULL)
{
Named_type* rcvr_type = rcvr->type()->deref()->named_type();
base_name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
base_name.append(1, '$');
}
base_name.append(Gogo::unpack_hidden_name(in_function->name()));
if (index > 0)
{
char buf[30];
snprintf(buf, sizeof buf, "%u", index);
base_name += '$';
base_name += buf;
}
}
}
*hash_name = base_name + "$hash";
*equal_name = base_name + "$equal";
}
// Return the assembler name to use for a global variable. GO_NAME is
// the name that appears in the Go code. PACKAGE is the package where
// the variable is defined, and is NULL for the package being
// compiled.
std::string
Gogo::global_var_asm_name(const std::string& go_name, const Package* package)
{
// FIXME: Using package_name for hidden names and pkgpath_symbol for
// non-hidden names doesn't make sense, but it dates back to the
// first public commit of the gofrontend repo.
std::string ret;
if (Gogo::is_hidden_name(go_name))
ret = (package != NULL
? package->package_name()
: this->package_name());
else
ret = (package != NULL
? package->pkgpath_symbol()
: this->pkgpath_symbol());
ret.push_back('.');
ret.append(Gogo::unpack_hidden_name(go_name));
return go_encode_id(ret);
}
// 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;
}
// Return the name to use for an init function. There can be multiple
// functions named "init" so each one needs a different name.
std::string
Gogo::init_function_name()
{
static int init_count;
char buf[30];
snprintf(buf, sizeof buf, ".$init%d", init_count);
++init_count;
return buf;
}
// Return the name to use for a nested function.
std::string
Gogo::nested_function_name()
{
static int nested_count;
char buf[30];
snprintf(buf, sizeof buf, ".$nested%d", nested_count);
++nested_count;
return buf;
}
// Return the index of a nested function name.
int
Gogo::nested_function_num(const std::string& name)
{
std::string n(Gogo::unpack_hidden_name(name));
go_assert(n.compare(0, 8, ".$nested") == 0);
return strtol(n.substr(8).c_str(), NULL, 0);
}
// Return the name to use for a sink function, a function whose name
// is simply underscore. We don't really need these functions but we
// do have to generate them for error checking.
std::string
Gogo::sink_function_name()
{
static int sink_count;
char buf[30];
snprintf(buf, sizeof buf, ".$sink%d", sink_count);
++sink_count;
return buf;
}
// Return the name to use for a redefined function. These functions
// are erroneous but we still generate them for further error
// checking.
std::string
Gogo::redefined_function_name()
{
static int redefinition_count;
char buf[30];
snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count);
++redefinition_count;
return buf;
}
// Return the name to use for a recover thunk for the function NAME.
// If the function is a method, RTYPE is the receiver type.
std::string
Gogo::recover_thunk_name(const std::string& name, const Type* rtype)
{
std::string ret(name);
if (rtype != NULL)
{
ret.push_back('$');
ret.append(rtype->mangled_name(this));
}
ret.append("$recover");
return ret;
}
// Return the name to use for a GC root variable. The GC root
// variable is a composite literal that is passed to
// runtime.registerGCRoots. There is at most one of these variables
// per compilation.
std::string
Gogo::gc_root_name()
{
return "gc0";
}
// Return the name to use for a composite literal or string
// initializer. This is a local name never referenced outside of this
// file.
std::string
Gogo::initializer_name()
{
static unsigned int counter;
char buf[30];
snprintf(buf, sizeof buf, "C%u", counter);
++counter;
return buf;
}
// Return the name of the variable used to represent the zero value of
// a map. This is a globally visible common symbol.
std::string
Gogo::map_zero_value_name()
{
return "go$zerovalue";
}
// Return the name to use for the import control function.
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 that 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_;
}
// Return a mangled name for a type. These names appear in symbol
// names in the assembler file for things like type descriptors and
// methods.
std::string
Type::mangled_name(Gogo* gogo) const
{
std::string ret;
// The do_mangled_name virtual function should set RET to the
// mangled name. For a composite type it should append a code for
// the composition and then call do_mangled_name on the components.
this->do_mangled_name(gogo, &ret);
return ret;
}
// The mangled name is implemented as a method on each instance of
// Type.
void
Error_type::do_mangled_name(Gogo*, std::string* ret) const
{
ret->push_back('E');
}
void
Void_type::do_mangled_name(Gogo*, std::string* ret) const
{
ret->push_back('v');
}
void
Boolean_type::do_mangled_name(Gogo*, std::string* ret) const
{
ret->push_back('b');
}
void
Integer_type::do_mangled_name(Gogo*, std::string* ret) const
{
char buf[100];
snprintf(buf, sizeof buf, "i%s%s%de",
this->is_abstract_ ? "a" : "",
this->is_unsigned_ ? "u" : "",
this->bits_);
ret->append(buf);
}
void
Float_type::do_mangled_name(Gogo*, std::string* ret) const
{
char buf[100];
snprintf(buf, sizeof buf, "f%s%de",
this->is_abstract_ ? "a" : "",
this->bits_);
ret->append(buf);
}
void
Complex_type::do_mangled_name(Gogo*, std::string* ret) const
{
char buf[100];
snprintf(buf, sizeof buf, "c%s%de",
this->is_abstract_ ? "a" : "",
this->bits_);
ret->append(buf);
}
void
String_type::do_mangled_name(Gogo*, std::string* ret) const
{
ret->push_back('z');
}
void
Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('F');
if (this->receiver_ != NULL)
{
ret->push_back('m');
this->append_mangled_name(this->receiver_->type(), gogo, ret);
}
const Typed_identifier_list* params = this->parameters();
if (params != NULL)
{
ret->push_back('p');
for (Typed_identifier_list::const_iterator p = params->begin();
p != params->end();
++p)
this->append_mangled_name(p->type(), gogo, ret);
if (this->is_varargs_)
ret->push_back('V');
ret->push_back('e');
}
const Typed_identifier_list* results = this->results();
if (results != NULL)
{
ret->push_back('r');
for (Typed_identifier_list::const_iterator p = results->begin();
p != results->end();
++p)
this->append_mangled_name(p->type(), gogo, ret);
ret->push_back('e');
}
ret->push_back('e');
}
void
Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('p');
this->append_mangled_name(this->to_type_, gogo, ret);
}
void
Nil_type::do_mangled_name(Gogo*, std::string* ret) const
{
ret->push_back('n');
}
void
Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('S');
const Struct_field_list* fields = this->fields_;
if (fields != NULL)
{
for (Struct_field_list::const_iterator p = fields->begin();
p != fields->end();
++p)
{
if (p->is_anonymous())
ret->append("0_");
else
{
std::string n(Gogo::mangle_possibly_hidden_name(p->field_name()));
char buf[20];
snprintf(buf, sizeof buf, "%u_",
static_cast<unsigned int>(n.length()));
ret->append(buf);
ret->append(n);
}
// For an anonymous field with an alias type, the field name
// is the alias name.
if (p->is_anonymous()
&& p->type()->named_type() != NULL
&& p->type()->named_type()->is_alias())
p->type()->named_type()->append_mangled_type_name(gogo, true, ret);
else
this->append_mangled_name(p->type(), gogo, ret);
if (p->has_tag())
{
const std::string& tag(p->tag());
std::string out;
for (std::string::const_iterator p = tag.begin();
p != tag.end();
++p)
{
if (ISALNUM(*p) || *p == '_')
out.push_back(*p);
else
{
char buf[20];
snprintf(buf, sizeof buf, ".%x.",
static_cast<unsigned int>(*p));
out.append(buf);
}
}
char buf[20];
snprintf(buf, sizeof buf, "T%u_",
static_cast<unsigned int>(out.length()));
ret->append(buf);
ret->append(out);
}
}
}
if (this->is_struct_incomparable_)
ret->push_back('x');
ret->push_back('e');
}
void
Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('A');
this->append_mangled_name(this->element_type_, gogo, ret);
if (this->length_ != NULL)
{
Numeric_constant nc;
if (!this->length_->numeric_constant_value(&nc))
{
go_assert(saw_errors());
return;
}
mpz_t val;
if (!nc.to_int(&val))
{
go_assert(saw_errors());
return;
}
char *s = mpz_get_str(NULL, 10, val);
ret->append(s);
free(s);
mpz_clear(val);
if (this->is_array_incomparable_)
ret->push_back('x');
}
ret->push_back('e');
}
void
Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('M');
this->append_mangled_name(this->key_type_, gogo, ret);
ret->append("__");
this->append_mangled_name(this->val_type_, gogo, ret);
}
void
Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('C');
this->append_mangled_name(this->element_type_, gogo, ret);
if (this->may_send_)
ret->push_back('s');
if (this->may_receive_)
ret->push_back('r');
ret->push_back('e');
}
void
Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
go_assert(this->methods_are_finalized_);
ret->push_back('I');
const Typed_identifier_list* methods = this->all_methods_;
if (methods != NULL && !this->seen_)
{
this->seen_ = true;
for (Typed_identifier_list::const_iterator p = methods->begin();
p != methods->end();
++p)
{
if (!p->name().empty())
{
std::string n(Gogo::mangle_possibly_hidden_name(p->name()));
char buf[20];
snprintf(buf, sizeof buf, "%u_",
static_cast<unsigned int>(n.length()));
ret->append(buf);
ret->append(n);
}
this->append_mangled_name(p->type(), gogo, ret);
}
this->seen_ = false;
}
ret->push_back('e');
}
void
Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
this->append_mangled_type_name(gogo, false, ret);
}
void
Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
if (this->is_defined())
this->append_mangled_name(this->real_type(), gogo, ret);
else
{
const Named_object* no = this->named_object();
std::string name;
if (no->package() == NULL)
name = gogo->pkgpath_symbol();
else
name = no->package()->pkgpath_symbol();
name += '.';
name += Gogo::unpack_hidden_name(no->name());
char buf[20];
snprintf(buf, sizeof buf, "N%u_",
static_cast<unsigned int>(name.length()));
ret->append(buf);
ret->append(name);
}
}
// Append the mangled name for a named type to RET. For an alias we
// normally use the real name, but if USE_ALIAS is true we use the
// alias name itself.
void
Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias,
std::string* ret) const
{
if (this->is_error_)
return;
if (this->is_alias_ && !use_alias)
{
if (this->seen_alias_)
return;
this->seen_alias_ = true;
this->append_mangled_name(this->type_, gogo, ret);
this->seen_alias_ = false;
return;
}
Named_object* no = this->named_object_;
std::string name;
if (this->is_builtin())
go_assert(this->in_function_ == NULL);
else
{
const std::string& pkgpath(no->package() == NULL
? gogo->pkgpath_symbol()
: no->package()->pkgpath_symbol());
name = pkgpath;
name.append(1, '.');
if (this->in_function_ != NULL)
{
const Typed_identifier* rcvr =
this->in_function_->func_value()->type()->receiver();
if (rcvr != NULL)
{
Named_type* rcvr_type = rcvr->type()->deref()->named_type();
name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
name.append(1, '.');
}
name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
name.append(1, '$');
if (this->in_function_index_ > 0)
{
char buf[30];
snprintf(buf, sizeof buf, "%u", this->in_function_index_);
name.append(buf);
name.append(1, '$');
}
}
}
name.append(Gogo::unpack_hidden_name(no->name()));
char buf[20];
snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length()));
ret->append(buf);
ret->append(name);
}
// Return the name for the type descriptor symbol for TYPE. This can
// be a global, common, or local symbol, depending. NT is not NULL if
// it is the name to use.
std::string
Gogo::type_descriptor_name(Type* type, Named_type* nt)
{
// The type descriptor symbol for the unsafe.Pointer type is defined
// in libgo/runtime/go-unsafe-pointer.c, so just use a reference to
// that symbol.
if (type->is_unsafe_pointer_type())
return "__go_tdn_unsafe.Pointer";
if (nt == NULL)
return "__go_td_" + type->mangled_name(this);
Named_object* no = nt->named_object();
unsigned int index;
const Named_object* in_function = nt->in_function(&index);
std::string ret = "__go_tdn_";
if (nt->is_builtin())
go_assert(in_function == NULL);
else
{
const std::string& pkgpath(no->package() == NULL
? this->pkgpath_symbol()
: no->package()->pkgpath_symbol());
ret.append(pkgpath);
ret.append(1, '.');
if (in_function != NULL)
{
const Typed_identifier* rcvr =
in_function->func_value()->type()->receiver();
if (rcvr != NULL)
{
Named_type* rcvr_type = rcvr->type()->deref()->named_type();
ret.append(Gogo::unpack_hidden_name(rcvr_type->name()));
ret.append(1, '.');
}
ret.append(Gogo::unpack_hidden_name(in_function->name()));
ret.append(1, '.');
if (index > 0)
{
char buf[30];
snprintf(buf, sizeof buf, "%u", index);
ret.append(buf);
ret.append(1, '.');
}
}
}
std::string mname(Gogo::mangle_possibly_hidden_name(no->name()));
ret.append(mname);
return ret;
}
// Return the name for the GC symbol for a type. This is used to
// initialize the gcdata field of a type descriptor. This is a local
// name never referenced outside of this assembly file. (Note that
// some type descriptors will initialize the gcdata field with a name
// generated by ptrmask_symbol_name rather than this method.)
std::string
Gogo::gc_symbol_name(Type* type)
{
return this->type_descriptor_name(type, type->named_type()) + "$gc";
}
// Return the name for a ptrmask variable. PTRMASK_SYM_NAME is a
// base64 string encoding the ptrmask (as returned by Ptrmask::symname
// in types.cc). This name is used to intialize the gcdata field of a
// type descriptor. These names are globally visible. (Note that
// some type descriptors will initialize the gcdata field with a name
// generated by gc_symbol_name rather than this method.)
std::string
Gogo::ptrmask_symbol_name(const std::string& ptrmask_sym_name)
{
return "runtime.gcbits." + ptrmask_sym_name;
}
// Return the name to use for an interface method table used for the
// ordinary type TYPE converted to the interface type ITYPE.
// IS_POINTER is true if this is for the method set for a pointer
// receiver.
std::string
Gogo::interface_method_table_name(Interface_type* itype, Type* type,
bool is_pointer)
{
return ((is_pointer ? "__go_pimt__" : "__go_imt_")
+ itype->mangled_name(this)
+ "__"
+ type->mangled_name(this));
}

View File

@ -1257,7 +1257,7 @@ Type::make_type_descriptor_var(Gogo* gogo)
Type* td_type = Type::make_type_descriptor_type();
Btype* td_btype = td_type->get_backend(gogo);
const char *name = "__go_tdn_unsafe.Pointer";
std::string name = gogo->type_descriptor_name(this, nt);
std::string asm_name(go_selectively_encode_id(name));
this->type_descriptor_var_ =
gogo->backend()->immutable_struct_reference(name, asm_name,
@ -1269,7 +1269,7 @@ Type::make_type_descriptor_var(Gogo* gogo)
return;
}
std::string var_name = this->type_descriptor_var_name(gogo, nt);
std::string var_name = gogo->type_descriptor_name(this, nt);
// Build the contents of the type descriptor.
Expression* initializer = this->do_type_descriptor(gogo, NULL);
@ -1331,56 +1331,6 @@ Type::make_type_descriptor_var(Gogo* gogo)
binitializer);
}
// Return the name of the type descriptor variable. If NT is not
// NULL, use it to get the name. Otherwise this is an unnamed type.
std::string
Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt)
{
if (nt == NULL)
return "__go_td_" + this->mangled_name(gogo);
Named_object* no = nt->named_object();
unsigned int index;
const Named_object* in_function = nt->in_function(&index);
std::string ret = "__go_tdn_";
if (nt->is_builtin())
go_assert(in_function == NULL);
else
{
const std::string& pkgpath(no->package() == NULL
? gogo->pkgpath_symbol()
: no->package()->pkgpath_symbol());
ret.append(pkgpath);
ret.append(1, '.');
if (in_function != NULL)
{
const Typed_identifier* rcvr =
in_function->func_value()->type()->receiver();
if (rcvr != NULL)
{
Named_type* rcvr_type = rcvr->type()->deref()->named_type();
ret.append(Gogo::unpack_hidden_name(rcvr_type->name()));
ret.append(1, '.');
}
ret.append(Gogo::unpack_hidden_name(in_function->name()));
ret.append(1, '.');
if (index > 0)
{
char buf[30];
snprintf(buf, sizeof buf, "%u", index);
ret.append(buf);
ret.append(1, '.');
}
}
}
std::string mname(Gogo::mangle_possibly_hidden_name(no->name()));
ret.append(mname);
return ret;
}
// Return true if this type descriptor is defined in a different
// package. If this returns true it sets *PACKAGE to the package.
@ -1967,48 +1917,9 @@ Type::specific_type_functions(Gogo* gogo, Named_type* name, int64_t size,
return;
}
std::string base_name;
if (name == NULL)
{
// Mangled names can have '.' if they happen to refer to named
// types in some way. That's fine if this is simply a named
// type, but otherwise it will confuse the code that builds
// function identifiers. Remove '.' when necessary.
base_name = this->mangled_name(gogo);
size_t i;
while ((i = base_name.find('.')) != std::string::npos)
base_name[i] = '$';
base_name = gogo->pack_hidden_name(base_name, false);
}
else
{
// This name is already hidden or not as appropriate.
base_name = name->name();
unsigned int index;
const Named_object* in_function = name->in_function(&index);
if (in_function != NULL)
{
base_name.append(1, '$');
const Typed_identifier* rcvr =
in_function->func_value()->type()->receiver();
if (rcvr != NULL)
{
Named_type* rcvr_type = rcvr->type()->deref()->named_type();
base_name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
base_name.append(1, '$');
}
base_name.append(Gogo::unpack_hidden_name(in_function->name()));
if (index > 0)
{
char buf[30];
snprintf(buf, sizeof buf, "%u", index);
base_name += '$';
base_name += buf;
}
}
}
std::string hash_name = base_name + "$hash";
std::string equal_name = base_name + "$equal";
std::string hash_name;
std::string equal_name;
gogo->specific_type_function_names(this, name, &hash_name, &equal_name);
Location bloc = Linemap::predeclared_location();
@ -2525,7 +2436,7 @@ Type::make_gc_symbol_var(Gogo* gogo)
return;
}
std::string sym_name = this->type_descriptor_var_name(gogo, nt) + "$gc";
std::string sym_name = gogo->gc_symbol_name(this);
// Build the contents of the gc symbol.
Expression* sym_init = this->gcprog_constructor(gogo, ptrsize, ptrdata);
@ -2818,7 +2729,8 @@ Type::gc_ptrmask_var(Gogo* gogo, int64_t ptrsize, int64_t ptrdata)
// This can happen in error cases. Just build an empty gcbits.
go_assert(saw_errors());
}
std::string sym_name = "runtime.gcbits." + ptrmask.symname();
std::string sym_name = gogo->ptrmask_symbol_name(ptrmask.symname());
Bvariable* bvnull = NULL;
std::pair<GC_gcbits_vars::iterator, bool> ins =
Type::gc_gcbits_vars.insert(std::make_pair(sym_name, bvnull));
@ -3462,21 +3374,6 @@ Type::reflection(Gogo* gogo) const
return ret;
}
// Return a mangled name for the type.
std::string
Type::mangled_name(Gogo* gogo) const
{
std::string ret;
// The do_mangled_name virtual function should set RET to the
// mangled name. For a composite type it should append a code for
// the composition and then call do_mangled_name on the components.
this->do_mangled_name(gogo, &ret);
return ret;
}
// Return whether the backend size of the type is known.
bool
@ -3796,37 +3693,32 @@ Type::import_type(Import* imp)
}
}
// A type used to indicate a parsing error. This exists to simplify
// later error detection.
// Class Error_type.
class Error_type : public Type
// Return the backend representation of an Error type.
Btype*
Error_type::do_get_backend(Gogo* gogo)
{
public:
Error_type()
: Type(TYPE_ERROR)
{ }
return gogo->backend()->error_type();
}
protected:
bool
do_compare_is_identity(Gogo*)
{ return false; }
// Return an expression for the type descriptor for an error type.
Btype*
do_get_backend(Gogo* gogo)
{ return gogo->backend()->error_type(); }
Expression*
do_type_descriptor(Gogo*, Named_type*)
{ return Expression::make_error(Linemap::predeclared_location()); }
Expression*
Error_type::do_type_descriptor(Gogo*, Named_type*)
{
return Expression::make_error(Linemap::predeclared_location());
}
void
do_reflection(Gogo*, std::string*) const
{ go_assert(saw_errors()); }
// We should not be asked for the reflection string for an error type.
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('E'); }
};
void
Error_type::do_reflection(Gogo*, std::string*) const
{
go_assert(saw_errors());
}
Type*
Type::make_error_type()
@ -3835,36 +3727,15 @@ Type::make_error_type()
return &singleton_error_type;
}
// The void type.
// Class Void_type.
class Void_type : public Type
// Get the backend representation of a void type.
Btype*
Void_type::do_get_backend(Gogo* gogo)
{
public:
Void_type()
: Type(TYPE_VOID)
{ }
protected:
bool
do_compare_is_identity(Gogo*)
{ return false; }
Btype*
do_get_backend(Gogo* gogo)
{ return gogo->backend()->void_type(); }
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
{ ret->push_back('v'); }
};
return gogo->backend()->void_type();
}
Type*
Type::make_void_type()
@ -3873,36 +3744,15 @@ Type::make_void_type()
return &singleton_void_type;
}
// The boolean type.
// Class Boolean_type.
class Boolean_type : public Type
// Return the backend representation of the boolean type.
Btype*
Boolean_type::do_get_backend(Gogo* gogo)
{
public:
Boolean_type()
: Type(TYPE_BOOLEAN)
{ }
protected:
bool
do_compare_is_identity(Gogo*)
{ return true; }
Btype*
do_get_backend(Gogo* gogo)
{ return gogo->backend()->bool_type(); }
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
{ ret->push_back('b'); }
};
return gogo->backend()->bool_type();
}
// Make the type descriptor.
@ -4069,19 +3919,6 @@ Integer_type::do_reflection(Gogo*, std::string*) const
go_assert(saw_errors());
}
// Mangled name.
void
Integer_type::do_mangled_name(Gogo*, std::string* ret) const
{
char buf[100];
snprintf(buf, sizeof buf, "i%s%s%de",
this->is_abstract_ ? "a" : "",
this->is_unsigned_ ? "u" : "",
this->bits_);
ret->append(buf);
}
// Make an integer type.
Named_type*
@ -4204,18 +4041,6 @@ Float_type::do_reflection(Gogo*, std::string*) const
go_assert(saw_errors());
}
// Mangled name.
void
Float_type::do_mangled_name(Gogo*, std::string* ret) const
{
char buf[100];
snprintf(buf, sizeof buf, "f%s%de",
this->is_abstract_ ? "a" : "",
this->bits_);
ret->append(buf);
}
// Make a floating point type.
Named_type*
@ -4331,18 +4156,6 @@ Complex_type::do_reflection(Gogo*, std::string*) const
go_assert(saw_errors());
}
// Mangled name.
void
Complex_type::do_mangled_name(Gogo*, std::string* ret) const
{
char buf[100];
snprintf(buf, sizeof buf, "c%s%de",
this->is_abstract_ ? "a" : "",
this->bits_);
ret->append(buf);
}
// Make a complex type.
Named_type*
@ -4428,14 +4241,6 @@ String_type::do_reflection(Gogo*, std::string* ret) const
ret->append("string");
}
// Mangled name of a string type.
void
String_type::do_mangled_name(Gogo*, std::string* ret) const
{
ret->push_back('z');
}
// Make a string type.
Type*
@ -5082,46 +4887,6 @@ Function_type::do_reflection(Gogo* gogo, std::string* ret) const
}
}
// Mangled name.
void
Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('F');
if (this->receiver_ != NULL)
{
ret->push_back('m');
this->append_mangled_name(this->receiver_->type(), gogo, ret);
}
const Typed_identifier_list* params = this->parameters();
if (params != NULL)
{
ret->push_back('p');
for (Typed_identifier_list::const_iterator p = params->begin();
p != params->end();
++p)
this->append_mangled_name(p->type(), gogo, ret);
if (this->is_varargs_)
ret->push_back('V');
ret->push_back('e');
}
const Typed_identifier_list* results = this->results();
if (results != NULL)
{
ret->push_back('r');
for (Typed_identifier_list::const_iterator p = results->begin();
p != results->end();
++p)
this->append_mangled_name(p->type(), gogo, ret);
ret->push_back('e');
}
ret->push_back('e');
}
// Export a function type.
void
@ -5484,13 +5249,6 @@ Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->to_type_, gogo, ret);
}
void
Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('p');
this->append_mangled_name(this->to_type_, gogo, ret);
}
// Export.
void
@ -5572,38 +5330,16 @@ Type::finish_pointer_types(Gogo* gogo)
}
}
// 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.
class Nil_type : public Type
// Get the backend representation of a nil type. FIXME: Is this ever
// actually called?
Btype*
Nil_type::do_get_backend(Gogo* gogo)
{
public:
Nil_type()
: Type(TYPE_NIL)
{ }
protected:
bool
do_compare_is_identity(Gogo*)
{ return false; }
Btype*
do_get_backend(Gogo* gogo)
{ return gogo->backend()->pointer_type(gogo->backend()->void_type()); }
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
{ ret->push_back('n'); }
};
return gogo->backend()->pointer_type(gogo->backend()->void_type());
}
// Make the nil type.
@ -6692,74 +6428,6 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->push_back('}');
}
// Mangled name.
void
Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('S');
const Struct_field_list* fields = this->fields_;
if (fields != NULL)
{
for (Struct_field_list::const_iterator p = fields->begin();
p != fields->end();
++p)
{
if (p->is_anonymous())
ret->append("0_");
else
{
std::string n(Gogo::mangle_possibly_hidden_name(p->field_name()));
char buf[20];
snprintf(buf, sizeof buf, "%u_",
static_cast<unsigned int>(n.length()));
ret->append(buf);
ret->append(n);
}
// For an anonymous field with an alias type, the field name
// is the alias name.
if (p->is_anonymous()
&& p->type()->named_type() != NULL
&& p->type()->named_type()->is_alias())
p->type()->named_type()->append_mangled_type_name(gogo, true, ret);
else
this->append_mangled_name(p->type(), gogo, ret);
if (p->has_tag())
{
const std::string& tag(p->tag());
std::string out;
for (std::string::const_iterator p = tag.begin();
p != tag.end();
++p)
{
if (ISALNUM(*p) || *p == '_')
out.push_back(*p);
else
{
char buf[20];
snprintf(buf, sizeof buf, ".%x.",
static_cast<unsigned int>(*p));
out.append(buf);
}
}
char buf[20];
snprintf(buf, sizeof buf, "T%u_",
static_cast<unsigned int>(out.length()));
ret->append(buf);
ret->append(out);
}
}
}
if (this->is_struct_incomparable_)
ret->push_back('x');
ret->push_back('e');
}
// If the offset of field INDEX in the backend implementation can be
// determined, set *POFFSET to the offset in bytes and return true.
// Otherwise, return false.
@ -7951,37 +7619,6 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->element_type_, gogo, ret);
}
// Mangled name.
void
Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('A');
this->append_mangled_name(this->element_type_, gogo, ret);
if (this->length_ != NULL)
{
Numeric_constant nc;
if (!this->length_->numeric_constant_value(&nc))
{
go_assert(saw_errors());
return;
}
mpz_t val;
if (!nc.to_int(&val))
{
go_assert(saw_errors());
return;
}
char *s = mpz_get_str(NULL, 10, val);
ret->append(s);
free(s);
mpz_clear(val);
if (this->is_array_incomparable_)
ret->push_back('x');
}
ret->push_back('e');
}
// Make an array type.
Array_type*
@ -8037,8 +7674,8 @@ Map_type::fat_zero_value(Gogo* gogo)
Array_type* array_type = Type::make_array_type(uint8_type, size);
array_type->set_is_array_incomparable();
Variable* var = new Variable(array_type, NULL, true, false, false, bloc);
Map_type::zero_value = Named_object::make_variable("go$zerovalue", NULL,
var);
std::string name = gogo->map_zero_value_name();
Map_type::zero_value = Named_object::make_variable(name, NULL, var);
}
Expression* z = Expression::make_var_reference(Map_type::zero_value, bloc);
@ -8582,17 +8219,6 @@ Map_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->val_type_, gogo, ret);
}
// Mangled name for a map.
void
Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('M');
this->append_mangled_name(this->key_type_, gogo, ret);
ret->append("__");
this->append_mangled_name(this->val_type_, gogo, ret);
}
// Export a map type.
void
@ -8765,20 +8391,6 @@ Channel_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->element_type_, gogo, ret);
}
// Mangled name.
void
Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
ret->push_back('C');
this->append_mangled_name(this->element_type_, gogo, ret);
if (this->may_send_)
ret->push_back('s');
if (this->may_receive_)
ret->push_back('r');
ret->push_back('e');
}
// Export.
void
@ -9702,40 +9314,6 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->append("}");
}
// Mangled name.
void
Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
go_assert(this->methods_are_finalized_);
ret->push_back('I');
const Typed_identifier_list* methods = this->all_methods_;
if (methods != NULL && !this->seen_)
{
this->seen_ = true;
for (Typed_identifier_list::const_iterator p = methods->begin();
p != methods->end();
++p)
{
if (!p->name().empty())
{
std::string n(Gogo::mangle_possibly_hidden_name(p->name()));
char buf[20];
snprintf(buf, sizeof buf, "%u_",
static_cast<unsigned int>(n.length()));
ret->append(buf);
ret->append(n);
}
this->append_mangled_name(p->type(), gogo, ret);
}
this->seen_ = false;
}
ret->push_back('e');
}
// Export.
void
@ -11178,71 +10756,6 @@ Named_type::append_reflection_type_name(Gogo* gogo, bool use_alias,
ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
}
// Get the mangled name.
void
Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
this->append_mangled_type_name(gogo, false, ret);
}
// Get the mangled name. For an alias we normally get the real name,
// but if USE_ALIAS is true we use the alias name itself.
void
Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias,
std::string* ret) const
{
if (this->is_error_)
return;
if (this->is_alias_ && !use_alias)
{
if (this->seen_alias_)
return;
this->seen_alias_ = true;
this->append_mangled_name(this->type_, gogo, ret);
this->seen_alias_ = false;
return;
}
Named_object* no = this->named_object_;
std::string name;
if (this->is_builtin())
go_assert(this->in_function_ == NULL);
else
{
const std::string& pkgpath(no->package() == NULL
? gogo->pkgpath_symbol()
: no->package()->pkgpath_symbol());
name = pkgpath;
name.append(1, '.');
if (this->in_function_ != NULL)
{
const Typed_identifier* rcvr =
this->in_function_->func_value()->type()->receiver();
if (rcvr != NULL)
{
Named_type* rcvr_type = rcvr->type()->deref()->named_type();
name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
name.append(1, '.');
}
name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
name.append(1, '$');
if (this->in_function_index_ > 0)
{
char buf[30];
snprintf(buf, sizeof buf, "%u", this->in_function_index_);
name.append(buf);
name.append(1, '$');
}
}
}
name.append(Gogo::unpack_hidden_name(no->name()));
char buf[20];
snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length()));
ret->append(buf);
ret->append(name);
}
// Export the type. This is called to export a global type.
void
@ -11623,7 +11136,7 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods,
package = NULL;
else
package = type->named_type()->named_object()->package();
std::string stub_name = name + "$stub";
std::string stub_name = gogo->stub_method_name(name);
Named_object* stub;
if (package != NULL)
stub = Named_object::make_function_declaration(stub_name, package,
@ -12453,31 +11966,6 @@ Forward_declaration_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->real_type(), gogo, ret);
}
// The mangled name.
void
Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
if (this->is_defined())
this->append_mangled_name(this->real_type(), gogo, ret);
else
{
const Named_object* no = this->named_object();
std::string name;
if (no->package() == NULL)
name = gogo->pkgpath_symbol();
else
name = no->package()->pkgpath_symbol();
name += '.';
name += Gogo::unpack_hidden_name(no->name());
char buf[20];
snprintf(buf, sizeof buf, "N%u_",
static_cast<unsigned int>(name.length()));
ret->append(buf);
ret->append(name);
}
}
// Export a forward declaration. This can happen when a defined type
// refers to a type which is only declared (and is presumably defined
// in some other file in the same package).

View File

@ -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