// 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. // Our external names contain only ASCII alphanumeric characters, // underscore, and dot. (According to the GCC sources, dot is not // permitted in assembler symbols on VxWorks and MMIX. We will not // support those systems.) Go names can not contain dot, so we rely // on using dot to encode Unicode characters, and to separate Go // symbols by package, and so forth. We assume that none of the // non-Go symbols in the final link will contain a dot, so we don't // worry about conflicts. // // We first describe the basic symbol names, used to represent Go // functions and variables. These never start with a dot, never end // with a dot, never contain two consecutive dots, and never contain a // dot followed by a digit. // // The external name for a normal Go symbol NAME, a function or // variable, is simply "PKGPATH.NAME". Note that NAME is not the // packed form used for the "hidden" name internally in the compiler; // it is the name that appears in the source code. PKGPATH is the // -fgo-pkgpath option as adjusted by Gogo::pkgpath_for_symbol. Note // that PKGPATH can not contain a dot and neither can NAME. Also, // NAME may not begin with a digit. NAME may require further encoding // for non-ASCII characters as described below, but until that // encoding these symbols contain exactly one dot, and they do not // start with a dot. // // The external name for a method NAME for a named type TYPE is // "PKGPATH.TYPE.NAME". Unlike the gc compiler, the external name // does not indicate whether this is a pointer method or a value // method; a named type can not have both a pointer and value method // with the same name, so there is no ambiguity. PKGPATH is the // package path of the package in which TYPE is defined. Here none of // PKGPATH, TYPE, or NAME can be empty or contain a dot, and neither // TYPE nor NAME may begin with a digit. Before encoding these names // contain exactly two dots, not consecutive, and they do not start // with a dot. // // It's uncommon, but the use of type literals with embedded fields // can cause us to have methods on unnamed types. The external names // for these are also PKGPATH.TYPE.NAME, where TYPE is an // approximately readable version of the type literal, described // below. As the type literal encoding always contains multiple dots, // these names always contain more than two dots. Although the type // literal encoding contains dots, neither PKGPATH nor NAME can // contain a dot, and neither TYPE nor NAME can begin with a digit. // The effect is that PKGPATH is always the portion of the name before // the first dot and NAME is always the portion after the last dot. // There is no ambiguity as long as encoded type literals are // unambiguous. // // Also uncommon is an external name that must refer to a named type // defined within a function. While such a type can not have methods // itself, it can pick up embedded methods, and those methods need // names. These are treated as a kind of type literal written as, // before type literal encoding, FNNAME.TYPENAME(INDEX) or, for a // method, TYPE.MNAME.TYPENAME(INDEX). INDEX is the index of that // named type within the function, as a single function can have // multiple types with the same name. This is unambiguous as // parentheses can not appear in a type literal in this form (they can // only appear in interface method declarations). // // That is the end of the list of basic names. The remaining names // exist for special purposes, and are differentiated from the basic // names by containing two consecutive dots. // // The hash function for a type is treated as a method whose name is // ".hash". That is, the method name begins with a dot. The effect // is that there will be two consecutive dots in the name; the name // will always end with "..hash". // // Similarly the equality function for a type is treated as a method // whose name is ".eq". // // The function descriptor for a function is the same as the name of // the function with an added suffix "..f". // // A thunk for a go or defer statement is treated as a function whose // name is ".thunkNN" where NN is a sequence of digits (these // functions are never globally visible). Thus the final name of a // thunk will be PKGPATH..thunkNN. // // An init function is treated as a function whose name is ".initNN" // where NN is a sequence of digits (these functions are never // globally visible). Thus the final name of an init function will be // PKGPATH..initNN. // // A nested function is given the name of outermost enclosing function // or method with an added suffix "..funcNN" where NN is a sequence of // digits. Note that the function descriptor of a nested function, if // needed, will end with "..funcNN..f". // // A recover thunk is the same as the name of the function with an // added suffix "..r". // // The name of a type descriptor for a named type is PKGPATH.TYPE..d. // // The name of a type descriptor for an unnamed type is type..TYPE. // That is, the string "type.." followed by the type literal encoding. // These names are common symbols, in the linker's sense of the word // common: in the final executable there is only one instance of the // type descriptor for a given unnamed type. The type literal // encoding can never start with a digit or with 'u' or 'U'. // // The name of the GC symbol for a named type is PKGPATH.TYPE..g. // // The name of the GC symbol for an unnamed type is typeg..TYPE. // These are common symbols. // // The name of a ptrmask symbol is gcbits..B32 where B32 is an // encoding of the ptrmask bits using only ASCII letters without 'u' // or 'U'. These are common symbols. // // An interface method table for assigning the non-interface type TYPE // to the interface type ITYPE is named imt..ITYPE..TYPE. If ITYPE or // TYPE is a named type, they are written as PKGPATH.TYPE. Otherwise // they are written as a type literal. An interface method table for // a pointer method set uses pimt instead of imt. // // The names of composite literal initializers, including the GC root // variable, are not referenced. They must not conflict with any C // language names, but the names are otherwise unimportant. They are // named "go..CNN" where NN is a sequence of digits. The names do not // include the PKGPATH. // // The map zero value, a common symbol that represents the zero value // of a map, is named simply "go..zerovalue". The name does not // include the PKGPATH. // // The import function for the main package is referenced by C code, // and is named __go_init_main. For other packages it is // PKGPATH..import. // // The type literal encoding is essentially a single line version of // the type literal, such as "struct { pkgpath.i int; J int }". In // this representation unexported names use their pkgpath, exported // names omit it. // // The type literal encoding is not quite valid Go, as some aspects of // compiler generated types can not be represented. For example, // incomparable struct types have an extra field "{x}". Struct tags // are quoted inside curly braces, rather than introduce an encoding // for quotes. Struct tags can contain any character, so any single // byte Unicode character that is not alphanumeric or underscore is // replaced with .xNN where NN is the hex encoding. // // There is a simple encoding for glue characters in type literals: // .0 - ' ' // .1 - '*' // .2 - ';' // .3 - ',' // .4 - '{' // .5 - '}' // .6 - '[' // .7 - ']' // .8 - '(' // .9 - ')' // This is unambiguous as, although the type literal can contain a dot // as shown above, those dots are always followed by a name and names // can not begin with a digit. A dot is always followed by a name or // a digit, and a type literal can neither start nor end with a dot, // so this never introduces consecutive dots. // // Struct tags can contain any character, so they need special // treatment. Alphanumerics, underscores, and Unicode characters that // require more than a single byte are left alone (Unicode characters // will be encoded later, as described below). Other single bytes // characters are replace with .xNN where NN is the hex encoding. // // Since Go identifiers can contain Unicode characters, we must encode // them into ASCII. We do this last, after the name is generated as // described above and after type literals are encoded. To make the // encoding unambiguous, we introduce it with two consecutive dots. // This is followed by the letter u and four hex digits or the letter // U and eight digits, just as in the language only using ..u and ..U // instead of \u and \U. Since before this encoding names can never // contain consecutive dots followed by 'u' or 'U', and after this // encoding "..u" and "..U" are followed by a known number of // characters, this is unambiguous. // // Demangling these names is straightforward: // - replace ..uXXXX with a unicode character // - replace ..UXXXXXXXX with a unicode character // - replace .D, where D is a digit, with the character from the above // That will get you as close as possible to a readable name. // 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; if (rtype != NULL) ret = rtype->deref()->mangled_name(this); else if (package == NULL) ret = this->pkgpath_symbol(); else ret = package->pkgpath_symbol(); ret.push_back('.'); // Check for special names that will break if we use // Gogo::unpack_hidden_name. if (Gogo::is_special_name(go_name)) ret.append(go_name); else 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) { if (no->is_function() && !no->func_value()->asm_name().empty()) return no->func_value()->asm_name() + "..f"; else if (no->is_function_declaration() && !no->func_declaration_value()->asm_name().empty()) return no->func_declaration_value()->asm_name() + "..f"; std::string ret = this->function_asm_name(no->name(), no->package(), NULL); ret.append("..f"); return ret; } // Return the name to use for a generated stub method. MNAME is the // method name. PACKAGE is the package where the type that needs this // stub method is defined. 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 Package* package, const std::string& mname) { if (!Gogo::is_hidden_name(mname)) return mname + "..stub"; const std::string& ppkgpath(package == NULL ? this->pkgpath() : package->pkgpath()); std::string mpkgpath = Gogo::hidden_name_pkgpath(mname); if (mpkgpath == ppkgpath) return Gogo::unpack_hidden_name(mname) + "..stub"; // We are creating a stub method for an unexported method of an // imported embedded type. We need to disambiguate the method name. std::string ret = this->pkgpath_symbol_for_package(mpkgpath); ret.push_back('.'); ret.append(Gogo::unpack_hidden_name(mname)); ret.append("..stub"); return ret; } // 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) { const Type* rtype = type; if (name != NULL) rtype = name; std::string tname = rtype->mangled_name(this); *hash_name = tname + "..hash"; *equal_name = tname + "..eq"; } // 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) { std::string ret; if (package == NULL) ret = this->pkgpath_symbol(); else ret = package->pkgpath_symbol(); ret.append(1, '.'); 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() { go_assert(saw_errors()); 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; std::string ret = this->pkgpath_symbol(); return ret + thunk_name; } // Return whether a function is a thunk. bool Gogo::is_thunk(const Named_object* no) { const std::string& name(no->name()); size_t i = name.find("..thunk"); if (i == std::string::npos) return false; for (i += 7; i < name.size(); ++i) if (name[i] < '0' || name[i] > '9') return false; return true; } // 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; std::string ret = this->pkgpath_symbol(); return ret + buf; } // Return the name to use for a nested function. std::string Gogo::nested_function_name(Named_object* enclosing) { std::string prefix; unsigned int index; if (enclosing == NULL) { // A function literal at top level, as in // var f = func() {} static unsigned int toplevel_index; ++toplevel_index; index = toplevel_index; prefix = ".go"; } else { while (true) { Named_object* parent = enclosing->func_value()->enclosing(); if (parent == NULL) break; enclosing = parent; } const Typed_identifier* rcvr = enclosing->func_value()->type()->receiver(); if (rcvr != NULL) { prefix = rcvr->type()->mangled_name(this); prefix.push_back('.'); } prefix.append(Gogo::unpack_hidden_name(enclosing->name())); index = enclosing->func_value()->next_nested_function_index(); } char buf[30]; snprintf(buf, sizeof buf, "..func%u", index); return prefix + buf; } // 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; if (rtype != NULL) { ret = rtype->mangled_name(this); ret.append(1, '.'); } if (Gogo::is_special_name(name)) ret.append(name); else ret.append(Gogo::unpack_hidden_name(name)); ret.append("..r"); 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 "go..C0"; } // 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]; ++counter; snprintf(buf, sizeof buf, "go..C%u", 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 will set RET to the mangled // name before glue character mapping. this->do_mangled_name(gogo, &ret); // Type descriptor names and interface method table names use a ".." // before the mangled name of a type, so to avoid ambiguity the // mangled name must not start with 'u' or 'U' or a digit. go_assert((ret[0] < '0' || ret[0] > '9') && ret[0] != ' '); if (ret[0] == 'u' || ret[0] == 'U') ret = " " + ret; // Map glue characters as described above. // The mapping is only unambiguous if there is no .DIGIT in the // string, so check that. for (size_t i = ret.find('.'); i != std::string::npos; i = ret.find('.', i + 1)) { if (i + 1 < ret.size()) { char c = ret[i + 1]; go_assert(c < '0' || c > '9'); } } // The order of these characters is the replacement code. const char * const replace = " *;,{}[]()"; const size_t rlen = strlen(replace); char buf[2]; buf[0] = '.'; for (size_t ri = 0; ri < rlen; ++ri) { buf[1] = '0' + ri; while (true) { size_t i = ret.find(replace[ri]); if (i == std::string::npos) break; ret.replace(i, 1, buf, 2); } } 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->append("{error}"); } void Void_type::do_mangled_name(Gogo*, std::string* ret) const { ret->append("{void}"); } void Boolean_type::do_mangled_name(Gogo*, std::string* ret) const { ret->append("bool"); } void Integer_type::do_mangled_name(Gogo*, std::string* ret) const { char buf[100]; snprintf(buf, sizeof buf, "%s%si%d", this->is_abstract_ ? "{abstract}" : "", 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, "%sfloat%d", this->is_abstract_ ? "{abstract}" : "", this->bits_); ret->append(buf); } void Complex_type::do_mangled_name(Gogo*, std::string* ret) const { char buf[100]; snprintf(buf, sizeof buf, "%sc%d", this->is_abstract_ ? "{abstract}" : "", this->bits_); ret->append(buf); } void String_type::do_mangled_name(Gogo*, std::string* ret) const { ret->append("string"); } void Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const { ret->append("func"); if (this->receiver_ != NULL) { ret->push_back('('); this->append_mangled_name(this->receiver_->type(), gogo, ret); ret->append(")"); } ret->push_back('('); const Typed_identifier_list* params = this->parameters(); if (params != NULL) { bool first = true; for (Typed_identifier_list::const_iterator p = params->begin(); p != params->end(); ++p) { if (first) first = false; else ret->push_back(','); if (this->is_varargs_ && p + 1 == params->end()) { // We can't use "..." here because the mangled name // might start with 'u' or 'U', which would be ambiguous // with the encoding of Unicode characters. ret->append(",,,"); } this->append_mangled_name(p->type(), gogo, ret); } } ret->push_back(')'); ret->push_back('('); const Typed_identifier_list* results = this->results(); if (results != NULL) { bool first = true; for (Typed_identifier_list::const_iterator p = results->begin(); p != results->end(); ++p) { if (first) first = false; else ret->append(","); this->append_mangled_name(p->type(), gogo, ret); } } ret->push_back(')'); } void Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const { ret->push_back('*'); this->append_mangled_name(this->to_type_, gogo, ret); } void Nil_type::do_mangled_name(Gogo*, std::string* ret) const { ret->append("{nil}"); } void Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const { ret->append("struct{"); if (this->is_struct_incomparable_) ret->append("{x}"); const Struct_field_list* fields = this->fields_; if (fields != NULL) { bool first = true; for (Struct_field_list::const_iterator p = fields->begin(); p != fields->end(); ++p) { if (first) first = false; else ret->push_back(';'); if (!p->is_anonymous()) { ret->append(Gogo::mangle_possibly_hidden_name(p->field_name())); ret->push_back(' '); } // 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()) { // Use curly braces around a struct tag, since they are // unambiguous here and we have no encoding for // quotation marks. ret->push_back('{'); ret->append(go_mangle_struct_tag(p->tag())); ret->push_back('}'); } } } ret->push_back('}'); } void Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const { ret->push_back('['); 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->append("x"); } ret->push_back(']'); this->append_mangled_name(this->element_type_, gogo, ret); } void Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const { ret->append("map["); this->append_mangled_name(this->key_type_, gogo, ret); ret->push_back(']'); this->append_mangled_name(this->val_type_, gogo, ret); } void Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const { if (!this->may_send_) ret->append("{}"); ret->append("chan"); if (!this->may_receive_) ret->append("{}"); ret->push_back(' '); this->append_mangled_name(this->element_type_, gogo, ret); } void Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const { go_assert(this->methods_are_finalized_); ret->append("interface{"); const Typed_identifier_list* methods = this->all_methods_; if (methods != NULL && !this->seen_) { this->seen_ = true; bool first = true; for (Typed_identifier_list::const_iterator p = methods->begin(); p != methods->end(); ++p) { if (first) first = false; else ret->push_back(';'); if (!p->name().empty()) { ret->append(Gogo::mangle_possibly_hidden_name(p->name())); ret->push_back(' '); } this->append_mangled_name(p->type(), gogo, ret); } this->seen_ = false; } ret->push_back('}'); } 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(); if (no->package() == NULL) ret->append(gogo->pkgpath_symbol()); else ret->append(no->package()->pkgpath_symbol()); ret->push_back('.'); ret->append(Gogo::unpack_hidden_name(no->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 { if (this->in_function_ != NULL) { const Typed_identifier* rcvr = this->in_function_->func_value()->type()->receiver(); if (rcvr != NULL) ret->append(rcvr->type()->deref()->mangled_name(gogo)); else if (this->in_function_->package() == NULL) ret->append(gogo->pkgpath_symbol()); else ret->append(this->in_function_->package()->pkgpath_symbol()); ret->push_back('.'); ret->append(Gogo::unpack_hidden_name(this->in_function_->name())); } else { if (no->package() == NULL) ret->append(gogo->pkgpath_symbol()); else ret->append(no->package()->pkgpath_symbol()); } ret->push_back('.'); } ret->append(Gogo::unpack_hidden_name(no->name())); if (this->in_function_ != NULL && this->in_function_index_ > 0) { char buf[30]; snprintf(buf, sizeof buf, "..i%u", this->in_function_index_); ret->append(buf); } } // 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 for all unsafe pointer types. if (type->is_unsafe_pointer_type()) return "unsafe.Pointer..d"; if (nt == NULL) return "type.." + type->mangled_name(this); std::string ret; Named_object* no = nt->named_object(); unsigned int index; const Named_object* in_function = nt->in_function(&index); if (nt->is_builtin()) go_assert(in_function == NULL); else { if (in_function != NULL) { const Typed_identifier* rcvr = in_function->func_value()->type()->receiver(); if (rcvr != NULL) ret.append(rcvr->type()->deref()->mangled_name(this)); else if (in_function->package() == NULL) ret.append(this->pkgpath_symbol()); else ret.append(in_function->package()->pkgpath_symbol()); ret.push_back('.'); ret.append(Gogo::unpack_hidden_name(in_function->name())); ret.push_back('.'); } if (no->package() == NULL) ret.append(this->pkgpath_symbol()); else ret.append(no->package()->pkgpath_symbol()); ret.push_back('.'); } ret.append(Gogo::mangle_possibly_hidden_name(no->name())); if (in_function != NULL && index > 0) { char buf[30]; snprintf(buf, sizeof buf, "..i%u", index); ret.append(buf); } ret.append("..d"); 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()) + "..g"; } // Return the name for a ptrmask variable. PTRMASK_SYM_NAME is a // base32 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 "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 ? "pimt.." : "imt..") + itype->mangled_name(this) + ".." + type->mangled_name(this)); } // Return whether NAME is a special name that can not be passed to // unpack_hidden_name. This is needed because various special names // use "..SUFFIX", but unpack_hidden_name just looks for '.'. bool Gogo::is_special_name(const std::string& name) { return (name.find("..hash") != std::string::npos || name.find("..eq") != std::string::npos || name.find("..stub") != std::string::npos || name.find("..func") != std::string::npos || name.find("..r") != std::string::npos || name.find("..init") != std::string::npos || name.find("..thunk") != std::string::npos || name.find("..import") != std::string::npos); }