[llvm] r338736 - [MS Demangler] Resolve back-references lazily.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 2 10:08:04 PDT 2018


Author: zturner
Date: Thu Aug  2 10:08:03 2018
New Revision: 338736

URL: http://llvm.org/viewvc/llvm-project?rev=338736&view=rev
Log:
[MS Demangler] Resolve back-references lazily.

We need to both record and resolve back-references lazily due to
not being able to know until a demangling is complete whether or
not a name should go into the back-reference table..  This patch
implements lazy resolution of back-references, but we still have
eager recording of back-references.  This will be fixed in a
subsequent patch.

Modified:
    llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp

Modified: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=338736&r1=338735&r2=338736&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Thu Aug  2 10:08:03 2018
@@ -209,6 +209,10 @@ enum class SymbolCategory { Function, Va
 
 namespace {
 
+struct NameResolver {
+  virtual StringView resolve(StringView S) = 0;
+};
+
 struct Type;
 struct Name;
 
@@ -246,15 +250,15 @@ struct Type {
   // Write the "first half" of a given type.  This is a static functions to
   // give the code a chance to do processing that is common to a subset of
   // subclasses
-  static void outputPre(OutputStream &OS, Type &Ty);
+  static void outputPre(OutputStream &OS, Type &Ty, NameResolver &Resolver);
 
   // Write the "second half" of a given type.  This is a static functions to
   // give the code a chance to do processing that is common to a subset of
   // subclasses
-  static void outputPost(OutputStream &OS, Type &Ty);
+  static void outputPost(OutputStream &OS, Type &Ty, NameResolver &Resolver);
 
-  virtual void outputPre(OutputStream &OS);
-  virtual void outputPost(OutputStream &OS);
+  virtual void outputPre(OutputStream &OS, NameResolver &Resolver);
+  virtual void outputPost(OutputStream &OS, NameResolver &Resolver);
 
   // Primitive type such as Int.
   PrimTy Prim = PrimTy::Unknown;
@@ -270,6 +274,7 @@ struct Name {
 
   bool IsTemplateInstantiation = false;
   bool IsOperator = false;
+  bool IsBackReference = false;
 
   // Template parameters. Only valid if Flags contains NF_TemplateInstantiation.
   TemplateParams *TParams = nullptr;
@@ -280,8 +285,8 @@ struct Name {
 
 struct PointerType : public Type {
   Type *clone(ArenaAllocator &Arena) const override;
-  void outputPre(OutputStream &OS) override;
-  void outputPost(OutputStream &OS) override;
+  void outputPre(OutputStream &OS, NameResolver &Resolver) override;
+  void outputPost(OutputStream &OS, NameResolver &Resolver) override;
 
   PointerAffinity Affinity;
 
@@ -292,8 +297,8 @@ struct PointerType : public Type {
 
 struct MemberPointerType : public Type {
   Type *clone(ArenaAllocator &Arena) const override;
-  void outputPre(OutputStream &OS) override;
-  void outputPost(OutputStream &OS) override;
+  void outputPre(OutputStream &OS, NameResolver &Resolver) override;
+  void outputPost(OutputStream &OS, NameResolver &Resolver) override;
 
   Name *MemberName = nullptr;
 
@@ -304,8 +309,8 @@ struct MemberPointerType : public Type {
 
 struct FunctionType : public Type {
   Type *clone(ArenaAllocator &Arena) const override;
-  void outputPre(OutputStream &OS) override;
-  void outputPost(OutputStream &OS) override;
+  void outputPre(OutputStream &OS, NameResolver &Resolver) override;
+  void outputPost(OutputStream &OS, NameResolver &Resolver) override;
 
   // True if this FunctionType instance is the Pointee of a PointerType or
   // MemberPointerType.
@@ -323,15 +328,15 @@ struct FunctionType : public Type {
 
 struct UdtType : public Type {
   Type *clone(ArenaAllocator &Arena) const override;
-  void outputPre(OutputStream &OS) override;
+  void outputPre(OutputStream &OS, NameResolver &Resolver) override;
 
   Name *UdtName = nullptr;
 };
 
 struct ArrayType : public Type {
   Type *clone(ArenaAllocator &Arena) const override;
-  void outputPre(OutputStream &OS) override;
-  void outputPost(OutputStream &OS) override;
+  void outputPre(OutputStream &OS, NameResolver &Resolver) override;
+  void outputPost(OutputStream &OS, NameResolver &Resolver) override;
 
   // Either NextDimension or ElementType will be valid.
   ArrayType *NextDimension = nullptr;
@@ -473,11 +478,9 @@ static bool startsWithLocalScopePattern(
   return true;
 }
 
-static void outputName(OutputStream &OS, const Name *TheName);
-
 // Write a function or template parameter list.
-static void outputParameterList(OutputStream &OS,
-                                const FunctionParams &Params) {
+static void outputParameterList(OutputStream &OS, const FunctionParams &Params,
+                                NameResolver &Resolver) {
   if (!Params.Current) {
     OS << "void";
     return;
@@ -485,8 +488,8 @@ static void outputParameterList(OutputSt
 
   const FunctionParams *Head = &Params;
   while (Head) {
-    Type::outputPre(OS, *Head->Current);
-    Type::outputPost(OS, *Head->Current);
+    Type::outputPre(OS, *Head->Current, Resolver);
+    Type::outputPost(OS, *Head->Current, Resolver);
 
     Head = Head->Next;
 
@@ -495,8 +498,11 @@ static void outputParameterList(OutputSt
   }
 }
 
-static void outputParameterList(OutputStream &OS,
-                                const TemplateParams &Params) {
+static void outputName(OutputStream &OS, const Name *TheName,
+                       NameResolver &Resolver);
+
+static void outputParameterList(OutputStream &OS, const TemplateParams &Params,
+                                NameResolver &Resolver) {
   if (!Params.ParamType && !Params.ParamName) {
     OS << "<>";
     return;
@@ -511,16 +517,16 @@ static void outputParameterList(OutputSt
     if (Head->ParamType && Head->ParamName) {
       // Function pointer.
       OS << "&";
-      Type::outputPre(OS, *Head->ParamType);
-      outputName(OS, Head->ParamName);
-      Type::outputPost(OS, *Head->ParamType);
+      Type::outputPre(OS, *Head->ParamType, Resolver);
+      outputName(OS, Head->ParamName, Resolver);
+      Type::outputPost(OS, *Head->ParamType, Resolver);
     } else if (Head->ParamType) {
       // simple type.
-      Type::outputPre(OS, *Head->ParamType);
-      Type::outputPost(OS, *Head->ParamType);
+      Type::outputPre(OS, *Head->ParamType, Resolver);
+      Type::outputPost(OS, *Head->ParamType, Resolver);
     } else {
       // Template alias.
-      outputName(OS, Head->ParamName);
+      outputName(OS, Head->ParamName, Resolver);
     }
 
     Head = Head->Next;
@@ -531,7 +537,20 @@ static void outputParameterList(OutputSt
   OS << ">";
 }
 
-static void outputName(OutputStream &OS, const Name *TheName) {
+static void outputNameComponent(OutputStream &OS, const Name &N,
+                                NameResolver &Resolver) {
+  StringView S = N.Str;
+
+  if (N.IsBackReference)
+    S = Resolver.resolve(N.Str);
+  OS << S;
+
+  if (N.IsTemplateInstantiation)
+    outputParameterList(OS, *N.TParams, Resolver);
+}
+
+static void outputName(OutputStream &OS, const Name *TheName,
+                       NameResolver &Resolver) {
   if (!TheName)
     return;
 
@@ -541,17 +560,13 @@ static void outputName(OutputStream &OS,
   // Print out namespaces or outer class BackReferences.
   for (; TheName->Next; TheName = TheName->Next) {
     Previous = TheName;
-    OS << TheName->Str;
-    if (TheName->IsTemplateInstantiation)
-      outputParameterList(OS, *TheName->TParams);
+    outputNameComponent(OS, *TheName, Resolver);
     OS << "::";
   }
 
   // Print out a regular name.
   if (!TheName->IsOperator) {
-    OS << TheName->Str;
-    if (TheName->IsTemplateInstantiation)
-      outputParameterList(OS, *TheName->TParams);
+    outputNameComponent(OS, *TheName, Resolver);
     return;
   }
 
@@ -560,16 +575,13 @@ static void outputName(OutputStream &OS,
     OS << "~";
 
   if (TheName->Str == "ctor" || TheName->Str == "dtor") {
-    OS << Previous->Str;
-    if (Previous->TParams)
-      outputParameterList(OS, *Previous->TParams);
+    outputNameComponent(OS, *Previous, Resolver);
     return;
   }
 
   // Print out an overloaded operator.
-  OS << "operator" << TheName->Str;
-  if (TheName->IsTemplateInstantiation)
-    outputParameterList(OS, *TheName->TParams);
+  OS << "operator";
+  outputNameComponent(OS, *TheName, Resolver);
 }
 
 namespace {
@@ -579,12 +591,12 @@ Type *Type::clone(ArenaAllocator &Arena)
 }
 
 // Write the "first half" of a given type.
-void Type::outputPre(OutputStream &OS, Type &Ty) {
+void Type::outputPre(OutputStream &OS, Type &Ty, NameResolver &Resolver) {
   // Function types require custom handling of const and static so we
   // handle them separately.  All other types use the same decoration
   // for these modifiers, so handle them here in common code.
   if (Ty.Prim == PrimTy::Function) {
-    Ty.outputPre(OS);
+    Ty.outputPre(OS, Resolver);
     return;
   }
 
@@ -596,7 +608,7 @@ void Type::outputPre(OutputStream &OS, T
   default:
     break;
   }
-  Ty.outputPre(OS);
+  Ty.outputPre(OS, Resolver);
 
   if (Ty.Quals & Q_Const) {
     outputSpaceIfNecessary(OS);
@@ -615,9 +627,11 @@ void Type::outputPre(OutputStream &OS, T
 }
 
 // Write the "second half" of a given type.
-void Type::outputPost(OutputStream &OS, Type &Ty) { Ty.outputPost(OS); }
+void Type::outputPost(OutputStream &OS, Type &Ty, NameResolver &Resolver) {
+  Ty.outputPost(OS, Resolver);
+}
 
-void Type::outputPre(OutputStream &OS) {
+void Type::outputPre(OutputStream &OS, NameResolver &Resolver) {
   switch (Prim) {
   case PrimTy::Void:
     OS << "void";
@@ -683,15 +697,15 @@ void Type::outputPre(OutputStream &OS) {
     assert(false && "Invalid primitive type!");
   }
 }
-void Type::outputPost(OutputStream &OS) {}
+void Type::outputPost(OutputStream &OS, NameResolver &Resolver) {}
 
 Type *PointerType::clone(ArenaAllocator &Arena) const {
   return Arena.alloc<PointerType>(*this);
 }
 
 static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity,
-                                   const Name *MemberName,
-                                   const Type *Pointee) {
+                                   const Name *MemberName, const Type *Pointee,
+                                   NameResolver &Resolver) {
   // "[]" and "()" (for function parameters) take precedence over "*",
   // so "int *x(int)" means "x is a function returning int *". We need
   // parentheses to supercede the default precedence. (e.g. we want to
@@ -707,7 +721,7 @@ static void outputPointerIndicator(Outpu
   }
 
   if (MemberName) {
-    outputName(OS, MemberName);
+    outputName(OS, MemberName, Resolver);
     OS << "::";
   }
 
@@ -719,38 +733,39 @@ static void outputPointerIndicator(Outpu
     OS << "&&";
 }
 
-void PointerType::outputPre(OutputStream &OS) {
-  Type::outputPre(OS, *Pointee);
+void PointerType::outputPre(OutputStream &OS, NameResolver &Resolver) {
+  Type::outputPre(OS, *Pointee, Resolver);
 
   outputSpaceIfNecessary(OS);
 
   if (Quals & Q_Unaligned)
     OS << "__unaligned ";
 
-  outputPointerIndicator(OS, Affinity, nullptr, Pointee);
+  outputPointerIndicator(OS, Affinity, nullptr, Pointee, Resolver);
 
   // FIXME: We should output this, but it requires updating lots of tests.
   // if (Ty.Quals & Q_Pointer64)
   //  OS << " __ptr64";
 }
 
-void PointerType::outputPost(OutputStream &OS) {
+void PointerType::outputPost(OutputStream &OS, NameResolver &Resolver) {
   if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array)
     OS << ")";
 
-  Type::outputPost(OS, *Pointee);
+  Type::outputPost(OS, *Pointee, Resolver);
 }
 
 Type *MemberPointerType::clone(ArenaAllocator &Arena) const {
   return Arena.alloc<MemberPointerType>(*this);
 }
 
-void MemberPointerType::outputPre(OutputStream &OS) {
-  Type::outputPre(OS, *Pointee);
+void MemberPointerType::outputPre(OutputStream &OS, NameResolver &Resolver) {
+  Type::outputPre(OS, *Pointee, Resolver);
 
   outputSpaceIfNecessary(OS);
 
-  outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee);
+  outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee,
+                         Resolver);
 
   // FIXME: We should output this, but it requires updating lots of tests.
   // if (Ty.Quals & Q_Pointer64)
@@ -759,25 +774,25 @@ void MemberPointerType::outputPre(Output
     OS << " __restrict";
 }
 
-void MemberPointerType::outputPost(OutputStream &OS) {
+void MemberPointerType::outputPost(OutputStream &OS, NameResolver &Resolver) {
   if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array)
     OS << ")";
 
-  Type::outputPost(OS, *Pointee);
+  Type::outputPost(OS, *Pointee, Resolver);
 }
 
 Type *FunctionType::clone(ArenaAllocator &Arena) const {
   return Arena.alloc<FunctionType>(*this);
 }
 
-void FunctionType::outputPre(OutputStream &OS) {
+void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) {
   if (!(FunctionClass & Global)) {
     if (FunctionClass & Static)
       OS << "static ";
   }
 
   if (ReturnType) {
-    Type::outputPre(OS, *ReturnType);
+    Type::outputPre(OS, *ReturnType, Resolver);
     OS << " ";
   }
 
@@ -788,9 +803,9 @@ void FunctionType::outputPre(OutputStrea
     outputCallingConvention(OS, CallConvention);
 }
 
-void FunctionType::outputPost(OutputStream &OS) {
+void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) {
   OS << "(";
-  outputParameterList(OS, Params);
+  outputParameterList(OS, Params, Resolver);
   OS << ")";
   if (Quals & Q_Const)
     OS << " const";
@@ -807,7 +822,7 @@ void FunctionType::outputPost(OutputStre
     OS << " &&";
 
   if (ReturnType)
-    Type::outputPost(OS, *ReturnType);
+    Type::outputPost(OS, *ReturnType, Resolver);
   return;
 }
 
@@ -815,7 +830,7 @@ Type *UdtType::clone(ArenaAllocator &Are
   return Arena.alloc<UdtType>(*this);
 }
 
-void UdtType::outputPre(OutputStream &OS) {
+void UdtType::outputPre(OutputStream &OS, NameResolver &Resolver) {
   switch (Prim) {
   case PrimTy::Class:
     OS << "class ";
@@ -833,24 +848,24 @@ void UdtType::outputPre(OutputStream &OS
     assert(false && "Not a udt type!");
   }
 
-  outputName(OS, UdtName);
+  outputName(OS, UdtName, Resolver);
 }
 
 Type *ArrayType::clone(ArenaAllocator &Arena) const {
   return Arena.alloc<ArrayType>(*this);
 }
 
-void ArrayType::outputPre(OutputStream &OS) {
-  Type::outputPre(OS, *ElementType);
+void ArrayType::outputPre(OutputStream &OS, NameResolver &Resolver) {
+  Type::outputPre(OS, *ElementType, Resolver);
 }
 
-void ArrayType::outputPost(OutputStream &OS) {
+void ArrayType::outputPost(OutputStream &OS, NameResolver &Resolver) {
   if (ArrayDimension > 0)
     OS << "[" << ArrayDimension << "]";
   if (NextDimension)
-    Type::outputPost(OS, *NextDimension);
+    Type::outputPost(OS, *NextDimension, Resolver);
   else if (ElementType)
-    Type::outputPost(OS, *ElementType);
+    Type::outputPost(OS, *ElementType, Resolver);
 }
 
 struct Symbol {
@@ -867,7 +882,7 @@ namespace {
 // Demangler class takes the main role in demangling symbols.
 // It has a set of functions to parse mangled symbols into Type instances.
 // It also has a set of functions to cnovert Type instances to strings.
-class Demangler {
+class Demangler : public NameResolver {
 public:
   Demangler() = default;
 
@@ -876,6 +891,8 @@ public:
   Symbol *parse(StringView &MangledName);
   void output(const Symbol *S, OutputStream &OS);
 
+  StringView resolve(StringView N) override;
+
   // True if an error occurred.
   bool Error = false;
 
@@ -1098,16 +1115,10 @@ void Demangler::memorizeString(StringVie
 
 Name *Demangler::demangleBackRefName(StringView &MangledName) {
   assert(startsWithDigit(MangledName));
-
-  size_t I = MangledName[0] - '0';
-  if (I >= BackRefCount) {
-    Error = true;
-    return nullptr;
-  }
-
-  MangledName = MangledName.dropFront();
   Name *Node = Arena.alloc<Name>();
-  Node->Str = BackReferences[I];
+  Node->IsBackReference = true;
+  Node->Str = {MangledName.begin(), 1};
+  MangledName = MangledName.dropFront();
   return Node;
 }
 
@@ -1128,7 +1139,7 @@ Name *Demangler::demangleTemplateInstant
   // Render this class template name into a string buffer so that we can
   // memorize it for the purpose of back-referencing.
   OutputStream OS = OutputStream::create(nullptr, nullptr, 1024);
-  outputName(OS, Node);
+  outputName(OS, Node, *this);
   OS << '\0';
   char *Name = OS.getBuffer();
 
@@ -2026,6 +2037,14 @@ Demangler::demangleTemplateParameterList
   return nullptr;
 }
 
+StringView Demangler::resolve(StringView N) {
+  assert(N.size() == 1 && isdigit(N[0]));
+  int Digit = N[0] - '0';
+  if (Digit >= BackRefCount)
+    return N;
+  return BackReferences[Digit];
+}
+
 void Demangler::output(const Symbol *S, OutputStream &OS) {
   // Converts an AST to a string.
   //
@@ -2044,9 +2063,9 @@ void Demangler::output(const Symbol *S,
   // the "first half" of type declaration, and outputPost() writes the
   // "second half". For example, outputPre() writes a return type for a
   // function and outputPost() writes an parameter list.
-  Type::outputPre(OS, *S->SymbolType);
-  outputName(OS, S->SymbolName);
-  Type::outputPost(OS, *S->SymbolType);
+  Type::outputPre(OS, *S->SymbolType, *this);
+  outputName(OS, S->SymbolName, *this);
+  Type::outputPost(OS, *S->SymbolType, *this);
 }
 
 void Demangler::dumpBackReferences() {
@@ -2059,8 +2078,8 @@ void Demangler::dumpBackReferences() {
     OS.setCurrentPosition(0);
 
     Type *T = FunctionParamBackRefs[I];
-    Type::outputPre(OS, *T);
-    Type::outputPost(OS, *T);
+    Type::outputPre(OS, *T, *this);
+    Type::outputPost(OS, *T, *this);
 
     std::printf("  [%d] - %*s\n", (int)I, (int)OS.getCurrentPosition(),
                 OS.getBuffer());




More information about the llvm-commits mailing list