Skip to content

Commit bf909ca

Browse files
authored
Merge pull request #22655 from eeckstein/stack-allocated-demangler
Make the demangler in the runtime use stack allocated memory.
2 parents b7daed7 + 80e86fb commit bf909ca

File tree

18 files changed

+492
-310
lines changed

18 files changed

+492
-310
lines changed

include/swift/Demangling/Demangle.h

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -142,32 +142,38 @@ class Node {
142142
friend class NodeFactory;
143143

144144
private:
145-
Kind NodeKind;
146145

147-
enum class PayloadKind : uint8_t {
148-
None, Text, Index
146+
struct NodeVector {
147+
NodePointer *Nodes;
148+
uint32_t Number = 0;
149+
uint32_t Capacity = 0;
149150
};
150-
PayloadKind NodePayloadKind;
151151

152152
union {
153-
llvm::StringRef TextPayload;
154-
IndexType IndexPayload;
153+
llvm::StringRef Text;
154+
IndexType Index;
155+
NodePointer InlineChildren[2];
156+
NodeVector Children;
155157
};
156158

157-
NodePointer *Children = nullptr;
158-
size_t NumChildren = 0;
159-
size_t ReservedChildren = 0;
159+
160+
Kind NodeKind;
161+
162+
enum class PayloadKind : uint8_t {
163+
None, Text, Index, OneChild, TwoChildren, ManyChildren
164+
};
165+
PayloadKind NodePayloadKind;
160166

161167
Node(Kind k)
162168
: NodeKind(k), NodePayloadKind(PayloadKind::None) {
163169
}
164170
Node(Kind k, llvm::StringRef t)
165171
: NodeKind(k), NodePayloadKind(PayloadKind::Text) {
166-
TextPayload = t;
172+
Text = t;
167173
}
168174
Node(Kind k, IndexType index)
169175
: NodeKind(k), NodePayloadKind(PayloadKind::Index) {
170-
IndexPayload = index;
176+
Index = index;
171177
}
172178
Node(const Node &) = delete;
173179
Node &operator=(const Node &) = delete;
@@ -178,37 +184,33 @@ class Node {
178184
bool hasText() const { return NodePayloadKind == PayloadKind::Text; }
179185
llvm::StringRef getText() const {
180186
assert(hasText());
181-
return TextPayload;
187+
return Text;
182188
}
183189

184190
bool hasIndex() const { return NodePayloadKind == PayloadKind::Index; }
185191
uint64_t getIndex() const {
186192
assert(hasIndex());
187-
return IndexPayload;
193+
return Index;
188194
}
189195

190-
using iterator = NodePointer *;
191-
using const_iterator = const NodePointer *;
192-
using size_type = size_t;
196+
using iterator = const NodePointer *;
197+
198+
size_t getNumChildren() const;
193199

194-
bool hasChildren() const { return NumChildren != 0; }
195-
size_t getNumChildren() const { return NumChildren; }
196-
iterator begin() { return Children; }
197-
iterator end() { return Children + NumChildren; }
198-
const_iterator begin() const { return Children; }
199-
const_iterator end() const { return Children + NumChildren; }
200+
bool hasChildren() const { return getNumChildren() != 0; }
201+
202+
iterator begin() const;
203+
204+
iterator end() const;
200205

201206
NodePointer getFirstChild() const {
202-
assert(NumChildren >= 1);
203-
return Children[0];
207+
return getChild(0);
204208
}
205209
NodePointer getChild(size_t index) const {
206-
assert(NumChildren > index);
207-
return Children[index];
210+
assert(getNumChildren() > index);
211+
return begin()[index];
208212
}
209213

210-
// inline void addChild(NodePointer Child, Context &Ctx);
211-
212214
// Only to be used by the demangler parsers.
213215
void addChild(NodePointer Child, NodeFactory &Factory);
214216
// Only to be used by the demangler parsers.
@@ -472,8 +474,10 @@ void mangleIdentifier(const char *data, size_t length,
472474

473475
/// Remangle a demangled parse tree.
474476
///
475-
/// This should always round-trip perfectly with demangleSymbolAsNode.
476-
std::string mangleNode(NodePointer root);
477+
/// If \p BorrowFrom is specified, the initial bump pointer memory is
478+
/// borrowed from the free memory of BorrowFrom.
479+
std::string mangleNode(NodePointer root,
480+
NodeFactory *BorrowFrom = nullptr);
477481

478482
using SymbolicResolver =
479483
llvm::function_ref<Demangle::NodePointer (SymbolicReferenceKind,
@@ -482,14 +486,17 @@ using SymbolicResolver =
482486
/// Remangle a demangled parse tree, using a callback to resolve
483487
/// symbolic references.
484488
///
485-
/// This should always round-trip perfectly with demangleSymbolAsNode.
486-
std::string mangleNode(NodePointer root, SymbolicResolver resolver);
489+
/// If \p BorrowFrom is specified, the initial bump pointer memory is
490+
/// borrowed from the free memory of BorrowFrom.
491+
std::string mangleNode(NodePointer root, SymbolicResolver resolver,
492+
NodeFactory *BorrowFrom = nullptr);
487493

488494
/// Remangle in the old mangling scheme.
489495
///
490-
/// This is only used for objc-runtime names and should be removed as soon as
491-
/// we switch to the new mangling for those names as well.
492-
std::string mangleNodeOld(NodePointer root);
496+
/// This is only used for objc-runtime names.
497+
/// If \p BorrowFrom is specified, the initial bump pointer memory is
498+
/// borrowed from the free memory of BorrowFrom.
499+
std::string mangleNodeOld(NodePointer root, NodeFactory *BorrowFrom = nullptr);
493500

494501
/// Transform the node structure to a string.
495502
///

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ NODE(FullTypeMetadata)
8888
CONTEXT_NODE(Function)
8989
NODE(FunctionSignatureSpecialization)
9090
NODE(FunctionSignatureSpecializationParam)
91+
NODE(FunctionSignatureSpecializationReturn)
9192
NODE(FunctionSignatureSpecializationParamKind)
9293
NODE(FunctionSignatureSpecializationParamPayload)
9394
NODE(FunctionType)

include/swift/Demangling/Demangler.h

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,31 +69,81 @@ class NodeFactory {
6969
}
7070

7171
static void freeSlabs(Slab *slab);
72-
72+
73+
/// If not null, the NodeFactory from which this factory borrowed free memory.
74+
NodeFactory *BorrowedFrom = nullptr;
75+
76+
/// True if some other NodeFactory borrowed free memory from this factory.
77+
bool isBorrowed = false;
78+
79+
#ifdef NODE_FACTORY_DEBUGGING
80+
size_t allocatedMemory = 0;
81+
static int nestingLevel;
82+
std::string indent() { return std::string(nestingLevel * 2, ' '); }
83+
#endif
84+
7385
public:
7486

7587
NodeFactory() {
7688
#ifdef NODE_FACTORY_DEBUGGING
77-
std::cerr << "## New NodeFactory " << this << "\n";
89+
std::cerr << indent() << "## New NodeFactory\n";
90+
nestingLevel++;
7891
#endif
7992
}
80-
93+
94+
/// Provide pre-allocated memory, e.g. memory on the stack.
95+
///
96+
/// Only if this memory overflows, the factory begins to malloc.
97+
void providePreallocatedMemory(char *Memory, size_t Size) {
98+
#ifdef NODE_FACTORY_DEBUGGING
99+
std::cerr << indent() << "++ provide preallocated memory, size = "
100+
<< Size << '\n';
101+
#endif
102+
assert(!CurPtr && !End && !CurrentSlab);
103+
CurPtr = Memory;
104+
End = CurPtr + Size;
105+
}
106+
107+
/// Borrow free memory from another factory \p BorrowFrom.
108+
///
109+
/// While this factory is alive, no allocations can be done in the
110+
/// \p BorrowFrom factory.
111+
void providePreallocatedMemory(NodeFactory &BorrowFrom) {
112+
assert(!CurPtr && !End && !CurrentSlab);
113+
assert(!BorrowFrom.isBorrowed && !BorrowedFrom);
114+
BorrowFrom.isBorrowed = true;
115+
BorrowedFrom = &BorrowFrom;
116+
CurPtr = BorrowFrom.CurPtr;
117+
End = BorrowFrom.End;
118+
#ifdef NODE_FACTORY_DEBUGGING
119+
std::cerr << indent() << "++ borrow memory, size = "
120+
<< (End - CurPtr) << '\n';
121+
#endif
122+
}
123+
81124
virtual ~NodeFactory() {
82125
freeSlabs(CurrentSlab);
83126
#ifdef NODE_FACTORY_DEBUGGING
84-
std::cerr << "Delete NodeFactory " << this << "\n";
127+
nestingLevel--;
128+
std::cerr << indent() << "## Delete NodeFactory: allocated memory = "
129+
<< allocatedMemory << '\n';
85130
#endif
131+
if (BorrowedFrom) {
132+
BorrowedFrom->isBorrowed = false;
133+
}
86134
}
87135

88136
virtual void clear();
89137

90138
/// Allocates an object of type T or an array of objects of type T.
91139
template<typename T> T *Allocate(size_t NumObjects = 1) {
140+
assert(!isBorrowed);
92141
size_t ObjectSize = NumObjects * sizeof(T);
93142
CurPtr = align(CurPtr, alignof(T));
94143
#ifdef NODE_FACTORY_DEBUGGING
95-
std::cerr << " alloc " << ObjectSize << ", CurPtr = "
144+
std::cerr << indent() << "alloc " << ObjectSize << ", CurPtr = "
96145
<< (void *)CurPtr << "\n";
146+
allocatedMemory += ObjectSize;
97147
#endif
98148

99149
// Do we have enough space in the current slab?
@@ -113,7 +163,7 @@ class NodeFactory {
113163
End = (char *)newSlab + AllocSize;
114164
assert(CurPtr + ObjectSize <= End);
115165
#ifdef NODE_FACTORY_DEBUGGING
116-
std::cerr << " ** new slab " << newSlab << ", allocsize = "
166+
std::cerr << indent() << "** new slab " << newSlab << ", allocsize = "
117167
<< AllocSize << ", CurPtr = " << (void *)CurPtr
118168
<< ", End = " << (void *)End << "\n";
119169
#endif
@@ -132,14 +182,15 @@ class NodeFactory {
132182
/// new memory address.
133183
/// The \p Capacity is enlarged at least by \p MinGrowth, but can also be
134184
/// enlarged by a bigger value.
135-
template<typename T> void Reallocate(T *&Objects, size_t &Capacity,
185+
template<typename T> void Reallocate(T *&Objects, uint32_t &Capacity,
136186
size_t MinGrowth) {
187+
assert(!isBorrowed);
137188
size_t OldAllocSize = Capacity * sizeof(T);
138189
size_t AdditionalAlloc = MinGrowth * sizeof(T);
139190

140191
#ifdef NODE_FACTORY_DEBUGGING
141-
std::cerr << " realloc " << Objects << ", num = " << NumObjects
142-
<< " (size = " << OldAllocSize << "), Growth = " << Growth
192+
std::cerr << indent() << "realloc: capacity = " << Capacity
193+
<< " (size = " << OldAllocSize << "), growth = " << MinGrowth
143194
<< " (size = " << AdditionalAlloc << ")\n";
144195
#endif
145196
if ((char *)Objects + OldAllocSize == CurPtr
@@ -149,7 +200,8 @@ class NodeFactory {
149200
CurPtr += AdditionalAlloc;
150201
Capacity += MinGrowth;
151202
#ifdef NODE_FACTORY_DEBUGGING
152-
std::cerr << " ** can grow: CurPtr = " << (void *)CurPtr << "\n";
203+
std::cerr << indent() << "** can grow: " << (void *)CurPtr << '\n';
204+
allocatedMemory += AdditionalAlloc;
153205
#endif
154206
return;
155207
}
@@ -203,8 +255,8 @@ template<typename T> class Vector {
203255

204256
protected:
205257
T *Elems = nullptr;
206-
size_t NumElems = 0;
207-
size_t Capacity = 0;
258+
uint32_t NumElems = 0;
259+
uint32_t Capacity = 0;
208260

209261
public:
210262
using iterator = T *;
@@ -469,7 +521,7 @@ class Demangler : public NodeFactory {
469521
NodePointer demangleThunkOrSpecialization();
470522
NodePointer demangleGenericSpecialization(Node::Kind SpecKind);
471523
NodePointer demangleFunctionSpecialization();
472-
NodePointer demangleFuncSpecParam(Node::IndexType ParamIdx);
524+
NodePointer demangleFuncSpecParam(Node::Kind Kind);
473525
NodePointer addFuncSpecParamNumber(NodePointer Param,
474526
FunctionSigSpecializationParamKind Kind);
475527

@@ -536,7 +588,19 @@ class Demangler : public NodeFactory {
536588
/// Demangler or with a call of clear().
537589
NodePointer demangleType(StringRef MangledName);
538590
};
539-
591+
592+
/// A demangler which uses stack space for its initial memory.
593+
///
594+
/// The \p Size paramter specifies the size of the stack space.
595+
template <size_t Size> class StackAllocatedDemangler : public Demangler {
596+
char StackSpace[Size];
597+
598+
public:
599+
StackAllocatedDemangler() {
600+
providePreallocatedMemory(StackSpace, Size);
601+
}
602+
};
603+
540604
NodePointer demangleOldSymbolAsNode(StringRef MangledName,
541605
NodeFactory &Factory);
542606
} // end namespace Demangle

include/swift/Demangling/TypeDecoder.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -676,21 +676,21 @@ class TypeDecoder {
676676
auto base = decodeMangledType(Node->getChild(0));
677677
if (!base)
678678
return BuiltType();
679-
auto member = Node->getChild(1)->getText();
680679
auto assocTypeChild = Node->getChild(1);
681-
if (assocTypeChild->getNumChildren() < 1)
680+
auto member = assocTypeChild->getFirstChild()->getText();
681+
if (assocTypeChild->getNumChildren() < 2)
682682
return Builder.createDependentMemberType(member, base);
683683

684-
auto protocol = decodeMangledProtocolType(assocTypeChild->getChild(0));
684+
auto protocol = decodeMangledProtocolType(assocTypeChild->getChild(1));
685685
if (!protocol)
686686
return BuiltType();
687687
return Builder.createDependentMemberType(member, base, protocol);
688688
}
689689
case NodeKind::DependentAssociatedTypeRef: {
690-
if (Node->getNumChildren() < 1)
690+
if (Node->getNumChildren() < 2)
691691
return BuiltType();
692692

693-
return decodeMangledType(Node->getChild(0));
693+
return decodeMangledType(Node->getChild(1));
694694
}
695695
case NodeKind::Unowned: {
696696
if (Node->getNumChildren() < 1)

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,12 @@ class TypeRefBuilder {
210210

211211
Optional<std::string>
212212
createTypeDecl(Node *node, bool &typeAlias) {
213-
return Demangle::mangleNode(node);
213+
return Demangle::mangleNode(node, &Dem);
214214
}
215215

216216
BuiltProtocolDecl
217217
createProtocolDecl(Node *node) {
218-
return std::make_pair(Demangle::mangleNode(node), false);
218+
return std::make_pair(Demangle::mangleNode(node, &Dem), false);
219219
}
220220

221221
BuiltProtocolDecl

include/swift/Remote/MetadataReader.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,9 +2109,10 @@ class MetadataReader {
21092109
}
21102110

21112111
if (importInfo && !importInfo->RelatedEntityName.empty()) {
2112-
auto relatedNode =
2113-
dem.createNode(Node::Kind::RelatedEntityDeclName,
2114-
std::move(importInfo->RelatedEntityName));
2112+
auto kindNode = dem.createNode(Node::Kind::Identifier,
2113+
std::move(importInfo->RelatedEntityName));
2114+
auto relatedNode = dem.createNode(Node::Kind::RelatedEntityDeclName);
2115+
relatedNode->addChild(kindNode, dem);
21152116
relatedNode->addChild(nameNode, dem);
21162117
nameNode = relatedNode;
21172118
}

lib/AST/ASTDemangler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,8 +820,8 @@ ASTBuilder::findDeclContext(NodePointer node) {
820820

821821
} else if (declNameNode->getKind() ==
822822
Demangle::Node::Kind::RelatedEntityDeclName) {
823-
name = declNameNode->getChild(0)->getText();
824-
relatedEntityKind = declNameNode->getText();
823+
name = declNameNode->getChild(1)->getText();
824+
relatedEntityKind = declNameNode->getFirstChild()->getText();
825825

826826
// Ignore any other decl-name productions for now.
827827
} else {

0 commit comments

Comments
 (0)