Skip to content

Commit f220a3b

Browse files
committed
Demangler: further speed improvements.
Avoid using std::string and std::vector in the demangler. Instead use vectors/strings with storage allocated by the NodeFactory’s bump pointer allocator. This brings another 35% speedup. Especially in the case the Demangle::Context is not reused for subsequent demanglings.
1 parent 3456d04 commit f220a3b

File tree

3 files changed

+208
-99
lines changed

3 files changed

+208
-99
lines changed

include/swift/Basic/Demangle.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ class Node {
207207

208208
// Only to be used by the demangler parsers.
209209
void addChild(NodePointer Child, NodeFactory &Factory);
210+
211+
// Reverses the order of children.
212+
void reverseChildren(size_t StartingAt = 0);
210213
};
211214

212215
/// Returns true if the mangledName starts with the swift mangling prefix.

include/swift/Basic/Demangler.h

Lines changed: 106 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ using llvm::StringRef;
3535
namespace swift {
3636
namespace Demangle {
3737

38+
class CharVector;
39+
3840
/// The allocator for demangling nodes and other demangling-internal stuff.
3941
///
4042
/// It implements a simple bump-pointer allocator.
@@ -77,15 +79,15 @@ class NodeFactory {
7779
#endif
7880
}
7981

80-
~NodeFactory() {
82+
virtual ~NodeFactory() {
8183
freeSlabs(CurrentSlab);
8284
#ifdef NODE_FACTORY_DEBUGGING
8385
std::cerr << "Delete NodeFactory " << this << "\n";
8486
#endif
8587
}
8688

87-
void clear();
88-
89+
virtual void clear();
90+
8991
/// Allocates an object of type T or an array of objects of type T.
9092
template<typename T> T *Allocate(size_t NumObjects = 1) {
9193
size_t ObjectSize = NumObjects * sizeof(T);
@@ -173,13 +175,105 @@ class NodeFactory {
173175
/// The \p Text string is copied.
174176
NodePointer createNode(Node::Kind K, llvm::StringRef Text);
175177

178+
/// Creates a node of kind \p K with a \p Text payload.
179+
///
180+
/// The \p Text string is already allocted with the Factory and therefore
181+
/// it is _not_ copied.
182+
NodePointer createNode(Node::Kind K, const CharVector &Text);
183+
176184
/// Creates a node of kind \p K with a \p Text payload, which must be a C
177185
/// string literal.
178186
///
179187
/// The \p Text string is _not_ copied.
180188
NodePointer createNode(Node::Kind K, const char *Text);
181189
};
182190

191+
/// A vector with a storage managed by a NodeFactory.
192+
///
193+
/// This Vector class only provides the minimal functionality needed by the
194+
/// Demangler.
195+
template<typename T> class Vector {
196+
197+
protected:
198+
T *Elems = nullptr;
199+
size_t NumElems = 0;
200+
size_t Capacity = 0;
201+
202+
public:
203+
204+
typedef T *iterator;
205+
206+
Vector() { }
207+
208+
/// Construct a vector with an inital capacity.
209+
explicit Vector(NodeFactory &Factory, size_t InitialCapacity) {
210+
init(Factory, InitialCapacity);
211+
}
212+
213+
/// Clears the content and re-allocates the buffer with an initial capacity.
214+
void init(NodeFactory &Factory, size_t InitialCapacity) {
215+
Elems = Factory.Allocate<T>(InitialCapacity);
216+
NumElems = 0;
217+
Capacity = InitialCapacity;
218+
}
219+
220+
void free() {
221+
Capacity = 0;
222+
Elems = 0;
223+
}
224+
225+
iterator begin() { return Elems; }
226+
iterator end() { return Elems + NumElems; }
227+
228+
T &operator[](size_t Idx) {
229+
assert(Idx < NumElems);
230+
return Elems[Idx];
231+
}
232+
233+
const T &operator[](size_t Idx) const {
234+
assert(Idx < NumElems);
235+
return Elems[Idx];
236+
}
237+
238+
size_t size() const { return NumElems; }
239+
240+
bool empty() const { return NumElems == 0; }
241+
242+
T &back() { return (*this)[NumElems - 1]; }
243+
244+
void push_back(const T &NewElem, NodeFactory &Factory) {
245+
if (NumElems >= Capacity)
246+
Factory.Reallocate(Elems, Capacity, /*Growth*/ 1);
247+
assert(NumElems < Capacity);
248+
Elems[NumElems++] = NewElem;
249+
}
250+
251+
T pop_back_val() {
252+
if (empty())
253+
return T();
254+
T Val = (*this)[NumElems - 1];
255+
NumElems--;
256+
return Val;
257+
}
258+
};
259+
260+
/// A vector of chars (a string) with a storage managed by a NodeFactory.
261+
///
262+
/// This CharVector class only provides the minimal functionality needed by the
263+
/// Demangler.
264+
class CharVector : public Vector<char> {
265+
public:
266+
// Append another string.
267+
void append(StringRef Rhs, NodeFactory &Factory);
268+
269+
// Append an integer as readable number.
270+
void append(int Number, NodeFactory &Factory);
271+
272+
StringRef str() const {
273+
return StringRef(Elems, NumElems);
274+
}
275+
};
276+
183277
/// The demangler.
184278
///
185279
/// It de-mangles a string and it also ownes the returned node-tree. This means
@@ -194,22 +288,14 @@ class Demangler : public NodeFactory {
194288
size_t Pos;
195289
};
196290

197-
std::vector<NodeWithPos> NodeStack;
198-
std::vector<NodePointer> Substitutions;
199-
std::vector<unsigned> PendingSubstitutions;
291+
Vector<NodeWithPos> NodeStack;
292+
Vector<NodePointer> Substitutions;
293+
Vector<unsigned> PendingSubstitutions;
200294

201295
static const int MaxNumWords = 26;
202296
StringRef Words[MaxNumWords];
203297
int NumWords = 0;
204298

205-
static NodePointer pop_back_val(std::vector<NodePointer> &NodeVector) {
206-
if (NodeVector.empty())
207-
return nullptr;
208-
NodePointer Val = NodeVector.back();
209-
NodeVector.pop_back();
210-
return Val;
211-
}
212-
213299
bool nextIf(StringRef str) {
214300
if (!Text.substr(Pos).startswith(str)) return false;
215301
Pos += str.size();
@@ -241,16 +327,11 @@ class Demangler : public NodeFactory {
241327
}
242328

243329
void pushNode(NodePointer Nd) {
244-
NodeStack.push_back({ Nd, Pos });
330+
NodeStack.push_back({ Nd, Pos }, *this);
245331
}
246332

247333
NodePointer popNode() {
248-
if (!NodeStack.empty()) {
249-
NodePointer Val = NodeStack.back().Node;
250-
NodeStack.pop_back();
251-
return Val;
252-
}
253-
return nullptr;
334+
return NodeStack.pop_back_val().Node;
254335
}
255336

256337
NodePointer popNode(Node::Kind kind) {
@@ -279,7 +360,7 @@ class Demangler : public NodeFactory {
279360

280361
void addSubstitution(NodePointer Nd) {
281362
if (Nd)
282-
Substitutions.push_back(Nd);
363+
Substitutions.push_back(Nd, *this);
283364
}
284365

285366
NodePointer addChild(NodePointer Parent, NodePointer Child);
@@ -326,7 +407,7 @@ class Demangler : public NodeFactory {
326407
NodePointer popProtocol();
327408
NodePointer demangleBoundGenericType();
328409
NodePointer demangleBoundGenericArgs(NodePointer nominalType,
329-
const std::vector<NodePointer> &TypeLists,
410+
const Vector<NodePointer> &TypeLists,
330411
size_t TypeListIdx);
331412
NodePointer demangleInitializer();
332413
NodePointer demangleImplParamConvention();
@@ -367,6 +448,8 @@ class Demangler : public NodeFactory {
367448

368449
public:
369450
Demangler() {}
451+
452+
void clear() override;
370453

371454
/// Demangle the given symbol and return the parse tree.
372455
///

0 commit comments

Comments
 (0)