Chromium Code Reviews| Index: src/IceGlobalContext.cpp |
| diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp |
| index d2940807a1e5f8e45fb33cd7beaf51c102ba2072..36afbedc73df4ecce9a0f64b3075b2b7fb834251 100644 |
| --- a/src/IceGlobalContext.cpp |
| +++ b/src/IceGlobalContext.cpp |
| @@ -12,7 +12,7 @@ |
| // |
| //===----------------------------------------------------------------------===// |
| -#include <ctype.h> // isdigit() |
| +#include <ctype.h> // isdigit(), isupper() |
| #include "IceDefs.h" |
| #include "IceTypes.h" |
| @@ -120,6 +120,92 @@ GlobalContext::GlobalContext(llvm::raw_ostream *OsDump, |
| ConstPool(new ConstantPool()), Arch(Arch), Opt(Opt), |
| TestPrefix(TestPrefix), HasEmittedFirstMethod(false) {} |
| +// Scan a string for S[0-9A-Z]*_ patterns and replace them with |
| +// S<num>_ where <num> is the next base-36 value. If a type name |
| +// legitimately contains that pattern, then the substitution will be |
| +// made in error and most likely the link will fail. In this case, |
| +// the test classes can be rewritten not to use that pattern, which is |
| +// much simpler and more reliable than implementing a full demangling |
| +// parser. Another substitution-in-error may occur if a type |
| +// identifier ends with the pattern S[0-9A-Z]*, because an immediately |
| +// following substitution string like "S1_" or "PS1_" may be combined |
| +// with the previous type. |
| +void GlobalContext::incrementSubstitutions(ManglerVector &OldName) const { |
| + // Provide extra space in case the length of <num> increases. |
| + ManglerVector NewName(OldName.size() * 2); |
| + size_t OldPos = 0; |
| + size_t NewPos = 0; |
| + size_t OldLen = OldName.size(); |
| + for (; OldPos < OldLen; ++OldPos, ++NewPos) { |
| + if (OldName[OldPos] == '\0') |
| + break; |
| + if (OldName[OldPos] == 'S') { |
| + // Search forward until we find _ or invalid character (including \0). |
| + bool AllZs = true; |
| + bool Valid = true; |
| + bool Found = false; |
| + size_t Last; |
| + for (Last = OldPos + 1; Last < OldLen && Valid; ++Last) { |
|
jvoung (off chromium)
2014/07/11 20:40:08
There's an explicit break; when Valid is set to fa
Jim Stichnoth
2014/07/11 21:05:11
Done. BTW, it would also be possible to remove th
|
| + char Ch = OldName[Last]; |
| + if (Ch == '_') { |
| + Found = true; |
| + break; |
| + } else if (std::isdigit(Ch) || std::isupper(Ch)) { |
|
jvoung (off chromium)
2014/07/11 20:40:08
Should this explicitly pass as parameter the "C" l
Jim Stichnoth
2014/07/11 21:05:12
Done.
|
| + if (Ch != 'Z') |
| + AllZs = false; |
| + } else { |
| + // Invalid character, stop searching. |
| + Valid = false; |
| + break; |
| + } |
| + } |
| + if (Found) { |
| + NewName[NewPos++] = OldName[OldPos++]; // 'S' |
| + size_t Length = Last - OldPos; |
| + // NewPos and OldPos point just past the 'S'. |
| + assert(NewName[NewPos - 1] == 'S'); |
| + assert(OldName[OldPos - 1] == 'S'); |
| + assert(OldName[OldPos + Length] == '_'); |
| + if (AllZs) { |
| + // Replace N 'Z' characters with N+1 '0' characters. |
|
jvoung (off chromium)
2014/07/11 20:40:08
This case also handles the "S_" ?
Jim Stichnoth
2014/07/11 21:05:11
Yes. Added a comment to clarify.
|
| + for (size_t i = 0; i < Length + 1; ++i) { |
| + NewName[NewPos++] = '0'; |
| + } |
| + } else { |
| + // Iterate right-to-left and increment the base-36 number. |
| + bool Carry = true; |
| + for (size_t i = 0; i < Length; ++i) { |
| + size_t Offset = Length - 1 - i; |
| + char Ch = OldName[OldPos + Offset]; |
| + if (Carry) { |
| + Carry = false; |
| + switch (Ch) { |
| + case '9': |
| + Ch = 'A'; |
| + break; |
| + case 'Z': |
| + Ch = '0'; |
| + Carry = true; |
| + break; |
| + default: |
| + ++Ch; |
| + break; |
| + } |
| + } |
| + NewName[NewPos + Offset] = Ch; |
| + } |
| + NewPos += Length; |
| + } |
| + OldPos = Last; |
| + // Fall through and let the '_' be copied across. |
| + } |
| + } |
| + NewName[NewPos] = OldName[OldPos]; |
| + } |
| + assert(NewName[NewPos] == '\0'); |
| + OldName = NewName; |
| +} |
| + |
| // In this context, name mangling means to rewrite a symbol using a |
| // given prefix. For a C++ symbol, nest the original symbol inside |
| // the "prefix" namespace. For other symbols, just prepend the |
| @@ -137,9 +223,9 @@ IceString GlobalContext::mangleName(const IceString &Name) const { |
| return Name; |
| unsigned PrefixLength = getTestPrefix().length(); |
| - llvm::SmallVector<char, 32> NameBase(1 + Name.length()); |
| + ManglerVector NameBase(1 + Name.length()); |
| const size_t BufLen = 30 + Name.length() + PrefixLength; |
| - llvm::SmallVector<char, 32> NewName(BufLen); |
| + ManglerVector NewName(BufLen); |
| uint32_t BaseLength = 0; // using uint32_t due to sscanf format string |
| int ItemsParsed = sscanf(Name.c_str(), "_ZN%s", NameBase.data()); |
| @@ -152,6 +238,7 @@ IceString GlobalContext::mangleName(const IceString &Name) const { |
| // somehow miscalculated the output buffer length, the output will |
| // be truncated, but it will be truncated consistently for all |
| // mangleName() calls on the same input string. |
| + incrementSubstitutions(NewName); |
| return NewName.data(); |
| } |
| @@ -172,8 +259,8 @@ IceString GlobalContext::mangleName(const IceString &Name) const { |
| // Transform _Z3barIabcExyz ==> _ZN6Prefix3barIabcEExyz |
| // ^^^^^^^^ ^ |
| // (splice in "N6Prefix", and insert "E" after "3barIabcE") |
| - llvm::SmallVector<char, 32> OrigName(Name.length()); |
| - llvm::SmallVector<char, 32> OrigSuffix(Name.length()); |
| + ManglerVector OrigName(Name.length()); |
| + ManglerVector OrigSuffix(Name.length()); |
| uint32_t ActualBaseLength = BaseLength; |
| if (NameBase[ActualBaseLength] == 'I') { |
| ++ActualBaseLength; |
| @@ -187,6 +274,7 @@ IceString GlobalContext::mangleName(const IceString &Name) const { |
| snprintf(NewName.data(), BufLen, "_ZN%u%s%u%sE%s", PrefixLength, |
| getTestPrefix().c_str(), BaseLength, OrigName.data(), |
| OrigSuffix.data()); |
| + incrementSubstitutions(NewName); |
| return NewName.data(); |
| } |