Skip to content

Commit fece895

Browse files
authored
Merge pull request swiftlang#36417 from ahoppen/pr/libsyntax-performance-improvements
[libSyntax] Several small improvements to libSyntax parsing
2 parents 58dbf60 + 084e57b commit fece895

File tree

6 files changed

+158
-161
lines changed

6 files changed

+158
-161
lines changed

include/swift/Parse/ParsedRawSyntaxRecorder.h

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,24 @@
2121

2222
#include "swift/Basic/LLVM.h"
2323
#include "swift/Parse/ParsedRawSyntaxNode.h"
24+
#include "swift/Parse/SyntaxParseActions.h"
25+
#include "swift/SyntaxParse/SyntaxTreeCreator.h"
2426
#include <memory>
2527

28+
/// Define a macro that creates a \c ParsedRawSyntaxNode. If \c
29+
/// PARSEDRAWSYNTAXNODE_VERIFY_RANGES is defined, it passes the \c Range
30+
/// parameter, otherwise it ignores it at the pre-processor level, which means
31+
/// that \c Range can be an invalid expression.
32+
#ifdef PARSEDRAWSYNTAXNODE_VERIFY_RANGES
33+
#define makeParsedRawSyntaxNode(Opaque, SynKind, TokKind, DataKind, IsMissing, \
34+
Range) \
35+
ParsedRawSyntaxNode(Opaque, SynKind, TokKind, DataKind, IsMissing, Range)
36+
#else
37+
#define makeParsedRawSyntaxNode(Opaque, SynKind, TokKind, DataKind, IsMissing, \
38+
Range) \
39+
ParsedRawSyntaxNode(Opaque, SynKind, TokKind, DataKind, IsMissing)
40+
#endif
41+
2642
namespace swift {
2743

2844
class CharSourceRange;
@@ -57,18 +73,50 @@ class ParsedRawSyntaxRecorder final {
5773
/// return the recorded node.
5874
/// This consumes the data from \c node, which is unusable after it has been
5975
/// recorded. The returned node should be used afterwards instead.
60-
ParsedRawSyntaxNode recordDeferredNode(ParsedRawSyntaxNode &node);
76+
ParsedRawSyntaxNode recordDeferredNode(ParsedRawSyntaxNode &node) {
77+
switch (node.getDataKind()) {
78+
case RecordedOrDeferredNode::Kind::Null:
79+
case RecordedOrDeferredNode::Kind::Recorded:
80+
llvm_unreachable("Not deferred");
81+
case RecordedOrDeferredNode::Kind::DeferredLayout: {
82+
OpaqueSyntaxNode Data = SPActions->recordDeferredLayout(node.takeData());
83+
return makeParsedRawSyntaxNode(Data, node.getKind(), node.getTokenKind(),
84+
ParsedRawSyntaxNode::DataKind::Recorded,
85+
node.isMissing(), node.getRange());
86+
}
87+
case RecordedOrDeferredNode::Kind::DeferredToken: {
88+
OpaqueSyntaxNode Data = SPActions->recordDeferredToken(node.takeData());
89+
return makeParsedRawSyntaxNode(Data, node.getKind(), node.getTokenKind(),
90+
ParsedRawSyntaxNode::DataKind::Recorded,
91+
node.isMissing(), node.getRange());
92+
}
93+
}
94+
}
6195

6296
public:
6397
explicit ParsedRawSyntaxRecorder(std::shared_ptr<SyntaxParseActions> spActions)
6498
: SPActions(std::move(spActions)) {}
6599

66100
ParsedRawSyntaxNode recordToken(const Token &tok, StringRef leadingTrivia,
67-
StringRef trailingTrivia);
101+
StringRef trailingTrivia) {
102+
return recordToken(tok.getKind(), tok.getRange(), leadingTrivia,
103+
trailingTrivia);
104+
}
68105

69106
ParsedRawSyntaxNode recordToken(tok tokenKind, CharSourceRange tokenRange,
70107
StringRef leadingTrivia,
71-
StringRef trailingTrivia);
108+
StringRef trailingTrivia) {
109+
SourceLoc offset =
110+
tokenRange.getStart().getAdvancedLoc(-leadingTrivia.size());
111+
unsigned length = leadingTrivia.size() + tokenRange.getByteLength() +
112+
trailingTrivia.size();
113+
CharSourceRange range(offset, length);
114+
OpaqueSyntaxNode n =
115+
SPActions->recordToken(tokenKind, leadingTrivia, trailingTrivia, range);
116+
return makeParsedRawSyntaxNode(n, syntax::SyntaxKind::Token, tokenKind,
117+
ParsedRawSyntaxNode::DataKind::Recorded,
118+
/*IsMissing=*/false, range);
119+
}
72120

