Skip to content

Commit a9ab4aa

Browse files
author
David Ungar
committed
Use SeparateCaching
1 parent 86ec6a0 commit a9ab4aa

File tree

6 files changed

+106
-76
lines changed

6 files changed

+106
-76
lines changed

include/swift/AST/ASTScope.h

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,12 @@ class ASTScopeImpl {
343343
/// expandScope me, sending deferred nodes to my descendants.
344344
/// Return the scope into which to place subsequent decls
345345
ASTScopeImpl *expandAndBeCurrentDetectingRecursion(ScopeCreator &);
346+
347+
/// Expand or reexpand the scope if unexpanded or if not current.
348+
/// There are several places in the compiler that mutate the AST after the
349+
/// fact, above and beyond adding Decls to the SourceFile. These are
350+
/// documented in: rdar://53018839, rdar://53027266, rdar://53027733,
351+
/// rdar://53028050
346352
ASTScopeImpl *expandAndBeCurrent(ScopeCreator &);
347353

348354
unsigned getASTAncestorScopeCount() const { return astAncestorScopeCount; }
@@ -354,6 +360,12 @@ class ASTScopeImpl {
354360
void setWasExpanded() { wasExpanded = true; }
355361
virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0;
356362
virtual void beCurrent();
363+
virtual bool doesExpansionOnlyAddNewDeclsAtEnd() const;
364+
365+
public:
366+
bool isExpansionNeeded(const ScopeCreator &) const;
367+
368+
protected:
357369
bool isCurrent() const;
358370
virtual bool isCurrentIfWasExpanded() const;
359371

@@ -384,16 +396,7 @@ class ASTScopeImpl {
384396

385397
bool isATypeDeclScope() const;
386398

387-
/// There are several places in the compiler that mutate the AST after the
388-
/// fact, above and beyond adding Decls to the SourceFile. These are
389-
/// documented in: rdar://53018839, rdar://53027266, rdar://53027733,
390-
/// rdar://53028050
391-
/// Return true if did reexpand
392-
bool reexpandIfObsolete(ScopeCreator &);
393-
394399
private:
395-
void reexpand(ScopeCreator &);
396-
397400
virtual ScopeCreator &getScopeCreator();
398401

399402
#pragma mark - - creation queries
@@ -544,7 +547,7 @@ class ASTSourceFileScope final : public ASTScopeImpl {
544547
/// Since parsing can be interleaved with type-checking, on every
545548
/// lookup, look at creating scopes for any \c Decls beyond this number.
546549
/// rdar://55562483 Unify with numberOfChildrenWhenLastExpanded
547-
int numberOfDeclsAlreadySeen = 0;
550+
size_t numberOfDeclsAlreadySeen = 0;
548551

549552
ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator);
550553

@@ -558,7 +561,6 @@ class ASTSourceFileScope final : public ASTScopeImpl {
558561
public:
559562
NullablePtr<DeclContext> getDeclContext() const override;
560563

561-
void addNewDeclsToScopeTree();
562564
void buildFullyExpandedTree();
563565
void
564566
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
@@ -569,11 +571,15 @@ class ASTSourceFileScope final : public ASTScopeImpl {
569571

570572
protected:
571573
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
574+
bool isCurrentIfWasExpanded() const override;
575+
void beCurrent() override;
576+
bool doesExpansionOnlyAddNewDeclsAtEnd() const override;
572577

573578
ScopeCreator &getScopeCreator() override;
574579

575580
private:
576-
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
581+
AnnotatedInsertionPoint
582+
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
577583
};
578584

579585
class Portion {

include/swift/AST/NameLookupRequests.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ class ExpandASTScopeRequest
333333
: public SimpleRequest<ExpandASTScopeRequest,
334334
ast_scope::ASTScopeImpl *(ast_scope::ASTScopeImpl *,
335335
ast_scope::ScopeCreator *),
336-
CacheKind::Uncached> {
336+
CacheKind::SeparatelyCached> {
337337
public:
338338
using SimpleRequest::SimpleRequest;
339339

@@ -346,8 +346,10 @@ class ExpandASTScopeRequest
346346
ast_scope::ScopeCreator *) const;
347347

348348
public:
349-
// Caching
350-
bool isCached() const { return true; }
349+
// Separate caching.
350+
bool isCached() const;
351+
Optional<ast_scope::ASTScopeImpl *> getCachedResult() const;
352+
void cacheResult(ast_scope::ASTScopeImpl *) const {}
351353
};
352354

353355
#define SWIFT_TYPEID_ZONE NameLookup

include/swift/AST/NameLookupTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ SWIFT_REQUEST(NameLookup, CustomAttrNominalRequest,
2020
NoLocationInfo)
2121
SWIFT_REQUEST(NameLookup, ExpandASTScopeRequest,
2222
ast_scope::ASTScopeImpl* (ast_scope::ASTScopeImpl*, ast_scope::ScopeCreator*),
23-
Uncached,
23+
SeparatelyCached,
2424
NoLocationInfo)
2525
SWIFT_REQUEST(NameLookup, ExtendedNominalRequest,
2626
NominalTypeDecl *(ExtensionDecl *), SeparatelyCached,

lib/AST/ASTScopeCreation.cpp

Lines changed: 76 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -654,9 +654,8 @@ class ScopeCreator final {
654654
bool containsAllDeclContextsFromAST() {
655655
auto allDeclContexts = findLocalizableDeclContextsInAST();
656656
llvm::DenseMap<const DeclContext *, const ASTScopeImpl *> bogusDCs;
657-
bool rebuilt = false;
658657
sourceFileScope->preOrderDo([&](ASTScopeImpl *scope) {
659-
rebuilt |= scope->reexpandIfObsolete(*this);
658+
scope->expandAndBeCurrentDetectingRecursion(*this);
660659
});
661660
sourceFileScope->postOrderDo([&](ASTScopeImpl *scope) {
662661
if (auto *dc = scope->getDeclContext().getPtrOrNull()) {
@@ -673,8 +672,6 @@ class ScopeCreator final {
673672
d->getSourceRange().dump(ctx.SourceMgr);
674673
llvm::errs() << " : ";
675674
d->dump(llvm::errs());
676-
if (rebuilt)
677-
llvm::errs() << " (rebuilt)";
678675
llvm::errs() << "\n";
679676
};
680677
bool foundOmission = false;
@@ -750,35 +747,17 @@ ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) {
750747
}
751748

752749
void ASTSourceFileScope::buildFullyExpandedTree() {
753-
addNewDeclsToScopeTree();
754-
preOrderChildrenDo(
755-
[&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); });
750+
expandAndBeCurrentDetectingRecursion(*scopeCreator);
751+
preOrderChildrenDo([&](ASTScopeImpl *s) {
752+
s->expandAndBeCurrentDetectingRecursion(*scopeCreator);
753+
});
756754
}
757755

758756
void ASTSourceFileScope::
759757
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() {
760-
addNewDeclsToScopeTree();
758+
expandAndBeCurrentDetectingRecursion(*scopeCreator);
761759
}
762760

763-
void ASTSourceFileScope::addNewDeclsToScopeTree() {
764-
ASTScopeAssert(SF && scopeCreator,
765-
"Must already have a SourceFile and a ScopeCreator.");
766-
ArrayRef<Decl *> decls = SF->Decls;
767-
// Assume that decls are only added at the end, in source order
768-
ArrayRef<Decl *> newDecls = decls.slice(numberOfDeclsAlreadySeen);
769-
std::vector<ASTNode> newNodes(newDecls.begin(), newDecls.end());
770-
insertionPoint =
771-
scopeCreator->addSiblingsToScopeTree(insertionPoint, this, newNodes);
772-
773-
// TODO: use regular expansion machinery for ASTSourceFileScope
774-
// rdar://55562483
775-
numberOfDeclsAlreadySeen = SF->Decls.size();
776-
setWasExpanded();
777-
778-
// Too slow to perform all the time:
779-
// ASTScopeAssert(scopeCreator->containsAllDeclContextsFromAST(),
780-
// "ASTScope tree missed some DeclContexts or made some up");
781-
}
782761

783762
ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
784763
ScopeCreator *scopeCreator)
@@ -1094,10 +1073,33 @@ ASTScopeImpl::expandAndBeCurrentDetectingRecursion(ScopeCreator &scopeCreator) {
10941073
llvm::Expected<ASTScopeImpl *>
10951074
ExpandASTScopeRequest::evaluate(Evaluator &evaluator, ASTScopeImpl *parent,
10961075
ScopeCreator *scopeCreator) const {
1097-
return parent->expandAndBeCurrent(*scopeCreator);
1076+
auto *insertionPoint = parent->expandAndBeCurrent(*scopeCreator);
1077+
ASTScopeAssert(insertionPoint,
1078+
"Used to return a null pointer if the insertion point would "
1079+
"not be used, but it breaks the request dependency hashing");
1080+
return insertionPoint;
1081+
}
1082+
1083+
bool ASTScopeImpl::doesExpansionOnlyAddNewDeclsAtEnd() const { return false; }
1084+
bool ASTSourceFileScope::doesExpansionOnlyAddNewDeclsAtEnd() const {
1085+
return true;
10981086
}
10991087

11001088
ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) {
1089+
1090+
// We might be reexpanding, so save any scopes that were inserted here from
1091+
// above it in the AST
1092+
auto astAncestorScopes = rescueASTAncestorScopesForReuseFromMeOrDescendants();
1093+
ASTScopeAssert(astAncestorScopes.empty() ||
1094+
!doesExpansionOnlyAddNewDeclsAtEnd(),
1095+
"ASTSourceFileScope has no ancestors to be rescued.");
1096+
1097+
// If reexpanding, we need to remove descendant decls from the duplication set
1098+
// in order to re-add them as sub-scopes. Since expansion only adds new Decls
1099+
// at end, don't bother with descendants
1100+
if (!doesExpansionOnlyAddNewDeclsAtEnd())
1101+
disownDescendants(scopeCreator);
1102+
11011103
auto *insertionPoint = expandSpecifically(scopeCreator);
11021104
if (scopeCreator.shouldBeLazy()) {
11031105
ASTScopeAssert(!insertionPointForDeferredExpansion() ||
@@ -1107,6 +1109,7 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) {
11071109
"accurate before expansion, the insertion point before "
11081110
"expansion must be the same as after expansion.");
11091111
}
1112+
replaceASTAncestorScopes(astAncestorScopes);
11101113
setWasExpanded();
11111114
beCurrent();
11121115
ASTScopeAssert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext()),
@@ -1132,6 +1135,7 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) {
11321135
#define NO_EXPANSION(Scope) \
11331136
ASTScopeImpl *Scope::expandSpecifically(ScopeCreator &) { return this; }
11341137

1138+
CREATES_NEW_INSERTION_POINT(ASTSourceFileScope)
11351139
CREATES_NEW_INSERTION_POINT(ParameterListScope)
11361140
CREATES_NEW_INSERTION_POINT(ConditionalClauseScope)
11371141
CREATES_NEW_INSERTION_POINT(GuardStmtScope)
@@ -1163,7 +1167,6 @@ NO_NEW_INSERTION_POINT(WhileStmtScope)
11631167
NO_NEW_INSERTION_POINT(WholeClosureScope)
11641168

11651169
NO_EXPANSION(GenericParamScope)
1166-
NO_EXPANSION(ASTSourceFileScope)
11671170
NO_EXPANSION(ClosureParametersScope)
11681171
NO_EXPANSION(SpecializeAttributeScope)
11691172
NO_EXPANSION(ConditionalClausePatternUseScope)
@@ -1172,6 +1175,22 @@ NO_EXPANSION(LookupParentDiversionScope)
11721175
#undef CREATES_NEW_INSERTION_POINT
11731176
#undef NO_NEW_INSERTION_POINT
11741177

1178+
AnnotatedInsertionPoint
1179+
ASTSourceFileScope::expandAScopeThatCreatesANewInsertionPoint(
1180+
ScopeCreator &scopeCreator) {
1181+
ASTScopeAssert(SF, "Must already have a SourceFile.");
1182+
ArrayRef<Decl *> decls = SF->Decls;
1183+
// Assume that decls are only added at the end, in source order
1184+
ArrayRef<Decl *> newDecls = decls.slice(numberOfDeclsAlreadySeen);
1185+
std::vector<ASTNode> newNodes(newDecls.begin(), newDecls.end());
1186+
insertionPoint =
1187+
scopeCreator.addSiblingsToScopeTree(insertionPoint, this, newNodes);
1188+
// Too slow to perform all the time:
1189+
// ASTScopeAssert(scopeCreator->containsAllDeclContextsFromAST(),
1190+
// "ASTScope tree missed some DeclContexts or made some up");
1191+
return {insertionPoint, "Next time decls are added they go here."};
1192+
}
1193+
11751194
AnnotatedInsertionPoint
11761195
ParameterListScope::expandAScopeThatCreatesANewInsertionPoint(
11771196
ScopeCreator &scopeCreator) {
@@ -1230,7 +1249,8 @@ PatternEntryInitializerScope::expandAScopeThatCreatesANewInsertionPoint(
12301249
"get its endpoint in order to push back start of "
12311250
"PatternEntryUseScope"};
12321251

1233-
return {nullptr, "Unused"};
1252+
// null pointer here blows up request printing
1253+
return {getParent().get(), "Unused"};
12341254
}
12351255

12361256
AnnotatedInsertionPoint
@@ -1308,11 +1328,6 @@ TopLevelCodeScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &
13081328

13091329
#pragma mark expandAScopeThatDoesNotCreateANewInsertionPoint
13101330

1311-
void ASTSourceFileScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
1312-
ScopeCreator &scopeCreator) {
1313-
ASTScope_unreachable("expanded by addNewDeclsToScopeTree()");
1314-
}
1315-
13161331
// Create child scopes for every declaration in a body.
13171332

13181333
void AbstractFunctionDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
@@ -1752,27 +1767,6 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) {
17521767
++s->getFrontendCounters().NumIterableTypeBodyASTScopeExpansions;
17531768
}
17541769

1755-
#pragma mark - reexpandIfObsolete
1756-
1757-
bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) {
1758-
if (isCurrent() &&
1759-
!scopeCreator.getASTContext().LangOpts.StressASTScopeLookup) {
1760-
ASTScopeAssert(getWasExpanded(), "Cannot be current if unexpanded.");
1761-
return false;
1762-
}
1763-
reexpand(scopeCreator);
1764-
return true;
1765-
}
1766-
1767-
void ASTScopeImpl::reexpand(ScopeCreator &scopeCreator) {
1768-
auto astAncestorScopes = rescueASTAncestorScopesForReuseFromMeOrDescendants();
1769-
disownDescendants(scopeCreator);
1770-
// If the expansion recurses back into the tree for lookup, the ASTAncestor
1771-
// scopes will have already been rescued and won't be found!
1772-
expandAndBeCurrentDetectingRecursion(scopeCreator);
1773-
replaceASTAncestorScopes(astAncestorScopes);
1774-
}
1775-
17761770
#pragma mark getScopeCreator
17771771
ScopeCreator &ASTScopeImpl::getScopeCreator() {
17781772
return getParent().get()->getScopeCreator();
@@ -1847,13 +1841,25 @@ IterableTypeBodyPortion::insertionPointForDeferredExpansion(
18471841
return s->getParent().get();
18481842
}
18491843

1844+
bool ASTScopeImpl::isExpansionNeeded(const ScopeCreator &scopeCreator) const {
1845+
return !isCurrent() ||
1846+
scopeCreator.getASTContext().LangOpts.StressASTScopeLookup;
1847+
}
1848+
18501849
bool ASTScopeImpl::isCurrent() const {
18511850
return getWasExpanded() && isCurrentIfWasExpanded();
18521851
}
18531852

18541853
void ASTScopeImpl::beCurrent() {}
18551854
bool ASTScopeImpl::isCurrentIfWasExpanded() const { return true; }
18561855

1856+
void ASTSourceFileScope::beCurrent() {
1857+
numberOfDeclsAlreadySeen = SF->Decls.size();
1858+
}
1859+
bool ASTSourceFileScope::isCurrentIfWasExpanded() const {
1860+
return SF->Decls.size() == numberOfDeclsAlreadySeen;
1861+
}
1862+
18571863
void IterableTypeScope::beCurrent() { portion->beCurrent(this); }
18581864
bool IterableTypeScope::isCurrentIfWasExpanded() const {
18591865
return portion->isCurrentIfWasExpanded(this);
@@ -2092,3 +2098,17 @@ void ast_scope::simple_display(llvm::raw_ostream &out,
20922098
const ScopeCreator *scopeCreator) {
20932099
scopeCreator->print(out);
20942100
}
2101+
2102+
//----------------------------------------------------------------------------//
2103+
// ExpandASTScopeRequest computation.
2104+
//----------------------------------------------------------------------------//
2105+
2106+
bool ExpandASTScopeRequest::isCached() const {
2107+
ASTScopeImpl *scope = std::get<0>(getStorage());
2108+
ScopeCreator *scopeCreator = std::get<1>(getStorage());
2109+
return !scope->isExpansionNeeded(*scopeCreator);
2110+
}
2111+
2112+
Optional<ASTScopeImpl *> ExpandASTScopeRequest::getCachedResult() const {
2113+
return std::get<0>(getStorage());
2114+
}

lib/AST/ASTScopeLookup.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ llvm::SmallVector<const ASTScopeImpl *, 0> ASTScopeImpl::unqualifiedLookup(
4040
SourceFile *sourceFile, const DeclName name, const SourceLoc loc,
4141
const DeclContext *const startingContext, DeclConsumer consumer) {
4242
SmallVector<const ASTScopeImpl *, 0> history;
43-
4443
const auto *start =
4544
findStartingScopeForLookup(sourceFile, name, loc, startingContext);
4645
if (start)
@@ -59,7 +58,6 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup(
5958

6059
auto *const fileScope = sourceFile->getScope().impl;
6160
// Parser may have added decls to source file, since previous lookup
62-
fileScope->addNewDeclsToScopeTree();
6361
if (name.isOperator())
6462
return fileScope; // operators always at file scope
6563

@@ -116,7 +114,7 @@ ASTScopeImpl::findInnermostEnclosingScope(SourceLoc loc,
116114
const ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl(
117115
SourceLoc loc, NullablePtr<raw_ostream> os, SourceManager &sourceMgr,
118116
ScopeCreator &scopeCreator) {
119-
reexpandIfObsolete(scopeCreator);
117+
expandAndBeCurrentDetectingRecursion(scopeCreator);
120118
auto child = findChildContaining(loc, sourceMgr);
121119
if (!child)
122120
return this;

lib/AST/ASTScopePrinting.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,5 +204,9 @@ bool IterableTypeScope::doesDeclHaveABody() const {
204204

205205
void ast_scope::simple_display(llvm::raw_ostream &out,
206206
const ASTScopeImpl *scope) {
207-
scope->print(out);
207+
// Cannot call scope->print(out) because printing an ASTFunctionBodyScope
208+
// gets the source range which can cause a request to parse it.
209+
// That in turn causes the request dependency printing code to blow up
210+
// as the AnyRequest ends up with a null.
211+
out << scope->getClassName() << "\n";
208212
}

0 commit comments

Comments
 (0)