[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