73121
/// Record a missing token. \p loc can be invalid or an approximate location
74122
/// of where the token would be if not missing.
@@ -77,8 +125,39 @@ class ParsedRawSyntaxRecorder final {
77125
/// The provided \p elements are an exact layout appropriate for the syntax
78126
/// \p kind. Missing optional elements are represented with a null
79127
/// ParsedRawSyntaxNode object.
80-
ParsedRawSyntaxNode recordRawSyntax(syntax::SyntaxKind kind,
81-
MutableArrayRef<ParsedRawSyntaxNode> elements);
128+
ParsedRawSyntaxNode
129+
recordRawSyntax(syntax::SyntaxKind kind,
130+
MutableArrayRef<ParsedRawSyntaxNode> elements) {
131+
assert(kind != syntax::SyntaxKind::Token &&
132+
"Use recordToken to record a token");
133+
#ifdef PARSEDRAWSYNTAXNODE_VERIFY_RANGES
134+
auto range = ParsedRawSyntaxRecorder::verifyElementRanges(elements);
135+
#endif
136+
137+
SmallVector<OpaqueSyntaxNode, 16> subnodes;
138+
if (!elements.empty()) {
139+
for (auto &subnode : elements) {
140+
switch (subnode.getDataKind()) {
141+
case RecordedOrDeferredNode::Kind::Null:
142+
subnodes.push_back(nullptr);
143+
break;
144+
case RecordedOrDeferredNode::Kind::Recorded:
145+
subnodes.push_back(subnode.takeData());
146+
break;
147+
case RecordedOrDeferredNode::Kind::DeferredLayout:
148+
case RecordedOrDeferredNode::Kind::DeferredToken: {
149+
auto recorded = recordDeferredNode(subnode);
150+
subnodes.push_back(recorded.takeData());
151+
break;
152+
}
153+
}
154+
}
155+
}
156+
OpaqueSyntaxNode n = SPActions->recordRawSyntax(kind, subnodes);
157+
return makeParsedRawSyntaxNode(n, kind, tok::NUM_TOKENS,
158+
ParsedRawSyntaxNode::DataKind::Recorded,
159+
/*IsMissing=*/false, range);
160+
}
82161

83162
/// Record a raw syntax collecton without eny elements. \p loc can be invalid
84163
/// or an approximate location of where an element of the collection would be
@@ -94,11 +173,38 @@ class ParsedRawSyntaxRecorder final {
94173
ParsedRawSyntaxNode
95174
makeDeferred(syntax::SyntaxKind k,
96175
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes,
97-
SyntaxParsingContext &ctx);
176+
SyntaxParsingContext &ctx) {
177+
#ifdef PARSEDRAWSYNTAXNODE_VERIFY_RANGES
178+
auto range = ParsedRawSyntaxRecorder::verifyElementRanges(deferredNodes);
179+
#endif
180+
181+
assert(llvm::none_of(deferredNodes, [](const ParsedRawSyntaxNode &node) {
182+
return node.isRecorded();
183+
}) && "Cannot create a deferred layout node that has recorded children");
184+
185+
auto data =
186+
SPActions->makeDeferredLayout(k, /*IsMissing=*/false, deferredNodes);
187+
return makeParsedRawSyntaxNode(
188+
data, k, tok::NUM_TOKENS, ParsedRawSyntaxNode::DataKind::DeferredLayout,
189+
/*IsMissing=*/false, range);
190+
}
98191

99192
/// Form a deferred token node.
100193
ParsedRawSyntaxNode makeDeferred(Token tok, StringRef leadingTrivia,
101-
StringRef trailingTrivia);
194+
StringRef trailingTrivia) {
195+
CharSourceRange tokRange = tok.getRange();
196+
CharSourceRange RangeWithTrivia = CharSourceRange(
197+
tokRange.getStart().getAdvancedLoc(-leadingTrivia.size()),
198+
(unsigned)leadingTrivia.size() + tokRange.getByteLength() +
199+
(unsigned)trailingTrivia.size());
200+
auto Data = SPActions->makeDeferredToken(tok.getKind(), leadingTrivia,
201+
trailingTrivia, RangeWithTrivia,
202+
/*IsMissing=*/false);
203+
return makeParsedRawSyntaxNode(Data, syntax::SyntaxKind::Token,
204+
tok.getKind(),
205+
ParsedRawSyntaxNode::DataKind::DeferredToken,
206+
/*IsMissing=*/false, RangeWithTrivia);
207+
}
102208

