mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[libSyntax] Don't create dedicated deferred nodes in SyntaxTreeCreator
We have finally reached our goal of optimising deferred node creation for SyntaxTreeCreator. Instead of creating dedicated deferred nodes and copying the data into a RawSyntax node when recording, we always create RawSyntax nodes. Recording a deferred node is thus a no-op, since we have already created a RawSyntax node. Should a deferred node not be recorded, it stays alive in the SyntaxArena without any reference to it. While this means, we are leaking some memory for such nodes, most nodes do get recorded, so the overhead should be fine compared to the performance benefit.
This commit is contained in:
@@ -98,10 +98,36 @@ public:
|
||||
swiftparse_client_node_t parse(const char *source, size_t len);
|
||||
};
|
||||
|
||||
struct DeferredTokenNode {
|
||||
bool IsMissing;
|
||||
tok TokenKind;
|
||||
StringRef LeadingTrivia;
|
||||
StringRef TrailingTrivia;
|
||||
/// The range of the token including trivia.
|
||||
CharSourceRange Range;
|
||||
|
||||
DeferredTokenNode(bool IsMissing, tok TokenKind, StringRef LeadingTrivia,
|
||||
StringRef TrailingTrivia, CharSourceRange Range)
|
||||
: IsMissing(IsMissing), TokenKind(TokenKind),
|
||||
LeadingTrivia(LeadingTrivia), TrailingTrivia(TrailingTrivia),
|
||||
Range(Range) {}
|
||||
};
|
||||
|
||||
struct DeferredLayoutNode {
|
||||
syntax::SyntaxKind Kind;
|
||||
ArrayRef<RecordedOrDeferredNode> Children;
|
||||
unsigned Length;
|
||||
|
||||
DeferredLayoutNode(syntax::SyntaxKind Kind,
|
||||
ArrayRef<RecordedOrDeferredNode> Children, unsigned Length)
|
||||
: Kind(Kind), Children(Children), Length(Length) {}
|
||||
};
|
||||
|
||||
class CLibParseActions : public SyntaxParseActions {
|
||||
SynParser &SynParse;
|
||||
SourceManager &SM;
|
||||
unsigned BufferID;
|
||||
llvm::BumpPtrAllocator DeferredNodeAllocator;
|
||||
|
||||
public:
|
||||
CLibParseActions(SynParser &synParse, SourceManager &sm, unsigned bufID)
|
||||
@@ -208,6 +234,139 @@ private:
|
||||
auto result = NodeLookup(lexerOffset, ckind);
|
||||
return {result.length, result.node};
|
||||
}
|
||||
|
||||
OpaqueSyntaxNode makeDeferredToken(tok tokenKind, StringRef leadingTrivia,
|
||||
StringRef trailingTrivia,
|
||||
CharSourceRange range,
|
||||
bool isMissing) override {
|
||||
return new (DeferredNodeAllocator) DeferredTokenNode(
|
||||
isMissing, tokenKind, leadingTrivia, trailingTrivia, range);
|
||||
}
|
||||
|
||||
OpaqueSyntaxNode makeDeferredLayout(
|
||||
syntax::SyntaxKind k, bool isMissing,
|
||||
const ArrayRef<RecordedOrDeferredNode> &children) override {
|
||||
assert(!isMissing && "Missing layout nodes not implemented yet");
|
||||
|
||||
// Compute the length of this node.
|
||||
unsigned length = 0;
|
||||
for (auto &child : children) {
|
||||
switch (child.getKind()) {
|
||||
case RecordedOrDeferredNode::Kind::Null:
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::Recorded:
|
||||
llvm_unreachable("Children of deferred nodes must also be deferred");
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::DeferredLayout:
|
||||
length +=
|
||||
static_cast<const DeferredLayoutNode *>(child.getOpaque())->Length;
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::DeferredToken:
|
||||
length += static_cast<const DeferredTokenNode *>(child.getOpaque())
|
||||
->Range.getByteLength();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new (DeferredNodeAllocator) DeferredLayoutNode(k, children, length);
|
||||
}
|
||||
|
||||
OpaqueSyntaxNode recordDeferredToken(OpaqueSyntaxNode deferred) override {
|
||||
auto Data = static_cast<const DeferredTokenNode *>(deferred);
|
||||
if (Data->IsMissing) {
|
||||
return recordMissingToken(Data->TokenKind, Data->Range.getStart());
|
||||
} else {
|
||||
return recordToken(Data->TokenKind, Data->LeadingTrivia,
|
||||
Data->TrailingTrivia, Data->Range);
|
||||
}
|
||||
}
|
||||
|
||||
OpaqueSyntaxNode recordDeferredLayout(OpaqueSyntaxNode deferred) override {
|
||||
auto Data = static_cast<const DeferredLayoutNode *>(deferred);
|
||||
|
||||
auto childrenStore =
|
||||
DeferredNodeAllocator.Allocate<OpaqueSyntaxNode>(Data->Children.size());
|
||||
MutableArrayRef<OpaqueSyntaxNode> children =
|
||||
llvm::makeMutableArrayRef(childrenStore, Data->Children.size());
|
||||
|
||||
for (size_t i = 0; i < Data->Children.size(); ++i) {
|
||||
auto Child = Data->Children[i];
|
||||
switch (Child.getKind()) {
|
||||
case RecordedOrDeferredNode::Kind::Null:
|
||||
children[i] = Child.getOpaque();
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::Recorded:
|
||||
llvm_unreachable("Children of deferred nodes must also be deferred");
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::DeferredLayout:
|
||||
children[i] = recordDeferredLayout(Child.getOpaque());
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::DeferredToken:
|
||||
children[i] = recordDeferredToken(Child.getOpaque());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return recordRawSyntax(Data->Kind, children);
|
||||
}
|
||||
|
||||
DeferredNodeInfo getDeferredChild(OpaqueSyntaxNode node, size_t ChildIndex,
|
||||
SourceLoc StartLoc) override {
|
||||
auto Data = static_cast<const DeferredLayoutNode *>(node);
|
||||
|
||||
// Compute the start offset of the child node by advancing StartLoc by the
|
||||
// length of all previous child nodes.
|
||||
for (unsigned i = 0; i < ChildIndex; ++i) {
|
||||
auto Child = Data->Children[i];
|
||||
switch (Child.getKind()) {
|
||||
case RecordedOrDeferredNode::Kind::Null:
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::Recorded:
|
||||
llvm_unreachable("Children of deferred nodes must also be deferred");
|
||||
case RecordedOrDeferredNode::Kind::DeferredLayout:
|
||||
StartLoc = StartLoc.getAdvancedLoc(
|
||||
static_cast<const DeferredLayoutNode *>(Child.getOpaque())->Length);
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::DeferredToken:
|
||||
StartLoc = StartLoc.getAdvancedLoc(
|
||||
static_cast<const DeferredTokenNode *>(Child.getOpaque())
|
||||
->Range.getByteLength());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto Child = Data->Children[ChildIndex];
|
||||
switch (Child.getKind()) {
|
||||
case RecordedOrDeferredNode::Kind::Null:
|
||||
return DeferredNodeInfo(
|
||||
RecordedOrDeferredNode(nullptr, RecordedOrDeferredNode::Kind::Null),
|
||||
syntax::SyntaxKind::Unknown, tok::NUM_TOKENS,
|
||||
/*IsMissing=*/false, CharSourceRange(StartLoc, /*Length=*/0));
|
||||
case RecordedOrDeferredNode::Kind::Recorded:
|
||||
llvm_unreachable("Children of deferred nodes must also be deferred");
|
||||
break;
|
||||
case RecordedOrDeferredNode::Kind::DeferredLayout: {
|
||||
auto ChildData = static_cast<const DeferredLayoutNode *>(Child.getOpaque());
|
||||
return DeferredNodeInfo(
|
||||
RecordedOrDeferredNode(ChildData,
|
||||
RecordedOrDeferredNode::Kind::DeferredLayout),
|
||||
ChildData->Kind, tok::NUM_TOKENS,
|
||||
/*IsMissing=*/false, CharSourceRange(StartLoc, ChildData->Length));
|
||||
}
|
||||
case RecordedOrDeferredNode::Kind::DeferredToken: {
|
||||
auto ChildData = static_cast<const DeferredTokenNode *>(Child.getOpaque());
|
||||
return DeferredNodeInfo(
|
||||
RecordedOrDeferredNode(ChildData,
|
||||
RecordedOrDeferredNode::Kind::DeferredToken),
|
||||
syntax::SyntaxKind::Token, ChildData->TokenKind, ChildData->IsMissing,
|
||||
ChildData->Range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t getDeferredNumChildren(OpaqueSyntaxNode node) override {
|
||||
auto Data = static_cast<const DeferredLayoutNode *>(node);
|
||||
return Data->Children.size();
|
||||
}
|
||||
};
|
||||
|
||||
static swiftparser_diagnostic_severity_t getSeverity(DiagnosticKind Kind) {
|
||||
|
||||
Reference in New Issue
Block a user