Skip to content

Commit 207c345

Browse files
committed
[Experiment] Stick a cache in front of lazy member loading
Add a cache of lazily-imported names so we don't run off and deserialize extensions multiple times. The cache indicates that the lookup table has a complete understanding of any given base name. As a consequence, it must be flushed when a new extension with lazy members is added to avoid returning inconsistent results. This should make lazy member cache misses much, much cheaper. In the best case, we'll avoid repeatedly crawling around on disk. In the average case, we'll have fallen off the lazy member loading path at some point for some extension and the lazily-complete cache will kick in to keep that one extension from pessimizing the rest. In the worst case - when an enormous amount of lookups for non-existent members occur - we'll probably balloon memory usage somewhat adding bogus members to the set.
1 parent 47a2bf3 commit 207c345

File tree

1 file changed

+42
-6
lines changed

1 file changed

+42
-6
lines changed

lib/AST/NameLookup.cpp

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,11 @@ class swift::MemberLookupTable {
880880
/// Lookup table mapping names to the set of declarations with that name.
881881
LookupTable Lookup;
882882

883+
/// The set of names of lazily-loaded members that the lookup table has a
884+
/// complete accounting of with respect to all known extensions of its
885+
/// parent nominal type.
886+
llvm::DenseSet<DeclBaseName> LazilyCompleteNames;
887+
883888
public:
884889
/// Create a new member lookup table.
885890
explicit MemberLookupTable(ASTContext &ctx);
@@ -893,6 +898,24 @@ class swift::MemberLookupTable {
893898
/// Add the given members to the lookup table.
894899
void addMembers(DeclRange members);
895900

901+
/// Returns \c true if the lookup table has a complete accounting of the
902+
/// given name.
903+
bool isLazilyComplete(DeclBaseName name) const {
904+
return LazilyCompleteNames.find(name) != LazilyCompleteNames.end();
905+
}
906+
907+
/// Mark a given lazily-loaded name as being complete.
908+
void markLazilyComplete(DeclBaseName name) {
909+
LazilyCompleteNames.insert(name);
910+
}
911+
912+
/// Clears the cache of lazily-complete names. This _must_ be called when
913+
/// new extensions with lazy members are added to the type, or direct lookup
914+
/// will return inconsistent or stale results.
915+
void clearLazilyCompleteCache() {
916+
LazilyCompleteNames.clear();
917+
}
918+
896919
/// Iterator into the lookup table.
897920
typedef LookupTable::iterator iterator;
898921

@@ -912,7 +935,11 @@ class swift::MemberLookupTable {
912935

913936
os << "Lookup:\n ";
914937
for (auto &pair : Lookup) {
915-
pair.getFirst().print(os) << ":\n ";
938+
pair.getFirst().print(os);
939+
if (isLazilyComplete(pair.getFirst().getBaseName())) {
940+
os << " (lazily complete)";
941+
}
942+
os << ":\n ";
916943
for (auto &decl : pair.getSecond()) {
917944
os << "- ";
918945
decl->dumpRef(os);
@@ -1033,6 +1060,7 @@ void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
10331060

10341061
if (ext->hasLazyMembers()) {
10351062
LookupTable->addMembers(ext->getCurrentMembersWithoutLoading());
1063+
LookupTable->clearLazilyCompleteCache();
10361064
} else {
10371065
LookupTable->addMembers(ext->getMembers());
10381066
}
@@ -1146,6 +1174,9 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx,
11461174
MemberLookupTable &table,
11471175
NominalTypeDecl *nominal,
11481176
DeclBaseName name) {
1177+
assert(!table.isLazilyComplete(name) &&
1178+
"Should not be searching extensions for complete name!");
1179+
11491180
for (auto e : nominal->getExtensions()) {
11501181
// If there's no lazy members to look at, all the members of this extension
11511182
// are present in the lookup table.
@@ -1275,14 +1306,19 @@ NominalTypeDecl::lookupDirect(DeclName name,
12751306

12761307
if (!useNamedLazyMemberLoading) {
12771308
updateLookupTable(LookupTable);
1278-
} else {
1279-
if (populateLookupTableEntryFromLazyIDCLoader(ctx, *LookupTable,
1280-
name.getBaseName(), this)) {
1309+
} else if (!LookupTable->isLazilyComplete(name.getBaseName())) {
1310+
// The lookup table believes it doesn't have a complete accounting of this
1311+
// name - either because we're never seen it before, or another extension
1312+
// was registered since the last time we searched. Ask the loaders to give
1313+
// us a hand.
1314+
auto &Table = *LookupTable;
1315+
DeclBaseName baseName(name.getBaseName());
1316+
if (populateLookupTableEntryFromLazyIDCLoader(ctx, Table, baseName, this)) {
12811317
updateLookupTable(LookupTable);
12821318
} else {
1283-
populateLookupTableEntryFromExtensions(ctx, *LookupTable, this,
1284-
name.getBaseName());
1319+
populateLookupTableEntryFromExtensions(ctx, Table, this, baseName);
12851320
}
1321+
Table.markLazilyComplete(baseName);
12861322
}
12871323

12881324
// Look for a declaration with this name.

0 commit comments

Comments
 (0)