103209
/// Form a deferred missing token node.
104210
ParsedRawSyntaxNode makeDeferredMissing(tok tokKind, SourceLoc loc);

include/swift/Parse/SyntaxParseActions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class ParsedTriviaPiece;
3030
class SourceFile;
3131
class SourceLoc;
3232
enum class tok : uint8_t;
33+
class ParsedRawSyntaxNode;
3334

3435
namespace syntax {
3536
class SourceFileSyntax;
@@ -112,9 +113,11 @@ class SyntaxParseActions {
112113
/// Create a deferred layout node that may or may not be recorded later using
113114
/// \c recordDeferredLayout. The \c SyntaxParseAction is responsible for
114115
/// keeping the deferred token alive until it is destructed.
116+
/// From all nodes in \p children, the underlying opaque data will be *taken*
117+
/// which resets the nodes.
115118
virtual OpaqueSyntaxNode
116119
makeDeferredLayout(syntax::SyntaxKind k, bool isMissing,
117-
const ArrayRef<RecordedOrDeferredNode> &children) = 0;
120+
const MutableArrayRef<ParsedRawSyntaxNode> &children) = 0;
118121

119122
/// Record a deferred token node that was previously created using \c
120123
/// makeDeferredToken. The deferred data will never be used again, so it can

include/swift/SyntaxParse/SyntaxTreeCreator.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ class SyntaxTreeCreator final : public SyntaxParseActions {
7676
CharSourceRange range,
7777
bool isMissing) override;
7878

79-
OpaqueSyntaxNode
80-
makeDeferredLayout(syntax::SyntaxKind k, bool IsMissing,
81-
const ArrayRef<RecordedOrDeferredNode> &children) override;
79+
OpaqueSyntaxNode makeDeferredLayout(
80+
syntax::SyntaxKind k, bool IsMissing,
81+
const MutableArrayRef<ParsedRawSyntaxNode> &children) override;
8282

8383
OpaqueSyntaxNode recordDeferredToken(OpaqueSyntaxNode deferred) override;
8484
OpaqueSyntaxNode recordDeferredLayout(OpaqueSyntaxNode deferred) override;

lib/Parse/ParsedRawSyntaxRecorder.cpp

Lines changed: 0 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -27,63 +27,6 @@
2727
using namespace swift;
2828
using namespace swift::syntax;
2929

30-
/// Define a macro that creates a \c ParsedRawSyntaxNode. If \c
31-
/// PARSEDRAWSYNTAXNODE_VERIFY_RANGES is defined, it passes the \c Range
32-
/// parameter, otherwise it ignores it at the pre-processor level, which means
33-
/// that \c Range can be an invalid expression.
34-
#ifdef PARSEDRAWSYNTAXNODE_VERIFY_RANGES
35-
#define makeParsedRawSyntaxNode(Opaque, SynKind, TokKind, DataKind, IsMissing, \
36-
Range) \
37-
ParsedRawSyntaxNode(Opaque, SynKind, TokKind, DataKind, IsMissing, Range)
38-
#else
39-
#define makeParsedRawSyntaxNode(Opaque, SynKind, TokKind, DataKind, IsMissing, \
40-
Range) \
41-
ParsedRawSyntaxNode(Opaque, SynKind, TokKind, DataKind, IsMissing)
42-
#endif
43-
44-
ParsedRawSyntaxNode
45-
ParsedRawSyntaxRecorder::recordDeferredNode(ParsedRawSyntaxNode &node) {
46-
switch (node.getDataKind()) {
47-
case RecordedOrDeferredNode::Kind::Null:
48-
case RecordedOrDeferredNode::Kind::Recorded:
49-
llvm_unreachable("Not deferred");
50-
case RecordedOrDeferredNode::Kind::DeferredLayout: {
51-
OpaqueSyntaxNode Data = SPActions->recordDeferredLayout(node.takeData());
52-
return makeParsedRawSyntaxNode(Data, node.getKind(), node.getTokenKind(),
53-
ParsedRawSyntaxNode::DataKind::Recorded,
54-
node.isMissing(), node.getRange());
55-
}
56-
case RecordedOrDeferredNode::Kind::DeferredToken: {
57-
OpaqueSyntaxNode Data = SPActions->recordDeferredToken(node.takeData());
58-
return makeParsedRawSyntaxNode(Data, node.getKind(), node.getTokenKind(),
59-
ParsedRawSyntaxNode::DataKind::Recorded,
60-
node.isMissing(), node.getRange());
61-
}
62-
}
63-
}
64-
65-
ParsedRawSyntaxNode
66-
ParsedRawSyntaxRecorder::recordToken(const Token &tok, StringRef leadingTrivia,
67-
StringRef trailingTrivia) {
68-
return recordToken(tok.getKind(), tok.getRange(), leadingTrivia,
69-
trailingTrivia);
70-
}
71-
72-
ParsedRawSyntaxNode
73-
ParsedRawSyntaxRecorder::recordToken(tok tokKind, CharSourceRange tokRange,
74-
StringRef leadingTrivia,
75-
StringRef trailingTrivia) {
76-
SourceLoc offset = tokRange.getStart().getAdvancedLoc(-leadingTrivia.size());
77-
unsigned length =
78-
leadingTrivia.size() + tokRange.getByteLength() + trailingTrivia.size();
79-
CharSourceRange range(offset, length);
80-
OpaqueSyntaxNode n =
81-
SPActions->recordToken(tokKind, leadingTrivia, trailingTrivia, range);
82-
return makeParsedRawSyntaxNode(n, SyntaxKind::Token, tokKind,
83-
ParsedRawSyntaxNode::DataKind::Recorded,
84-
/*IsMissing=*/false, range);
85-
}
86-
8730
ParsedRawSyntaxNode
8831
ParsedRawSyntaxRecorder::recordMissingToken(tok tokenKind, SourceLoc loc) {
8932
OpaqueSyntaxNode n = SPActions->recordMissingToken(tokenKind, loc);
@@ -92,39 +35,6 @@ ParsedRawSyntaxRecorder::recordMissingToken(tok tokenKind, SourceLoc loc) {
9235
/*isMissing=*/true, CharSourceRange(loc, 0));
9336
}
9437

