Skip to content

Commit 6108c88

Browse files
authored
[Syntax] Use TrailingObjects for SyntaxData (#14301)
This should optimize memory usage for SyntaxData.
1 parent 77992d3 commit 6108c88

File tree

6 files changed

+61
-46
lines changed

6 files changed

+61
-46
lines changed

Diff for: include/swift/Syntax/RawSyntax.h

+6
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,12 @@ class RawSyntax final
397397
return {getTrailingObjects<RC<RawSyntax>>(), Bits.NumChildren};
398398
}
399399

400+
size_t getNumChildren() const {
401+
if (isToken())
402+
return 0;
403+
return Bits.NumChildren;
404+
}
405+
400406
/// Get a child based on a particular node's "Cursor", indicating
401407
/// the position of the terms in the production of the Swift grammar.
402408
const RC<RawSyntax> &getChild(CursorIndex Index) const {

Diff for: include/swift/Syntax/SyntaxData.h

+47-35
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,13 @@ namespace syntax {
5757
/// This is only for holding a strong reference to the RawSyntax, a weak
5858
/// reference to the parent, and, in subclasses, lazily created strong
5959
/// references to non-terminal child nodes.
60-
class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
61-
using RootDataPair = std::pair<RC<SyntaxData>, RC<SyntaxData>>;
60+
class SyntaxData final
61+
: public llvm::ThreadSafeRefCountedBase<SyntaxData>,
62+
private llvm::TrailingObjects<SyntaxData, AtomicCache<SyntaxData>> {
63+
friend TrailingObjects;
6264

63-
llvm::SmallVector<AtomicCache<SyntaxData>, 10> Children;
65+
using RootDataPair = std::pair<RC<SyntaxData>, RC<SyntaxData>>;
6466

65-
public:
6667
/// The shared raw syntax representing this syntax data node.
6768
const RC<RawSyntax> Raw;
6869

@@ -77,18 +78,16 @@ class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
7778
/// If there is no parent, this is 0.
7879
const CursorIndex IndexInParent;
7980

81+
size_t numTrailingObjects(OverloadToken<AtomicCache<SyntaxData>>) const {
82+
return Raw->getNumChildren();
83+
}
84+
8085
SyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
8186
CursorIndex IndexInParent = 0)
8287
: Raw(Raw), Parent(Parent), IndexInParent(IndexInParent) {
83-
Children.resize(Raw ? Raw->getLayout().size() : 0);
84-
}
85-
86-
/// Constructs a SyntaxNode by replacing `self` and recursively building
87-
/// the parent chain up to the root.
88-
template <typename SyntaxNode>
89-
SyntaxNode replaceSelf(const RC<RawSyntax> NewRaw) const {
90-
auto NewRootAndData = replaceSelf(NewRaw);
91-
return { NewRootAndData.first, NewRootAndData.second.get() };
88+
auto *I = getTrailingObjects<AtomicCache<SyntaxData>>();
89+
for (auto *E = I + getNumChildren(); I != E; ++I)
90+
::new (static_cast<void *>(I)) AtomicCache<SyntaxData>();
9291
}
9392

9493
/// With a new RawSyntax node, create a new node from this one and
@@ -97,8 +96,7 @@ class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
9796
/// DO NOT expose this as public API.
9897
RootDataPair replaceSelf(const RC<RawSyntax> NewRaw) const {
9998
if (hasParent()) {
100-
auto NewRootAndParent =
101-
getParent().getValue()->replaceChild(NewRaw, IndexInParent);
99+
auto NewRootAndParent = Parent->replaceChild(NewRaw, IndexInParent);
102100
auto NewMe = NewRootAndParent.second->getChild(IndexInParent);
103101
return { NewRootAndParent.first, NewMe.get() };
104102
} else {
@@ -116,6 +114,35 @@ class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
116114
return nullptr;
117115
}
118116

117+
/// Replace a child in the raw syntax and recursively rebuild the
118+
/// parental chain up to the root.
119+
///
120+
/// DO NOT expose this as public API.
121+
template <typename CursorType>
122+
RootDataPair replaceChild(const RC<RawSyntax> RawChild,
123+
CursorType ChildCursor) const {
124+
auto NewRaw = Raw->replaceChild(ChildCursor, RawChild);
125+
return replaceSelf(NewRaw);
126+
}
127+
128+
ArrayRef<AtomicCache<SyntaxData>> getChildren() const {
129+
return {getTrailingObjects<AtomicCache<SyntaxData>>(), getNumChildren()};
130+
}
131+
132+
public:
133+
~SyntaxData() {
134+
for (auto &I : getChildren())
135+
I.~AtomicCache<SyntaxData>();
136+
}
137+
138+
/// Constructs a SyntaxNode by replacing `self` and recursively building
139+
/// the parent chain up to the root.
140+
template <typename SyntaxNode>
141+
SyntaxNode replaceSelf(const RC<RawSyntax> NewRaw) const {
142+
auto NewRootAndData = replaceSelf(NewRaw);
143+
return { NewRootAndData.first, NewRootAndData.second.get() };
144+
}
145+
119146
/// Replace a child in the raw syntax and recursively rebuild the
120147
/// parental chain up to the root.
121148
///
@@ -130,18 +157,6 @@ class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
130157
};
131158
}
132159

133-
/// Replace a child in the raw syntax and recursively rebuild the
134-
/// parental chain up to the root.
135-
///
136-
/// DO NOT expose this as public API.
137-
template <typename CursorType>
138-
RootDataPair replaceChild(const RC<RawSyntax> RawChild,
139-
CursorType ChildCursor) const {
140-
auto NewRaw = Raw->replaceChild(ChildCursor, RawChild);
141-
return replaceSelf(NewRaw);
142-
}
143-
144-
public:
145160

146161
static RC<SyntaxData> make(RC<RawSyntax> Raw,
147162
const SyntaxData *Parent = nullptr,
@@ -158,11 +173,8 @@ class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
158173
}
159174

160175
/// Return the parent syntax if there is one.
161-
llvm::Optional<const SyntaxData *> getParent() const {
162-
if (Parent != nullptr) {
163-
return Parent;
164-
}
165-
return llvm::None;
176+
const SyntaxData * getParent() const {
177+
return Parent;
166178
}
167179

168180
/// Returns true if this syntax node has a parent.
@@ -218,7 +230,7 @@ class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
218230
RC<SyntaxData> getChild(size_t Index) const {
219231
if (!getRaw()->getChild(Index))
220232
return nullptr;
221-
return Children[Index].getOrCreate([&]() {
233+
return getChildren()[Index].getOrCreate([&]() {
222234
return realizeSyntaxNode(Index);
223235
});
224236
}
@@ -262,8 +274,8 @@ namespace llvm {
262274
}
263275
static unsigned getHashValue(const RCSD Value) {
264276
unsigned H = 0;
265-
H ^= DenseMapInfo<uintptr_t>::getHashValue(reinterpret_cast<const uintptr_t>(Value->Raw.get()));
266-
H ^= DenseMapInfo<uintptr_t>::getHashValue(reinterpret_cast<const uintptr_t>(Value->Parent));
277+
H ^= DenseMapInfo<uintptr_t>::getHashValue(reinterpret_cast<const uintptr_t>(Value->getRaw().get()));
278+
H ^= DenseMapInfo<uintptr_t>::getHashValue(reinterpret_cast<const uintptr_t>(Value->getParent()));
267279
H ^= DenseMapInfo<swift::syntax::CursorIndex>::getHashValue(Value->getIndexInParent());
268280
return H;
269281
}

Diff for: lib/Syntax/Syntax.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ bool Syntax::isMissing() const {
7575
}
7676

7777
llvm::Optional<Syntax> Syntax::getParent() const {
78-
auto ParentData = getData().Parent;
79-
if (ParentData == nullptr) return llvm::None;
78+
auto ParentData = getData().getParent();
79+
if (!ParentData) return llvm::None;
8080
return llvm::Optional<Syntax> {
8181
Syntax { Root, ParentData }
8282
};

Diff for: lib/Syntax/SyntaxData.cpp

+4-7
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,17 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "swift/Syntax/UnknownSyntax.h"
14-
#include "llvm/Support/ErrorHandling.h"
13+
#include "swift/Syntax/SyntaxData.h"
1514

1615
using namespace swift;
1716
using namespace swift::syntax;
1817

1918
RC<SyntaxData> SyntaxData::make(RC<RawSyntax> Raw,
2019
const SyntaxData *Parent,
2120
CursorIndex IndexInParent) {
22-
if (!Raw)
23-
return nullptr;
24-
return RC<SyntaxData> {
25-
new SyntaxData(Raw, Parent, IndexInParent)
26-
};
21+
auto size = totalSizeToAlloc<AtomicCache<SyntaxData>>(Raw->getNumChildren());
22+
void *data = ::operator new(size);
23+
return RC<SyntaxData>{new (data) SyntaxData(Raw, Parent, IndexInParent)};
2724
}
2825

2926
bool SyntaxData::isType() const {

Diff for: lib/Syntax/SyntaxNodes.cpp.gyb

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ using namespace swift::syntax;
2828
% if node.requires_validation():
2929
void ${node.name}::validate() const {
3030
#ifndef NDEBUG
31-
auto raw = Data->Raw;
31+
auto raw = Data->getRaw();
3232
if (isMissing()) return;
3333
assert(raw->getLayout().size() == ${len(node.children)});
3434
% for child in node.children:

Diff for: lib/Syntax/UnknownSyntax.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ using namespace swift;
1717
using namespace swift::syntax;
1818

1919
void UnknownSyntax::validate() const {
20-
assert(Data->Raw->isUnknown());
20+
assert(Data->getRaw()->isUnknown());
2121
}
2222

0 commit comments

Comments
 (0)