LCOV - code coverage report
Current view: top level - gcc/go/gofrontend - go-encode-id.cc (source / functions) Hit Total Coverage
Test: gcc.info Lines: 78 118 66.1 %
Date: 2020-07-04 13:15:35 Functions: 7 9 77.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // go-encode-id.cc -- Go identifier and packagepath encoding/decoding hooks
       2                 :            : 
       3                 :            : // Copyright 2016 The Go Authors. All rights reserved.
       4                 :            : // Use of this source code is governed by a BSD-style
       5                 :            : // license that can be found in the LICENSE file.
       6                 :            : 
       7                 :            : #include "go-system.h"
       8                 :            : 
       9                 :            : #include "gogo.h"
      10                 :            : #include "go-location.h"
      11                 :            : #include "go-linemap.h"
      12                 :            : #include "go-encode-id.h"
      13                 :            : #include "lex.h"
      14                 :            : 
      15                 :            : // Return whether the character c is OK to use in the assembler.  We
      16                 :            : // only permit ASCII alphanumeric characters, underscore, and dot.
      17                 :            : 
      18                 :            : static bool
      19                 :   61090503 : char_needs_encoding(char c)
      20                 :            : {
      21                 :   61090503 :   switch (c)
      22                 :            :     {
      23                 :            :     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
      24                 :            :     case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
      25                 :            :     case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
      26                 :            :     case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
      27                 :            :     case 'Y': case 'Z':
      28                 :            :     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
      29                 :            :     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
      30                 :            :     case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
      31                 :            :     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
      32                 :            :     case 'y': case 'z':
      33                 :            :     case '0': case '1': case '2': case '3': case '4':
      34                 :            :     case '5': case '6': case '7': case '8': case '9':
      35                 :            :     case '_': case '.':
      36                 :            :       return false;
      37                 :    1435450 :     default:
      38                 :    1435450 :       return true;
      39                 :            :     }
      40                 :            : }
      41                 :            : 
      42                 :            : // Return whether the identifier needs to be translated because it
      43                 :            : // contains non-ASCII characters.
      44                 :            : 
      45                 :            : bool
      46                 :    1497811 : go_id_needs_encoding(const std::string& str)
      47                 :            : {
      48                 :   31360606 :   for (std::string::const_iterator p = str.begin();
      49                 :   31360606 :        p != str.end();
      50                 :   31360606 :        ++p)
      51                 :   30011049 :     if (char_needs_encoding(*p))
      52                 :    1497811 :       return true;
      53                 :            :   return false;
      54                 :            : }
      55                 :            : 
      56                 :            : // Pull the next UTF-8 character out of P and store it in *PC.  Return
      57                 :            : // the number of bytes read.
      58                 :            : 
      59                 :            : static size_t
      60                 :   31079720 : fetch_utf8_char(const char* p, unsigned int* pc)
      61                 :            : {
      62                 :   31079720 :   unsigned char c = *p;
      63                 :   31079720 :   if ((c & 0x80) == 0)
      64                 :            :     {
      65                 :   31079454 :       *pc = c;
      66                 :   31079454 :       return 1;
      67                 :            :     }
      68                 :            :   size_t len = 0;
      69                 :        960 :   while ((c & 0x80) != 0)
      70                 :            :     {
      71                 :        694 :       ++len;
      72                 :        694 :       c <<= 1;
      73                 :            :     }
      74                 :        266 :   unsigned int rc = *p & ((1 << (7 - len)) - 1);
      75                 :        694 :   for (size_t i = 1; i < len; i++)
      76                 :            :     {
      77                 :        428 :       unsigned int u = p[i];
      78                 :        428 :       rc <<= 6;
      79                 :        428 :       rc |= u & 0x3f;
      80                 :            :     }
      81                 :        266 :   *pc = rc;
      82                 :        266 :   return len;
      83                 :            : }
      84                 :            : 
      85                 :            : // Encode an identifier using assembler-friendly characters. The encoding is
      86                 :            : // described in detail near the end of the long comment at the start of
      87                 :            : // names.cc. Short version: translate all non-ASCII-alphanumeric characters into
      88                 :            : // ..uXXXX or ..UXXXXXXXX, translate ASCII non-alphanumerics into ".zXX".
      89                 :            : 
      90                 :            : std::string
      91                 :     838738 : go_encode_id(const std::string &id)
      92                 :            : {
      93                 :     838738 :   if (Lex::is_invalid_identifier(id))
      94                 :            :     {
      95                 :          1 :       go_assert(saw_errors());
      96                 :          1 :       return id;
      97                 :            :     }
      98                 :            : 
      99                 :            :   // The encoding is only unambiguous if the input string does not
     100                 :            :   // contain ..z, ..u or ..U.
     101                 :     838737 :   go_assert(id.find("..z") == std::string::npos);
     102                 :     838737 :   go_assert(id.find("..u") == std::string::npos);
     103                 :     838737 :   go_assert(id.find("..U") == std::string::npos);
     104                 :            : 
     105                 :     838737 :   std::string ret;
     106                 :     838737 :   const char* p = id.c_str();
     107                 :     838737 :   const char* pend = p + id.length();
     108                 :            : 
     109                 :            :   // A leading ".0" is a space introduced before a mangled type name
     110                 :            :   // that starts with a 'u' or 'U', to avoid confusion with the
     111                 :            :   // mangling used here.  We don't need a leading ".0", and we don't
     112                 :            :   // want symbols that start with '.', so remove it.
     113                 :     838737 :   if (p[0] == '.' && p[1] == '0')
     114                 :         60 :     p += 2;
     115                 :            : 
     116                 :   31220955 :   while (p < pend)
     117                 :            :     {
     118                 :   30382218 :       unsigned int c;
     119                 :   30382218 :       size_t len = fetch_utf8_char(p, &c);
     120                 :   30382218 :       if (len == 1 && !char_needs_encoding(c))
     121                 :            :         {
     122                 :   29259623 :           ret += c;
     123                 :            :         }
     124                 :            :       else
     125                 :            :         {
     126                 :    1122595 :           char buf[16];
     127                 :    1122595 :           if (len == 1)
     128                 :    1122419 :             snprintf(buf, sizeof buf, "..z%02x", c);
     129                 :        176 :           else if (c < 0x10000)
     130                 :        176 :             snprintf(buf, sizeof buf, "..u%04x", c);
     131                 :            :           else
     132                 :          0 :             snprintf(buf, sizeof buf, "..U%08x", c);
     133                 :            : 
     134                 :            :           // We don't want a symbol to start with '.', so add a prefix
     135                 :            :           // if needed.
     136                 :    1122595 :           if (ret.empty())
     137                 :          0 :             ret += '_';
     138                 :            : 
     139                 :    1122595 :           ret += buf;
     140                 :            :         }
     141                 :   30382218 :       p += len;
     142                 :            :     }
     143                 :    1677474 :   return ret;
     144                 :            : }
     145                 :            : 
     146                 :            : // Convert a hex digit string to a unicode codepoint. No checking
     147                 :            : // to insure that the hex digit is meaningful.
     148                 :            : 
     149                 :            : static unsigned
     150                 :          0 : hex_digits_to_unicode_codepoint(const char *digits, unsigned ndig)
     151                 :            : {
     152                 :          0 :   unsigned result = 0;
     153                 :          0 :   for (unsigned i = 0; i < ndig; ++i) {
     154                 :          0 :     result <<= 4;
     155                 :          0 :     result |= Lex::hex_val(digits[i]);
     156                 :            :   }
     157                 :          0 :   return result;
     158                 :            : }
     159                 :            : 
     160                 :            : // Decode/demangle a mangled string produced by go_encode_id(). Returns
     161                 :            : // empty string if demangling process fails in some way.  At the moment
     162                 :            : // this routine is unused; there is an equivalent routine in the runtime
     163                 :            : // used for demangling symbols appearing in stack traces.
     164                 :            : 
     165                 :            : std::string
     166                 :          0 : go_decode_id(const std::string &encoded)
     167                 :            : {
     168                 :          0 :   std::string ret;
     169                 :          0 :   const char* p = encoded.c_str();
     170                 :          0 :   const char* pend = p + encoded.length();
     171                 :          0 :   const Location loc = Linemap::predeclared_location();
     172                 :            : 
     173                 :            :   // Special case for initial "_", in case it was introduced
     174                 :            :   // as a way to prevent encoded symbol starting with ".".
     175                 :          0 :   if (*p == '_' && (strncmp(p+1, "..u", 3) == 0 || strncmp(p+1, "..U", 3) == 0))
     176                 :          0 :     p++;
     177                 :            : 
     178                 :          0 :   while (p < pend)
     179                 :            :     {
     180                 :          0 :       if (strncmp(p, "..z", 3) == 0)
     181                 :            :         {
     182                 :          0 :           const char* digits = p+3;
     183                 :          0 :           if (strlen(digits) < 2)
     184                 :          0 :             return "";
     185                 :          0 :           unsigned rune = hex_digits_to_unicode_codepoint(digits, 2);
     186                 :          0 :           Lex::append_char(rune, true, &ret, loc);
     187                 :          0 :           p += 5;
     188                 :            :         }
     189                 :          0 :       else if (strncmp(p, "..u", 3) == 0)
     190                 :            :         {
     191                 :          0 :           const char* digits = p+3;
     192                 :          0 :           if (strlen(digits) < 4)
     193                 :          0 :             return "";
     194                 :          0 :           unsigned rune = hex_digits_to_unicode_codepoint(digits, 4);
     195                 :          0 :           Lex::append_char(rune, true, &ret, loc);
     196                 :          0 :           p += 7;
     197                 :            :         }
     198                 :          0 :       else if (strncmp(p, "..U", 3) == 0)
     199                 :            :         {
     200                 :          0 :           const char* digits = p+3;
     201                 :          0 :           if (strlen(digits) < 8)
     202                 :          0 :             return "";
     203                 :          0 :           unsigned rune = hex_digits_to_unicode_codepoint(digits, 8);
     204                 :          0 :           Lex::append_char(rune, true, &ret, loc);
     205                 :          0 :           p += 11;
     206                 :            :         }
     207                 :            :       else
     208                 :            :         {
     209                 :          0 :           ret += *p;
     210                 :          0 :           p += 1;
     211                 :            :         }
     212                 :            :     }
     213                 :            : 
     214                 :          0 :   return ret;
     215                 :            : }
     216                 :            : 
     217                 :            : std::string
     218                 :    1395818 : go_selectively_encode_id(const std::string &id)
     219                 :            : {
     220                 :    1395818 :   if (go_id_needs_encoding(id))
     221                 :     148254 :     return go_encode_id(id);
     222                 :    1247564 :   return std::string();
     223                 :            : }
     224                 :            : 
     225                 :            : // Encode a struct field tag.  This is only used when we need to
     226                 :            : // create a type descriptor for an anonymous struct type with field
     227                 :            : // tags.  This mangling is applied before go_encode_id.  We skip
     228                 :            : // alphanumerics and underscore, replace every other single byte
     229                 :            : // character with .xNN, and leave larger UTF-8 characters for
     230                 :            : // go_encode_id.
     231                 :            : 
     232                 :            : std::string
     233                 :      41624 : go_mangle_struct_tag(const std::string& tag)
     234                 :            : {
     235                 :      41624 :   std::string ret;
     236                 :      41624 :   const char* p = tag.c_str();
     237                 :      41624 :   const char* pend = p + tag.length();
     238                 :     739126 :   while (p < pend)
     239                 :            :     {
     240                 :     697502 :       unsigned int c;
     241                 :     697502 :       size_t len = fetch_utf8_char(p, &c);
     242                 :     697502 :       if (len > 1)
     243                 :         90 :         ret.append(p, len);
     244                 :     697412 :       else if (!char_needs_encoding(c) && c != '.')
     245                 :     531963 :         ret += c;
     246                 :            :       else
     247                 :            :         {
     248                 :     165449 :           char buf[16];
     249                 :     165449 :           snprintf(buf, sizeof buf, ".x%02x", c);
     250                 :     165449 :           ret += buf;
     251                 :            :         }
     252                 :     697502 :       p += len;
     253                 :            :     }
     254                 :      41624 :   return ret;
     255                 :            : }
     256                 :            : 
     257                 :            : // Encode a package path.
     258                 :            : 
     259                 :            : std::string
     260                 :       1964 : go_mangle_pkgpath(const std::string& pkgpath)
     261                 :            : {
     262                 :       1964 :   std::string s = pkgpath;
     263                 :       1964 :   for (size_t i = s.find('.');
     264                 :       2212 :        i != std::string::npos;
     265                 :        248 :        i = s.find('.', i + 1))
     266                 :        248 :     s.replace(i, 1, ".x2e"); // 0x2e is the ASCII encoding for '.'
     267                 :       1964 :   return s;
     268                 :            : }

Generated by: LCOV version 1.0

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto --enable-host-shared. GCC test suite is run with the built compiler.