95-
ParsedRawSyntaxNode
96-
ParsedRawSyntaxRecorder::recordRawSyntax(SyntaxKind kind,
97-
MutableArrayRef<ParsedRawSyntaxNode> elements) {
98-
assert(kind != SyntaxKind::Token && "Use recordToken to record a token");
99-
#ifdef PARSEDRAWSYNTAXNODE_VERIFY_RANGES
100-
auto range = ParsedRawSyntaxRecorder::verifyElementRanges(elements);
101-
#endif
102-
103-
SmallVector<OpaqueSyntaxNode, 16> subnodes;
104-
if (!elements.empty()) {
105-
for (auto &subnode : elements) {
106-
switch (subnode.getDataKind()) {
107-
case RecordedOrDeferredNode::Kind::Null:
108-
subnodes.push_back(nullptr);
109-
break;
110-
case RecordedOrDeferredNode::Kind::Recorded:
111-
subnodes.push_back(subnode.takeData());
112-
break;
113-
case RecordedOrDeferredNode::Kind::DeferredLayout:
114-
case RecordedOrDeferredNode::Kind::DeferredToken: {
115-
auto recorded = recordDeferredNode(subnode);
116-
subnodes.push_back(recorded.takeData());
117-
break;
118-
}
119-
}
120-
}
121-
}
122-
OpaqueSyntaxNode n = SPActions->recordRawSyntax(kind, subnodes);
123-
return makeParsedRawSyntaxNode(n, kind, tok::NUM_TOKENS,
124-
ParsedRawSyntaxNode::DataKind::Recorded,
125-
/*IsMissing=*/false, range);
126-
}
127-
12838
ParsedRawSyntaxNode
12939
ParsedRawSyntaxRecorder::recordEmptyRawSyntaxCollection(SyntaxKind kind,
13040
SourceLoc loc) {
@@ -134,48 +44,6 @@ ParsedRawSyntaxRecorder::recordEmptyRawSyntaxCollection(SyntaxKind kind,
13444
/*IsMissing=*/false, CharSourceRange(loc, 0));
13545
}
13646

