From f3878205ddc2970e384ffaed3a95362763eee9fe Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 22 Nov 2016 22:28:05 +0000 Subject: [PATCH] compiler: relocate ID encoding utilities to gofrontend Relocate the code that encodes/sanitizes identifiers to make them assembler-friendly, moving it from the back end to the front end; the decisions about when to encode an identifier and the calls to the encoding helpers now take place entirely in gofrontend. Reviewed-on: https://go-review.googlesource.com/33424 * go-gcc.cc (char_needs_encoding): Remove. (needs_encoding, fetch_utf8_char, encode_id): Remove. (Gcc_backend::global_variable): Add asm_name parameter. Don't compute asm_name here. (Gcc_backend::implicit_variable): Likewise. (Gcc_backend::implicit_variable_reference): Likewise. (Gcc_backend::immutable_struct): Likewise. (Gcc_backend::immutable_struct_reference): Likewise. * Make-lang.in (GO_OBJS): Add go/go-encode-id.o. From-SVN: r242726 --- gcc/go/ChangeLog | 12 +++ gcc/go/Make-lang.in | 2 + gcc/go/go-gcc.cc | 171 +++++++----------------------- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/backend.h | 61 ++++++----- gcc/go/gofrontend/expressions.cc | 26 +++-- gcc/go/gofrontend/go-encode-id.cc | 113 ++++++++++++++++++++ gcc/go/gofrontend/go-encode-id.h | 30 ++++++ gcc/go/gofrontend/gogo.cc | 47 +++++--- gcc/go/gofrontend/types.cc | 31 ++++-- 10 files changed, 303 insertions(+), 192 deletions(-) create mode 100644 gcc/go/gofrontend/go-encode-id.cc create mode 100644 gcc/go/gofrontend/go-encode-id.h diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 825e4f06e4e..bbae1a9f017 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,15 @@ +2016-11-22 Than McIntosh + + * go-gcc.cc (char_needs_encoding): Remove. + (needs_encoding, fetch_utf8_char, encode_id): Remove. + (Gcc_backend::global_variable): Add asm_name parameter. Don't + compute asm_name here. + (Gcc_backend::implicit_variable): Likewise. + (Gcc_backend::implicit_variable_reference): Likewise. + (Gcc_backend::immutable_struct): Likewise. + (Gcc_backend::immutable_struct_reference): Likewise. + * Make-lang.in (GO_OBJS): Add go/go-encode-id.o. + 2016-11-22 Ian Lance Taylor * go-gcc.cc (Gcc_backend::Gcc_backend): Add builtin function diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index 7235f19af17..67683304634 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -55,6 +55,7 @@ GO_OBJS = \ go/expressions.o \ go/go-backend.o \ go/go-diagnostics.o \ + go/go-encode-id.o \ go/go-dump.o \ go/go-gcc.o \ go/go-gcc-diagnostics.o \ @@ -230,6 +231,7 @@ CFLAGS-go/go-gcc.o += $(GOINCLUDES) CFLAGS-go/go-linemap.o += $(GOINCLUDES) CFLAGS-go/go-sha1.o += $(GOINCLUDES) CFLAGS-go/go-gcc-diagnostics.o += $(GOINCLUDES) +CFLAGS-go/go-encode-id.o += $(GOINCLUDES) go/%.o: go/gofrontend/%.cc $(COMPILE) $(GOINCLUDES) $< diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 619499ec573..dc0041339aa 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -412,9 +412,8 @@ class Gcc_backend : public Backend { return new Bvariable(error_mark_node); } Bvariable* - global_variable(const std::string& package_name, - const std::string& pkgpath, - const std::string& name, + global_variable(const std::string& var_name, + const std::string& asm_name, Btype* btype, bool is_external, bool is_hidden, @@ -440,25 +439,27 @@ class Gcc_backend : public Backend Location, Bstatement**); Bvariable* - implicit_variable(const std::string&, Btype*, bool, bool, bool, - int64_t); + implicit_variable(const std::string&, const std::string&, Btype*, + bool, bool, bool, int64_t); void implicit_variable_set_init(Bvariable*, const std::string&, Btype*, bool, bool, bool, Bexpression*); Bvariable* - implicit_variable_reference(const std::string&, Btype*); + implicit_variable_reference(const std::string&, const std::string&, Btype*); Bvariable* - immutable_struct(const std::string&, bool, bool, Btype*, Location); + immutable_struct(const std::string&, const std::string&, + bool, bool, Btype*, Location); void immutable_struct_set_init(Bvariable*, const std::string&, bool, bool, Btype*, Location, Bexpression*); Bvariable* - immutable_struct_reference(const std::string&, Btype*, Location); + immutable_struct_reference(const std::string&, const std::string&, + Btype*, Location); // Labels. @@ -550,102 +551,6 @@ get_identifier_from_string(const std::string& str) return get_identifier_with_length(str.data(), str.length()); } -// Return whether the character c is OK to use in the assembler. - -static bool -char_needs_encoding(char c) -{ - switch (c) - { - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '_': case '.': case '$': case '/': - return false; - default: - return true; - } -} - -// Return whether the identifier needs to be translated because it -// contains non-ASCII characters. - -static bool -needs_encoding(const std::string& str) -{ - for (std::string::const_iterator p = str.begin(); - p != str.end(); - ++p) - if (char_needs_encoding(*p)) - return true; - return false; -} - -// Pull the next UTF-8 character out of P and store it in *PC. Return -// the number of bytes read. - -static size_t -fetch_utf8_char(const char* p, unsigned int* pc) -{ - unsigned char c = *p; - if ((c & 0x80) == 0) - { - *pc = c; - return 1; - } - size_t len = 0; - while ((c & 0x80) != 0) - { - ++len; - c <<= 1; - } - unsigned int rc = *p & ((1 << (7 - len)) - 1); - for (size_t i = 1; i < len; i++) - { - unsigned int u = p[i]; - rc <<= 6; - rc |= u & 0x3f; - } - *pc = rc; - return len; -} - -// Encode an identifier using ASCII characters. - -static std::string -encode_id(const std::string id) -{ - std::string ret; - const char* p = id.c_str(); - const char* pend = p + id.length(); - while (p < pend) - { - unsigned int c; - size_t len = fetch_utf8_char(p, &c); - if (len == 1 && !char_needs_encoding(c)) - ret += c; - else - { - ret += "$U"; - char buf[30]; - snprintf(buf, sizeof buf, "%x", c); - ret += buf; - ret += "$"; - } - p += len; - } - return ret; -} - // Define the built-in functions that are exposed to GCCGo. Gcc_backend::Gcc_backend() @@ -2580,9 +2485,8 @@ Gcc_backend::non_zero_size_type(tree type) // Make a global variable. Bvariable* -Gcc_backend::global_variable(const std::string& package_name, - const std::string& pkgpath, - const std::string& name, +Gcc_backend::global_variable(const std::string& var_name, + const std::string& asm_name, Btype* btype, bool is_external, bool is_hidden, @@ -2598,9 +2502,6 @@ Gcc_backend::global_variable(const std::string& package_name, if ((is_external || !is_hidden) && int_size_in_bytes(type_tree) == 0) type_tree = this->non_zero_size_type(type_tree); - std::string var_name(package_name); - var_name.push_back('.'); - var_name.append(name); tree decl = build_decl(location.gcc_location(), VAR_DECL, get_identifier_from_string(var_name), type_tree); @@ -2611,17 +2512,12 @@ Gcc_backend::global_variable(const std::string& package_name, if (!is_hidden) { TREE_PUBLIC(decl) = 1; - - std::string asm_name(pkgpath); - asm_name.push_back('.'); - asm_name.append(name); - if (needs_encoding(asm_name)) - asm_name = encode_id(asm_name); SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); } - else if (needs_encoding(var_name)) - SET_DECL_ASSEMBLER_NAME(decl, - get_identifier_from_string(encode_id(var_name))); + else + { + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + } TREE_USED(decl) = 1; @@ -2814,8 +2710,9 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, // generating GC root variables and storing the values of a slice initializer. Bvariable* -Gcc_backend::implicit_variable(const std::string& name, Btype* type, - bool is_hidden, bool is_constant, +Gcc_backend::implicit_variable(const std::string& name, + const std::string& asm_name, + Btype* type, bool is_hidden, bool is_constant, bool is_common, int64_t alignment) { tree type_tree = type->get_tree(); @@ -2857,8 +2754,8 @@ Gcc_backend::implicit_variable(const std::string& name, Btype* type, SET_DECL_ALIGN(decl, alignment * BITS_PER_UNIT); DECL_USER_ALIGN(decl) = 1; } - if (needs_encoding(name)) - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name))); + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); go_preserve_from_gc(decl); return new Bvariable(decl); @@ -2899,7 +2796,9 @@ Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&, // Return a reference to an implicit variable defined in another package. Bvariable* -Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype) +Gcc_backend::implicit_variable_reference(const std::string& name, + const std::string& asm_name, + Btype* btype) { tree type_tree = btype->get_tree(); if (type_tree == error_mark_node) @@ -2911,8 +2810,8 @@ Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype) TREE_PUBLIC(decl) = 1; TREE_STATIC(decl) = 1; DECL_ARTIFICIAL(decl) = 1; - if (needs_encoding(name)) - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name))); + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); go_preserve_from_gc(decl); return new Bvariable(decl); } @@ -2920,7 +2819,9 @@ Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype) // Create a named immutable initialized data structure. Bvariable* -Gcc_backend::immutable_struct(const std::string& name, bool is_hidden, +Gcc_backend::immutable_struct(const std::string& name, + const std::string& asm_name, + bool is_hidden, bool is_common, Btype* btype, Location location) { tree type_tree = btype->get_tree(); @@ -2937,8 +2838,8 @@ Gcc_backend::immutable_struct(const std::string& name, bool is_hidden, DECL_ARTIFICIAL(decl) = 1; if (!is_hidden) TREE_PUBLIC(decl) = 1; - if (needs_encoding(name)) - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name))); + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); // When the initializer for one immutable_struct refers to another, // it needs to know the visibility of the referenced struct so that @@ -2998,7 +2899,9 @@ Gcc_backend::immutable_struct_set_init(Bvariable* var, const std::string&, // defined in another package. Bvariable* -Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype, +Gcc_backend::immutable_struct_reference(const std::string& name, + const std::string& asm_name, + Btype* btype, Location location) { tree type_tree = btype->get_tree(); @@ -3013,8 +2916,8 @@ Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype, DECL_ARTIFICIAL(decl) = 1; TREE_PUBLIC(decl) = 1; DECL_EXTERNAL(decl) = 1; - if (needs_encoding(name)) - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name))); + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); go_preserve_from_gc(decl); return new Bvariable(decl); } @@ -3104,10 +3007,8 @@ Gcc_backend::function(Btype* fntype, const std::string& name, return this->error_function(); tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype); - if (!asm_name.empty()) + if (! asm_name.empty()) SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); - else if (needs_encoding(name)) - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name))); if (is_visible) TREE_PUBLIC(decl) = 1; if (is_declaration) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5ff8b8df065..fec65b8ca0d 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -e66f30e862cb5d02b9d55bf44ac439bb8fc4ea19 +4d8e00e730897cc7e73b1582522ecab031cfcaf2 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index dacfe486e5d..e93cdfece76 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -482,21 +482,19 @@ class Backend virtual Bvariable* error_variable() = 0; - // Create a global variable. PACKAGE_NAME is the name of the - // package where the variable is defined. PKGPATH is the package - // path for that package, from the -fgo-pkgpath or -fgo-prefix - // option. NAME is the name of the variable. BTYPE is the type of - // the variable. IS_EXTERNAL is true if the variable is defined in - // some other package. IS_HIDDEN is true if the variable is not - // exported (name begins with a lower case letter). - // IN_UNIQUE_SECTION is true if the variable should be put into a - // unique section if possible; this is intended to permit the linker - // to garbage collect the variable if it is not referenced. - // LOCATION is where the variable was defined. + // Create a global variable. NAME is the package-qualified name of + // the variable. ASM_NAME is the encoded identifier for the + // variable, incorporating the package, and made safe for the + // assembler. BTYPE is the type of the variable. IS_EXTERNAL is + // true if the variable is defined in some other package. IS_HIDDEN + // is true if the variable is not exported (name begins with a lower + // case letter). IN_UNIQUE_SECTION is true if the variable should + // be put into a unique section if possible; this is intended to + // permit the linker to garbage collect the variable if it is not + // referenced. LOCATION is where the variable was defined. virtual Bvariable* - global_variable(const std::string& package_name, - const std::string& pkgpath, - const std::string& name, + global_variable(const std::string& name, + const std::string& asm_name, Btype* btype, bool is_external, bool is_hidden, @@ -561,6 +559,9 @@ class Backend // // NAME is the name to use for the initialized variable this will create. // + // ASM_NAME is encoded assembler-friendly version of the name, or the + // empty string if no encoding is needed. + // // TYPE is the type of the implicit variable. // // IS_HIDDEN will be true if the descriptor should only be visible @@ -578,8 +579,9 @@ class Backend // // If ALIGNMENT is not zero, it is the desired alignment of the variable. virtual Bvariable* - implicit_variable(const std::string& name, Btype* type, bool is_hidden, - bool is_constant, bool is_common, int64_t alignment) = 0; + implicit_variable(const std::string& name, const std::string& asm_name, + Btype* type, bool is_hidden, bool is_constant, + bool is_common, int64_t alignment) = 0; // Set the initial value of a variable created by implicit_variable. @@ -597,12 +599,15 @@ class Backend bool is_hidden, bool is_constant, bool is_common, Bexpression* init) = 0; - // Create a reference to a named implicit variable defined in some other - // package. This will be a variable created by a call to implicit_variable - // with the same NAME and TYPE and with IS_COMMON passed as false. This - // corresponds to an extern global variable in C. + // Create a reference to a named implicit variable defined in some + // other package. This will be a variable created by a call to + // implicit_variable with the same NAME, ASM_NAME and TYPE and with + // IS_COMMON passed as false. This corresponds to an extern global + // variable in C. virtual Bvariable* - implicit_variable_reference(const std::string& name, Btype* type) = 0; + implicit_variable_reference(const std::string& name, + const std::string& asm_name, + Btype* type) = 0; // Create a named immutable initialized data structure. This is // used for type descriptors, map descriptors, and function @@ -612,6 +617,9 @@ class Backend // NAME is the name to use for the initialized global variable which // this call will create. // + // ASM_NAME is the encoded, assembler-friendly version of NAME, or + // the empty string if no encoding is needed. + // // IS_HIDDEN will be true if the descriptor should only be visible // within the current object. // @@ -630,7 +638,9 @@ class Backend // address. After calling this the frontend will call // immutable_struct_set_init. virtual Bvariable* - immutable_struct(const std::string& name, bool is_hidden, bool is_common, + immutable_struct(const std::string& name, + const std::string& asm_name, + bool is_hidden, bool is_common, Btype* type, Location) = 0; // Set the initial value of a variable created by immutable_struct. @@ -648,11 +658,12 @@ class Backend // Create a reference to a named immutable initialized data // structure defined in some other package. This will be a // structure created by a call to immutable_struct with the same - // NAME and TYPE and with IS_COMMON passed as false. This + // NAME, ASM_NAME and TYPE and with IS_COMMON passed as false. This // corresponds to an extern const global variable in C. virtual Bvariable* - immutable_struct_reference(const std::string& name, Btype* type, - Location) = 0; + immutable_struct_reference(const std::string& name, + const std::string& asm_name, + Btype* type, Location) = 0; // Labels. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 35c3e744dd2..0ab67260875 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -11,6 +11,7 @@ #include "go-c.h" #include "gogo.h" #include "go-diagnostics.h" +#include "go-encode-id.h" #include "types.h" #include "export.h" #include "import.h" @@ -1304,16 +1305,18 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) Btype* btype = this->type()->get_backend(gogo); Bvariable* bvar; + std::string asm_name(go_selectively_encode_id(var_name)); if (no->package() != NULL || is_descriptor) - bvar = context->backend()->immutable_struct_reference(var_name, btype, - loc); + bvar = context->backend()->immutable_struct_reference(var_name, asm_name, + btype, loc); else { Location bloc = Linemap::predeclared_location(); bool is_hidden = ((no->is_function() && no->func_value()->enclosing() != NULL) || Gogo::is_thunk(no)); - bvar = context->backend()->immutable_struct(var_name, is_hidden, false, + bvar = context->backend()->immutable_struct(var_name, asm_name, + is_hidden, false, btype, bloc); Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_func_code_reference(this->fn_, bloc)); @@ -4283,9 +4286,11 @@ 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)); Bvariable* implicit = - gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap, - false, 0); + gogo->backend()->implicit_variable(buf, asm_name, + btype, true, copy_to_heap, + false, 0); gogo->backend()->implicit_variable_set_init(implicit, buf, btype, true, copy_to_heap, false, bexpr); @@ -4299,8 +4304,10 @@ Unary_expression::do_get_backend(Translate_context* context) snprintf(buf, sizeof buf, "C%u", counter); ++counter; + std::string asm_name(go_selectively_encode_id(buf)); Bvariable* decl = - gogo->backend()->immutable_struct(buf, true, false, btype, loc); + gogo->backend()->immutable_struct(buf, asm_name, + true, false, btype, loc); gogo->backend()->immutable_struct_set_init(decl, buf, true, false, btype, loc, bexpr); bexpr = gogo->backend()->var_expression(decl, loc); @@ -15074,8 +15081,10 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) && this->type_->named_type()->named_object()->package() != NULL) { Btype* btype = this->type()->get_backend(gogo); + std::string asm_name(go_selectively_encode_id(mangled_name)); this->bvar_ = - gogo->backend()->immutable_struct_reference(mangled_name, btype, loc); + gogo->backend()->immutable_struct_reference(mangled_name, asm_name, + btype, loc); return gogo->backend()->var_expression(this->bvar_, this->location()); } @@ -15119,7 +15128,8 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) Bexpression* ctor = mtable->get_backend(context); bool is_public = has_hidden_methods && this->type_->named_type() != NULL; - this->bvar_ = gogo->backend()->immutable_struct(mangled_name, false, + std::string asm_name(go_selectively_encode_id(mangled_name)); + this->bvar_ = gogo->backend()->immutable_struct(mangled_name, asm_name, false, !is_public, btype, loc); gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false, !is_public, btype, loc, ctor); diff --git a/gcc/go/gofrontend/go-encode-id.cc b/gcc/go/gofrontend/go-encode-id.cc new file mode 100644 index 00000000000..978f20823d6 --- /dev/null +++ b/gcc/go/gofrontend/go-encode-id.cc @@ -0,0 +1,113 @@ +// go-encode-id.cc -- Go identifier encoding hooks + +// Copyright 2016 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-location.h" +#include "go-linemap.h" +#include "go-encode-id.h" + +// Return whether the character c is OK to use in the assembler. + +static bool +char_needs_encoding(char c) +{ + switch (c) + { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '_': case '.': case '$': case '/': + return false; + default: + return true; + } +} + +// Return whether the identifier needs to be translated because it +// contains non-ASCII characters. + +bool +go_id_needs_encoding(const std::string& str) +{ + for (std::string::const_iterator p = str.begin(); + p != str.end(); + ++p) + if (char_needs_encoding(*p)) + return true; + return false; +} + +// Pull the next UTF-8 character out of P and store it in *PC. Return +// the number of bytes read. + +static size_t +fetch_utf8_char(const char* p, unsigned int* pc) +{ + unsigned char c = *p; + if ((c & 0x80) == 0) + { + *pc = c; + return 1; + } + size_t len = 0; + while ((c & 0x80) != 0) + { + ++len; + c <<= 1; + } + unsigned int rc = *p & ((1 << (7 - len)) - 1); + for (size_t i = 1; i < len; i++) + { + unsigned int u = p[i]; + rc <<= 6; + rc |= u & 0x3f; + } + *pc = rc; + return len; +} + +// Encode an identifier using ASCII characters. + +std::string +go_encode_id(const std::string &id) +{ + std::string ret; + const char* p = id.c_str(); + const char* pend = p + id.length(); + while (p < pend) + { + unsigned int c; + size_t len = fetch_utf8_char(p, &c); + if (len == 1 && !char_needs_encoding(c)) + ret += c; + else + { + ret += "$U"; + char buf[30]; + snprintf(buf, sizeof buf, "%x", c); + ret += buf; + ret += "$"; + } + p += len; + } + return ret; +} + +std::string +go_selectively_encode_id(const std::string &id) +{ + if (go_id_needs_encoding(id)) + return go_encode_id(id); + return std::string(); +} diff --git a/gcc/go/gofrontend/go-encode-id.h b/gcc/go/gofrontend/go-encode-id.h new file mode 100644 index 00000000000..b95d97dd1ba --- /dev/null +++ b/gcc/go/gofrontend/go-encode-id.h @@ -0,0 +1,30 @@ +// go-encode-id.h -- Go identifier encoding utilities -*- C++ -*- + +// Copyright 2016 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. + +#ifndef GO_ENCODE_ID_H +#define GO_ENCODE_ID_H + +#include "backend.h" + +// Given an identifier corresponding to a function or variable, +// this helper returns TRUE if the identifier needs special +// encoding to be used as an ASM name (symbol), FALSE if the name +// is OK as is. +extern bool +go_id_needs_encoding(const std::string& str); + +// Encodes the specified identifier for ASM name safety, returning a +// string with the encoded value. +extern std::string +go_encode_id(const std::string &id); + +// Returns the empty string if the specified name needs encoding, +// otherwise invokes go_encode_id() on the name and returns the +// result. +extern std::string +go_selectively_encode_id(const std::string &id); + +#endif // !defined(GO_ENCODE_ID_H) diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index a9dd0a6f168..b671ce5bced 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -12,6 +12,7 @@ #include "go-c.h" #include "go-diagnostics.h" +#include "go-encode-id.h" #include "go-dump.h" #include "go-optimize.h" #include "lex.h" @@ -5326,6 +5327,10 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) if ((this->pragmas_ & GOPRAGMA_NOSPLIT) != 0) 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)); + // This should go into a unique section if that has been // requested elsewhere, or if this is a nointerface function. // We want to put a nointerface function into a unique section @@ -5379,6 +5384,8 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) asm_name.append(rtype->mangled_name(gogo)); } } + else if (go_id_needs_encoding(no->get_id(gogo))) + asm_name = go_encode_id(no->get_id(gogo)); Btype* functype = this->fntype_->get_backend_fntype(gogo); this->fndecl_ = @@ -6594,25 +6601,39 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, type = Type::make_pointer_type(type); } - std::string n = Gogo::unpack_hidden_name(name); + const std::string n = Gogo::unpack_hidden_name(name); Btype* btype = type->get_backend(gogo); Bvariable* bvar; if (Map_type::is_zero_value(this)) bvar = Map_type::backend_zero_value(gogo); else if (this->is_global_) - bvar = backend->global_variable((package == NULL - ? gogo->package_name() - : package->package_name()), - (package == NULL - ? gogo->pkgpath_symbol() - : package->pkgpath_symbol()), - n, - btype, - package != NULL, - Gogo::is_hidden_name(name), - this->in_unique_section_, - this->location_); + { + std::string var_name(package != NULL + ? package->package_name() + : 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); + bvar = backend->global_variable(var_name, + asm_name, + btype, + package != NULL, + Gogo::is_hidden_name(name), + this->in_unique_section_, + this->location_); + } else if (function == NULL) { go_assert(saw_errors()); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index bc6e3c62838..33d3460e493 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -11,6 +11,7 @@ #include "go-c.h" #include "gogo.h" #include "go-diagnostics.h" +#include "go-encode-id.h" #include "operator.h" #include "expressions.h" #include "statements.h" @@ -1217,10 +1218,12 @@ 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 asm_name(go_selectively_encode_id(name)); this->type_descriptor_var_ = - gogo->backend()->immutable_struct_reference("__go_tdn_unsafe.Pointer", - td_btype, - bloc); + gogo->backend()->immutable_struct_reference(name, asm_name, + td_btype, + bloc); if (phash != NULL) *phash = this->type_descriptor_var_; @@ -1239,10 +1242,11 @@ Type::make_type_descriptor_var(Gogo* gogo) const Package* dummy; if (this->type_descriptor_defined_elsewhere(nt, &dummy)) { + std::string asm_name(go_selectively_encode_id(var_name)); this->type_descriptor_var_ = - gogo->backend()->immutable_struct_reference(var_name, - initializer_btype, - loc); + gogo->backend()->immutable_struct_reference(var_name, asm_name, + initializer_btype, + loc); if (phash != NULL) *phash = this->type_descriptor_var_; return; @@ -1271,8 +1275,9 @@ Type::make_type_descriptor_var(Gogo* gogo) // ensure that type_descriptor_pointer will work if called while // converting INITIALIZER. + std::string asm_name(go_selectively_encode_id(var_name)); this->type_descriptor_var_ = - gogo->backend()->immutable_struct(var_name, false, is_common, + gogo->backend()->immutable_struct(var_name, asm_name, false, is_common, initializer_btype, loc); if (phash != NULL) *phash = this->type_descriptor_var_; @@ -2187,8 +2192,10 @@ Type::make_gc_symbol_var(Gogo* gogo) const Package* dummy; if (this->type_descriptor_defined_elsewhere(nt, &dummy)) { + std::string asm_name(go_selectively_encode_id(sym_name)); this->gc_symbol_var_ = - gogo->backend()->implicit_variable_reference(sym_name, sym_btype); + gogo->backend()->implicit_variable_reference(sym_name, asm_name, + sym_btype); if (phash != NULL) *phash = this->gc_symbol_var_; return; @@ -2213,8 +2220,10 @@ Type::make_gc_symbol_var(Gogo* gogo) // Since we are building the GC symbol in this package, we must create the // variable before converting the initializer to its backend representation // because the initializer may refer to the GC symbol for this type. + std::string asm_name(go_selectively_encode_id(sym_name)); this->gc_symbol_var_ = - gogo->backend()->implicit_variable(sym_name, sym_btype, false, true, is_common, 0); + gogo->backend()->implicit_variable(sym_name, asm_name, + sym_btype, false, true, is_common, 0); if (phash != NULL) *phash = this->gc_symbol_var_; @@ -7034,8 +7043,10 @@ Map_type::backend_zero_value(Gogo* gogo) Btype* barray_type = gogo->backend()->array_type(buint8_type, blength); std::string zname = Map_type::zero_value->name(); + std::string asm_name(go_selectively_encode_id(zname)); Bvariable* zvar = - gogo->backend()->implicit_variable(zname, barray_type, false, true, true, + gogo->backend()->implicit_variable(zname, asm_name, + barray_type, false, true, true, Map_type::zero_value_align); gogo->backend()->implicit_variable_set_init(zvar, zname, barray_type, false, true, true, NULL); -- 2.30.2