LLVM 20.0.0git
MicrosoftDemangle.h
Go to the documentation of this file.
1//===------------------------- MicrosoftDemangle.h --------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
10#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
11
13
14#include <cassert>
15#include <string_view>
16#include <utility>
17
18namespace llvm {
19namespace ms_demangle {
20// This memory allocator is extremely fast, but it doesn't call dtors
21// for allocated objects. That means you can't use STL containers
22// (such as std::vector) with this allocator. But it pays off --
23// the demangler is 3x faster with this allocator compared to one with
24// STL containers.
25constexpr size_t AllocUnit = 4096;
26
28 struct AllocatorNode {
29 uint8_t *Buf = nullptr;
30 size_t Used = 0;
31 size_t Capacity = 0;
32 AllocatorNode *Next = nullptr;
33 };
34
35 void addNode(size_t Capacity) {
36 AllocatorNode *NewHead = new AllocatorNode;
37 NewHead->Buf = new uint8_t[Capacity];
38 NewHead->Next = Head;
39 NewHead->Capacity = Capacity;
40 Head = NewHead;
41 NewHead->Used = 0;
42 }
43
44public:
45 ArenaAllocator() { addNode(AllocUnit); }
46
48 while (Head) {
49 assert(Head->Buf);
50 delete[] Head->Buf;
51 AllocatorNode *Next = Head->Next;
52 delete Head;
53 Head = Next;
54 }
55 }
56
57 // Delete the copy constructor and the copy assignment operator.
58 ArenaAllocator(const ArenaAllocator &) = delete;
60
61 char *allocUnalignedBuffer(size_t Size) {
62 assert(Head && Head->Buf);
63
64 uint8_t *P = Head->Buf + Head->Used;
65
66 Head->Used += Size;
67 if (Head->Used <= Head->Capacity)
68 return reinterpret_cast<char *>(P);
69
70 addNode(std::max(AllocUnit, Size));
71 Head->Used = Size;
72 return reinterpret_cast<char *>(Head->Buf);
73 }
74
75 template <typename T, typename... Args> T *allocArray(size_t Count) {
76 size_t Size = Count * sizeof(T);
77 assert(Head && Head->Buf);
78
79 size_t P = (size_t)Head->Buf + Head->Used;
80 uintptr_t AlignedP =
81 (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));
82 uint8_t *PP = (uint8_t *)AlignedP;
83 size_t Adjustment = AlignedP - P;
84
85 Head->Used += Size + Adjustment;
86 if (Head->Used <= Head->Capacity)
87 return new (PP) T[Count]();
88
89 addNode(std::max(AllocUnit, Size));
90 Head->Used = Size;
91 return new (Head->Buf) T[Count]();
92 }
93
94 template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {
95 constexpr size_t Size = sizeof(T);
96 assert(Head && Head->Buf);
97
98 size_t P = (size_t)Head->Buf + Head->Used;
99 uintptr_t AlignedP =
100 (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));
101 uint8_t *PP = (uint8_t *)AlignedP;
102 size_t Adjustment = AlignedP - P;
103
104 Head->Used += Size + Adjustment;
105 if (Head->Used <= Head->Capacity)
106 return new (PP) T(std::forward<Args>(ConstructorArgs)...);
107
108 static_assert(Size < AllocUnit);
109 addNode(AllocUnit);
110 Head->Used = Size;
111 return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);
112 }
113
114private:
115 AllocatorNode *Head = nullptr;
116};
117
119 static constexpr size_t Max = 10;
120
123
124 // The first 10 BackReferences in a mangled name can be back-referenced by
125 // special name @[0-9]. This is a storage for the first 10 BackReferences.
127 size_t NamesCount = 0;
128};
129
131
132enum NameBackrefBehavior : uint8_t {
133 NBB_None = 0, // don't save any names as backrefs.
134 NBB_Template = 1 << 0, // save template instanations.
135 NBB_Simple = 1 << 1, // save simple names.
136};
137
139
140// Demangler class takes the main role in demangling symbols.
141// It has a set of functions to parse mangled symbols into Type instances.
142// It also has a set of functions to convert Type instances to strings.
144public:
145 Demangler() = default;
146 virtual ~Demangler() = default;
147
148 // You are supposed to call parse() first and then check if error is true. If
149 // it is false, call output() to write the formatted name to the given stream.
150 SymbolNode *parse(std::string_view &MangledName);
151
152 TagTypeNode *parseTagUniqueName(std::string_view &MangledName);
153
154 // True if an error occurred.
155 bool Error = false;
156
157 void dumpBackReferences();
158
159private:
160 SymbolNode *demangleEncodedSymbol(std::string_view &MangledName,
162 SymbolNode *demangleDeclarator(std::string_view &MangledName);
163 SymbolNode *demangleMD5Name(std::string_view &MangledName);
164 SymbolNode *demangleTypeinfoName(std::string_view &MangledName);
165
166 VariableSymbolNode *demangleVariableEncoding(std::string_view &MangledName,
167 StorageClass SC);
168 FunctionSymbolNode *demangleFunctionEncoding(std::string_view &MangledName);
169
170 Qualifiers demanglePointerExtQualifiers(std::string_view &MangledName);
171
172 // Parser functions. This is a recursive-descent parser.
173 TypeNode *demangleType(std::string_view &MangledName,
175 PrimitiveTypeNode *demanglePrimitiveType(std::string_view &MangledName);
176 CustomTypeNode *demangleCustomType(std::string_view &MangledName);
177 TagTypeNode *demangleClassType(std::string_view &MangledName);
178 PointerTypeNode *demanglePointerType(std::string_view &MangledName);
179 PointerTypeNode *demangleMemberPointerType(std::string_view &MangledName);
180 FunctionSignatureNode *demangleFunctionType(std::string_view &MangledName,
181 bool HasThisQuals);
182
183 ArrayTypeNode *demangleArrayType(std::string_view &MangledName);
184
185 NodeArrayNode *demangleFunctionParameterList(std::string_view &MangledName,
186 bool &IsVariadic);
187 NodeArrayNode *demangleTemplateParameterList(std::string_view &MangledName);
188
189 std::pair<uint64_t, bool> demangleNumber(std::string_view &MangledName);
190 uint64_t demangleUnsigned(std::string_view &MangledName);
191 int64_t demangleSigned(std::string_view &MangledName);
192
193 void memorizeString(std::string_view s);
194 void memorizeIdentifier(IdentifierNode *Identifier);
195
196 /// Allocate a copy of \p Borrowed into memory that we own.
197 std::string_view copyString(std::string_view Borrowed);
198
200 demangleFullyQualifiedTypeName(std::string_view &MangledName);
202 demangleFullyQualifiedSymbolName(std::string_view &MangledName);
203
204 IdentifierNode *demangleUnqualifiedTypeName(std::string_view &MangledName,
205 bool Memorize);
206 IdentifierNode *demangleUnqualifiedSymbolName(std::string_view &MangledName,
208
209 QualifiedNameNode *demangleNameScopeChain(std::string_view &MangledName,
210 IdentifierNode *UnqualifiedName);
211 IdentifierNode *demangleNameScopePiece(std::string_view &MangledName);
212
213 NamedIdentifierNode *demangleBackRefName(std::string_view &MangledName);
215 demangleTemplateInstantiationName(std::string_view &MangledName,
218 translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group);
219 IdentifierNode *demangleFunctionIdentifierCode(std::string_view &MangledName);
221 demangleFunctionIdentifierCode(std::string_view &MangledName,
224 demangleStructorIdentifier(std::string_view &MangledName, bool IsDestructor);
226 demangleConversionOperatorIdentifier(std::string_view &MangledName);
228 demangleLiteralOperatorIdentifier(std::string_view &MangledName);
229
230 SymbolNode *demangleSpecialIntrinsic(std::string_view &MangledName);
232 demangleSpecialTableSymbolNode(std::string_view &MangledName,
235 demangleLocalStaticGuard(std::string_view &MangledName, bool IsThread);
236 VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena,
237 std::string_view &MangledName,
238 std::string_view VariableName);
240 demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,
241 std::string_view &MangledName);
242 FunctionSymbolNode *demangleInitFiniStub(std::string_view &MangledName,
243 bool IsDestructor);
244
245 NamedIdentifierNode *demangleSimpleName(std::string_view &MangledName,
246 bool Memorize);
248 demangleAnonymousNamespaceName(std::string_view &MangledName);
250 demangleLocallyScopedNamePiece(std::string_view &MangledName);
252 demangleStringLiteral(std::string_view &MangledName);
253 FunctionSymbolNode *demangleVcallThunkNode(std::string_view &MangledName);
254
255 std::string_view demangleSimpleString(std::string_view &MangledName,
256 bool Memorize);
257
258 FuncClass demangleFunctionClass(std::string_view &MangledName);
259 CallingConv demangleCallingConvention(std::string_view &MangledName);
260 StorageClass demangleVariableStorageClass(std::string_view &MangledName);
261 bool demangleThrowSpecification(std::string_view &MangledName);
262 wchar_t demangleWcharLiteral(std::string_view &MangledName);
263 uint8_t demangleCharLiteral(std::string_view &MangledName);
264
265 std::pair<Qualifiers, bool> demangleQualifiers(std::string_view &MangledName);
266
267 // Memory allocator.
268 ArenaAllocator Arena;
269
270 // A single type uses one global back-ref table for all function params.
271 // This means back-refs can even go "into" other types. Examples:
272 //
273 // // Second int* is a back-ref to first.
274 // void foo(int *, int*);
275 //
276 // // Second int* is not a back-ref to first (first is not a function param).
277 // int* foo(int*);
278 //
279 // // Second int* is a back-ref to first (ALL function types share the same
280 // // back-ref map.
281 // using F = void(*)(int*);
282 // F G(int *);
283 BackrefContext Backrefs;
284};
285
286} // namespace ms_demangle
287} // namespace llvm
288
289#endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
uint64_t Size
#define T
#define P(N)
#define CH(x, y, z)
Definition: SHA256.cpp:34
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
T * alloc(Args &&... ConstructorArgs)
char * allocUnalignedBuffer(size_t Size)
ArenaAllocator & operator=(const ArenaAllocator &)=delete
ArenaAllocator(const ArenaAllocator &)=delete
TagTypeNode * parseTagUniqueName(std::string_view &MangledName)
virtual ~Demangler()=default
constexpr size_t AllocUnit
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
NamedIdentifierNode * Names[Max]
Definition: regcomp.c:192