137-
/// Create a deferred layout node.
138-
ParsedRawSyntaxNode ParsedRawSyntaxRecorder::makeDeferred(
139-
syntax::SyntaxKind k, MutableArrayRef<ParsedRawSyntaxNode> deferredNodes,
140-
SyntaxParsingContext &ctx) {
141-
#ifdef PARSEDRAWSYNTAXNODE_VERIFY_RANGES
142-
auto range = ParsedRawSyntaxRecorder::verifyElementRanges(deferredNodes);
143-
#endif
144-
145-
RecordedOrDeferredNode *newPtr =
146-
ctx.getScratchAlloc().Allocate<RecordedOrDeferredNode>(
147-
deferredNodes.size());
148-
auto children = llvm::makeMutableArrayRef(newPtr, deferredNodes.size());
149-
for (size_t i = 0; i < deferredNodes.size(); ++i) {
150-
auto &node = deferredNodes[i];
151-
assert(!node.isRecorded() &&
152-
"Cannot create a deferred layout node that has recorded children");
153-
154-
children[i] = node.takeRecordedOrDeferredNode();
155-
}
156-
auto data = SPActions->makeDeferredLayout(k, /*IsMissing=*/false, children);
157-
return makeParsedRawSyntaxNode(data, k, tok::NUM_TOKENS,
158-
ParsedRawSyntaxNode::DataKind::DeferredLayout,
159-
/*IsMissing=*/false, range);
160-
}
161-
162-
/// Create a deferred token node.
163-
ParsedRawSyntaxNode
164-
ParsedRawSyntaxRecorder::makeDeferred(Token tok, StringRef leadingTrivia,
165-
StringRef trailingTrivia) {
166-
CharSourceRange tokRange = tok.getRange();
167-
CharSourceRange RangeWithTrivia = CharSourceRange(
168-
tokRange.getStart().getAdvancedLoc(-leadingTrivia.size()),
169-
(unsigned)leadingTrivia.size() + tokRange.getByteLength() +
170-
(unsigned)trailingTrivia.size());
171-
auto Data =
172-
SPActions->makeDeferredToken(tok.getKind(), leadingTrivia, trailingTrivia,
173-
RangeWithTrivia, /*IsMissing=*/false);
174-
return makeParsedRawSyntaxNode(Data, SyntaxKind::Token, tok.getKind(),
175-
ParsedRawSyntaxNode::DataKind::DeferredToken,
176-
/*IsMissing=*/false, RangeWithTrivia);
177-
}
178-
17947
ParsedRawSyntaxNode
18048
ParsedRawSyntaxRecorder::makeDeferredMissing(tok tokKind, SourceLoc loc) {
18149
auto Data = SPActions->makeDeferredToken(

0 commit comments

Comments
 (0)