LLDB mainline
DemangledNameInfo.cpp
Go to the documentation of this file.
1//===-- DemangledNameInfo.cpp ---------------------------------------------===//
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
10#include "lldb/Core/Mangled.h"
11
12using namespace llvm::itanium_demangle;
13
14namespace lldb_private {
15
16std::optional<DemangledNameInfo>
18 ConstString mangled_name = mangled.GetMangledName();
19 if (!mangled_name)
20 return std::nullopt;
21
22 bool cache_enabled = false;
23 {
24 auto state = m_state.LockShared();
25 cache_enabled = state->max_entries != 0;
26 auto it = state->infos.find(mangled_name);
27 if (it != state->infos.end())
28 return it->second;
29 }
30
31 // Demangle outside of the lock. Two threads asking for the same name at the
32 // same time just compute the same info twice, which is cheaper than making
33 // every other thread wait for one demangle to finish.
34 std::optional<DemangledNameInfo> info = mangled.ComputeDemangledInfo();
35
36 // Caching is disabled.
37 if (!cache_enabled)
38 return info;
39
40 auto state = m_state.Lock();
41 // Another thread might have cached this name while we were demangling.
42 if (state->infos.contains(mangled_name))
43 return info;
44
45 // Make room for the new entry by dropping a random one.
46 if (state->infos.size() >= state->max_entries)
47 state->EvictRandomEntry();
48
49 state->infos.insert({mangled_name, info});
50 state->mangled_names.push_back(mangled_name);
51 return info;
52}
53
55 assert(!mangled_names.empty() && "evicting from an empty cache");
56 std::uniform_int_distribution<size_t> dist(0, mangled_names.size() - 1);
57 size_t index = dist(rng);
58 infos.erase(mangled_names[index]);
59 mangled_names[index] = mangled_names.back();
60 mangled_names.pop_back();
61}
62
64 auto state = m_state.Lock();
65 state->infos.clear();
66 state->mangled_names.clear();
67}
68
70 return m_state.LockShared()->max_entries;
71}
72
74 return m_state.LockShared()->infos.size();
75}
76
77void DemangledNameInfoCache::SetMaxEntries(size_t max_entries) {
78 // This is called before every lookup, so avoid taking the exclusive lock
79 // when the limit didn't change.
80 if (GetMaxEntries() == max_entries)
81 return;
82
83 auto state = m_state.Lock();
84 state->max_entries = max_entries;
85 if (state->infos.size() > state->max_entries) {
86 state->infos.clear();
87 state->mangled_names.clear();
88 }
89}
90
93 return false;
94
95 if (isInsideTemplateArgs())
96 return false;
97
98 if (NameInfo.ArgumentsRange.first > 0)
99 return false;
100
101 return true;
102}
103
106 return false;
107
108 if (isInsideTemplateArgs())
109 return false;
110
111 if (NameInfo.ArgumentsRange.first == 0)
112 return false;
113
114 return true;
115}
116
118 if (!shouldTrack())
119 return;
120
121 NameInfo.BasenameRange.second = getCurrentPosition();
122}
123
125 if (!shouldTrack())
126 return;
127
128 NameInfo.ScopeRange.first = getCurrentPosition();
129}
130
132 if (!shouldTrack())
133 return;
134
135 NameInfo.ScopeRange.second = getCurrentPosition();
136}
137
139 if (!canFinalize())
140 return;
141
142 NameInfo.ArgumentsRange.second = getCurrentPosition();
143}
144
146 if (!canFinalize())
147 return;
148
149 NameInfo.QualifiersRange.first = getCurrentPosition();
150}
151
153 if (!canFinalize())
154 return;
155
156 NameInfo.QualifiersRange.second = getCurrentPosition();
157}
158
160 if (!shouldTrack())
161 return;
162
163 NameInfo.ArgumentsRange.first = getCurrentPosition();
164
165 // If nothing has set the end of the basename yet (for example when
166 // printing templates), then the beginning of the arguments is the end of
167 // the basename.
168 if (NameInfo.BasenameRange.second == 0)
169 NameInfo.BasenameRange.second = getCurrentPosition();
170
171 // There is something between the basename and the start of the function
172 // arguments. Assume those are template arguments (which *should* be true for
173 // C++ demangled names, but this assumption may change in the future, in
174 // which case this needs to be adjusted).
175 if (NameInfo.BasenameRange.second != NameInfo.ArgumentsRange.first)
176 NameInfo.TemplateArgumentsRange = {NameInfo.BasenameRange.second,
177 NameInfo.ArgumentsRange.first};
178
179 assert(!shouldTrack());
180 assert(canFinalize());
181}
182
184 if (!canFinalize())
185 return;
186
187 if (NameInfo.ScopeRange.first > NameInfo.ScopeRange.second)
188 NameInfo.ScopeRange.second = NameInfo.ScopeRange.first;
189 NameInfo.BasenameRange.first = NameInfo.ScopeRange.second;
190
191 // We call anything past the FunctionEncoding the "suffix".
192 // In practice this would be nodes like `DotSuffix` that wrap
193 // a FunctionEncoding.
194 NameInfo.SuffixRange.first = getCurrentPosition();
195}
196
200
204
206 switch (N.getKind()) {
207 case Node::KFunctionType:
208 printLeftImpl(static_cast<const FunctionType &>(N));
209 break;
210 case Node::KFunctionEncoding:
211 printLeftImpl(static_cast<const FunctionEncoding &>(N));
212 break;
213 case Node::KNestedName:
214 printLeftImpl(static_cast<const NestedName &>(N));
215 break;
216 case Node::KNameWithTemplateArgs:
217 printLeftImpl(static_cast<const NameWithTemplateArgs &>(N));
218 break;
219 default:
220 OutputBuffer::printLeft(N);
221 }
222
223 // Keep updating suffix until we reach the end.
224 NameInfo.SuffixRange.second = getCurrentPosition();
225}
226
228 switch (N.getKind()) {
229 case Node::KFunctionType:
230 printRightImpl(static_cast<const FunctionType &>(N));
231 break;
232 case Node::KFunctionEncoding:
233 printRightImpl(static_cast<const FunctionEncoding &>(N));
234 break;
235 default:
236 OutputBuffer::printRight(N);
237 }
238
239 // Keep updating suffix until we reach the end.
240 NameInfo.SuffixRange.second = getCurrentPosition();
241}
242
243void TrackingOutputBuffer::printLeftImpl(const FunctionType &N) {
244 auto Scoped = enterFunctionTypePrinting();
245 OutputBuffer::printLeft(N);
246}
247
248void TrackingOutputBuffer::printRightImpl(const FunctionType &N) {
249 auto Scoped = enterFunctionTypePrinting();
250 OutputBuffer::printRight(N);
251}
252
253void TrackingOutputBuffer::printLeftImpl(const FunctionEncoding &N) {
254 auto Scoped = enterFunctionTypePrinting();
255
256 const Node *Ret = N.getReturnType();
257 if (Ret) {
258 printLeft(*Ret);
259 if (!Ret->hasRHSComponent(*this))
260 *this += " ";
261 }
262
263 updateScopeStart();
264
265 N.getName()->print(*this);
266}
267
268void TrackingOutputBuffer::printRightImpl(const FunctionEncoding &N) {
269 auto Scoped = enterFunctionTypePrinting();
270 finalizeStart();
271
272 printOpen();
273 N.getParams().printWithComma(*this);
274 printClose();
275
276 finalizeArgumentEnd();
277
278 const Node *Ret = N.getReturnType();
279
280 if (Ret)
281 printRight(*Ret);
282
283 finalizeQualifiersStart();
284
285 auto CVQuals = N.getCVQuals();
286 auto RefQual = N.getRefQual();
287 auto *Attrs = N.getAttrs();
288 auto *Requires = N.getRequires();
289
290 if (CVQuals & QualConst)
291 *this += " const";
292 if (CVQuals & QualVolatile)
293 *this += " volatile";
294 if (CVQuals & QualRestrict)
295 *this += " restrict";
296 if (RefQual == FrefQualLValue)
297 *this += " &";
298 else if (RefQual == FrefQualRValue)
299 *this += " &&";
300 if (Attrs != nullptr)
301 Attrs->print(*this);
302 if (Requires != nullptr) {
303 *this += " requires ";
304 Requires->print(*this);
305 }
306
307 finalizeQualifiersEnd();
308 finalizeEnd();
309}
310
311void TrackingOutputBuffer::printLeftImpl(const NestedName &N) {
312 N.Qual->print(*this);
313 *this += "::";
314 updateScopeEnd();
315 N.Name->print(*this);
316 updateBasenameEnd();
317}
318
319void TrackingOutputBuffer::printLeftImpl(const NameWithTemplateArgs &N) {
320 N.Name->print(*this);
321 updateBasenameEnd();
322 N.TemplateArgs->print(*this);
323}
324
325} // namespace lldb_private
A uniqued constant string class.
Definition ConstString.h:40
void SetMaxEntries(size_t max_entries)
Changes the maximum number of entries. A limit of 0 disables the cache.
std::optional< DemangledNameInfo > Get(const Mangled &mangled)
Calculates the DemangledNameInfo and caches the result.
A class that handles mangled names.
Definition Mangled.h:34
std::optional< DemangledNameInfo > ComputeDemangledInfo() const
Compute the DemangledNameInfo of the demangled name.
Definition Mangled.cpp:226
ConstString GetMangledName() const
Mangled name get accessor.
Definition Mangled.h:170
A class that represents a running process on the host machine.
std::vector< ConstString > mangled_names
The mangled names.
llvm::DenseMap< ConstString, std::optional< DemangledNameInfo > > infos
Maps a ConstString to its DemangledNameInfo.
void EvictRandomEntry()
Drops a random entry from the cache.
void updateScopeStart()
If this object shouldTrack, then update the beginning of the scope range to the current OB position.
bool canFinalize() const
Helper used in the finalize APIs.
void printRightImpl(const llvm::itanium_demangle::FunctionType &N)
void printLeftImpl(const llvm::itanium_demangle::FunctionType &N)
bool isPrintingTopLevelFunctionType() const
Returns true if we're not printing any nested function types, just a FunctionEncoding in the Itanium ...
llvm::itanium_demangle::ScopedOverride< unsigned > enterFunctionTypePrinting()
Called whenever we start printing a function type in the Itanium mangling scheme.
void updateBasenameEnd()
If this object shouldTrack, then update the end of the basename range to the current OB position.
unsigned FunctionPrintingDepth
Incremented each time we start printing a function type node in the Itanium mangling scheme (e....
void printLeft(const llvm::itanium_demangle::Node &N) override
void finalizeArgumentEnd()
Helpers called to track beginning and end of the function arguments.
void updateScopeEnd()
If this object shouldTrack, then update the end of the scope range to the current OB position.
void printRight(const llvm::itanium_demangle::Node &N) override
bool shouldTrack() const
Returns true if the members of this object can be updated.
DemangledNameInfo NameInfo
Holds information about the demangled name that is being printed into this buffer.