Skip to content

Commit 47a2bf3

Browse files
committed
[NFC] One-Shot Name Lookup
Simplify lookupDirect to attempt one-shot name lookup based on some ideas Slava had. This means we'll try to perform a cache fill up front, then access the table rather than assuming the table is always (relatively) up to date and filling when we miss the first cache access. This avoids a walk over the deserialized members of an extension that fails named lazy member loading. Instead, we eagerly page the members of the extension into the table and remove it from consideration for lazy member loading entirely. In the future, we can convince the Clang Importer to avoid falling off the lazy member loading happy path.
1 parent 5ff9586 commit 47a2bf3

File tree

3 files changed

+54
-65
lines changed

3 files changed

+54
-65
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3300,6 +3300,10 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
33003300
/// so that it can also be added to the lookup table (if needed).
33013301
void addedMember(Decl *member);
33023302

3303+
/// Note that we have added an extension into the nominal type,
3304+
/// so that its members can eventually be added to the lookup table.
3305+
void addedExtension(ExtensionDecl *ext);
3306+
33033307
/// A lookup table used to find the protocol conformances of
33043308
/// a given nominal type.
33053309
mutable ConformanceLookupTable *ConformanceTable = nullptr;

lib/AST/Decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3664,12 +3664,16 @@ void NominalTypeDecl::addExtension(ExtensionDecl *extension) {
36643664
if (!FirstExtension) {
36653665
FirstExtension = extension;
36663666
LastExtension = extension;
3667+
3668+
addedExtension(extension);
36673669
return;
36683670
}
36693671

36703672
// Add to the end of the list.
36713673
LastExtension->NextExtension.setPointer(extension);
36723674
LastExtension = extension;
3675+
3676+
addedExtension(extension);
36733677
}
36743678

36753679
ArrayRef<VarDecl *> NominalTypeDecl::getStoredProperties() const {

lib/AST/NameLookup.cpp

Lines changed: 46 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,25 +1028,25 @@ void MemberLookupTable::updateLookupTable(NominalTypeDecl *nominal) {
10281028
}
10291029
}
10301030

1031-
void NominalTypeDecl::addedMember(Decl *member) {
1032-
auto *vd = dyn_cast<ValueDecl>(member);
1033-
if (!vd)
1034-
return;
1031+
void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
1032+
if (!LookupTable) return;
10351033

1034+
if (ext->hasLazyMembers()) {
1035+
LookupTable->addMembers(ext->getCurrentMembersWithoutLoading());
1036+
} else {
1037+
LookupTable->addMembers(ext->getMembers());
1038+
}
1039+
}
1040+
1041+
void NominalTypeDecl::addedMember(Decl *member) {
10361042
// If we have a lookup table, add the new member to it. If not, we'll pick up
10371043
// this member when we first create the table.
1038-
if (auto *lookup = LookupTable) {
1039-
if (hasLazyMembers()) {
1040-
// If we have lazy members, only add the new member to the lookup
1041-
// table if we already have another member with the same name.
1042-
// The presence of a lookup table entry indicates that the
1043-
// nominal as well as all extensions have already been searched.
1044-
if (lookup->find(vd->getBaseName()) == lookup->end())
1045-
return;
1046-
}
1044+
auto *vd = dyn_cast<ValueDecl>(member);
1045+
auto *lookup = LookupTable;
1046+
if (!vd || !lookup)
1047+
return;
10471048

1048-
lookup->addMember(vd);
1049-
}
1049+
lookup->addMember(vd);
10501050
}
10511051

10521052
void ExtensionDecl::addedMember(Decl *member) {
@@ -1079,8 +1079,8 @@ void ExtensionDecl::addedMember(Decl *member) {
10791079
// │ExtensionDecl *LastExtension ─┼───────┐│ │ └───┐
10801080
// │ │ ││ └──────────────────────┐│
10811081
// │MemberLookupTable *LookupTable├─┐ ││ ││
1082-
// │bool LookupTableComplete │ │ ││ ┌─────────────────┐ ││
1083-
// └──────────────────────────────┘ │ ││ │ExtensionDecl │ ││
1082+
// └──────────────────────────────┘ │ ││ ┌─────────────────┐ ││
1083+
// │ ││ │ExtensionDecl │ ││
10841084
// │ ││ │------------- │ ││
10851085
// ┌─────────────┘ │└────▶│ExtensionDecl │ ││
10861086
// │ │ │ *NextExtension ├──┐ ││
@@ -1141,34 +1141,27 @@ populateLookupTableEntryFromLazyIDCLoader(ASTContext &ctx,
11411141
}
11421142
}
11431143

1144-
static void populateLookupTableEntryFromCurrentMembers(
1145-
ASTContext &ctx, MemberLookupTable &LookupTable, DeclBaseName name,
1146-
IterableDeclContext *IDC) {
1147-
for (auto m : IDC->getMembers()) {
1148-
if (auto v = dyn_cast<ValueDecl>(m)) {
1149-
if (v->getBaseName() == name) {
1150-
LookupTable.addMember(m);
1151-
}
1152-
}
1153-
}
1154-
}
1155-
11561144
static void
11571145
populateLookupTableEntryFromExtensions(ASTContext &ctx,
11581146
MemberLookupTable &table,
11591147
NominalTypeDecl *nominal,
11601148
DeclBaseName name) {
11611149
for (auto e : nominal->getExtensions()) {
1162-
// If we can retrieve the members of this extension without deserializing
1163-
// anything, do so now.
1164-
if (!e->wasDeserialized() && !e->hasClangNode()) {
1165-
populateLookupTableEntryFromCurrentMembers(ctx, table, name, e);
1150+
// If there's no lazy members to look at, all the members of this extension
1151+
// are present in the lookup table.
1152+
if (!e->hasLazyMembers()) {
11661153
continue;
11671154
}
11681155

1156+
assert(e->wasDeserialized() || e->hasClangNode() &&
1157+
"Extension without deserializable content has lazy members!");
11691158
assert(!e->hasUnparsedMembers());
1159+
1160+
// Try lazy loading. If that fails, then we fall back by loading the
1161+
// entire extension. FIXME: It's rather unfortunate that we fall off the
1162+
// happy path because the Clang Importer can't handle lazy import-as-member.
11701163
if (populateLookupTableEntryFromLazyIDCLoader(ctx, table, name, e)) {
1171-
populateLookupTableEntryFromCurrentMembers(ctx, table, name, e);
1164+
e->loadAllMembers();
11721165
}
11731166
}
11741167
}
@@ -1189,19 +1182,18 @@ void NominalTypeDecl::prepareLookupTable() {
11891182

11901183
// Lazy members: if the table needs population, populate the table _only
11911184
// from those members already in the IDC member list_ such as implicits or
1192-
// globals-as-members, then update table entries from the extensions that
1193-
// have the same names as any such initial-population members.
1185+
// globals-as-members.
11941186
LookupTable->addMembers(getCurrentMembersWithoutLoading());
1195-
1196-
llvm::SmallSet<DeclBaseName, 4> baseNamesPresent;
1197-
for (auto entry : *LookupTable) {
1198-
auto baseName = entry.getFirst().getBaseName();
1199-
if (!baseNamesPresent.insert(baseName).second)
1187+
for (auto e : getExtensions()) {
1188+
// If we can lazy-load this extension, only take the members we've loaded
1189+
// so far.
1190+
if (e->wasDeserialized() || e->hasClangNode()) {
1191+
LookupTable->addMembers(e->getCurrentMembersWithoutLoading());
12001192
continue;
1193+
}
12011194

1202-
populateLookupTableEntryFromExtensions(getASTContext(),
1203-
*LookupTable,
1204-
this, baseName);
1195+
// Else, load all the members into the table.
1196+
LookupTable->addMembers(e->getMembers());
12051197
}
12061198
} else {
12071199
LookupTable->addMembers(getMembers());
@@ -1261,8 +1253,9 @@ NominalTypeDecl::lookupDirect(DeclName name,
12611253
DeclName name) -> Optional<TinyPtrVector<ValueDecl *>> {
12621254
// Look for a declaration with this name.
12631255
auto known = table->find(name);
1264-
if (known == table->end())
1256+
if (known == table->end()) {
12651257
return None;
1258+
}
12661259

12671260
// We found something; return it.
12681261
return maybeFilterOutAttrImplements(known->second, name,
@@ -1282,29 +1275,17 @@ NominalTypeDecl::lookupDirect(DeclName name,
12821275

12831276
if (!useNamedLazyMemberLoading) {
12841277
updateLookupTable(LookupTable);
1285-
}
1286-
1287-
// Look for a declaration with this name.
1288-
if (auto lookup = tryCacheLookup(LookupTable, name))
1289-
return lookup.getValue();
1290-
1291-
if (!useNamedLazyMemberLoading) {
1292-
return { };
1293-
}
1294-
1295-
// If we get here, we had a cache-miss and _are_ using
1296-
// NamedLazyMemberLoading. Try to populate a _single_ entry in the
1297-
// MemberLookupTable from both this nominal and all of its extensions, and
1298-
// retry.
1299-
auto &Table = *LookupTable;
1300-
if (populateLookupTableEntryFromLazyIDCLoader(ctx, Table,
1301-
name.getBaseName(), this)) {
1302-
updateLookupTable(LookupTable);
13031278
} else {
1304-
populateLookupTableEntryFromExtensions(ctx, Table, this,
1305-
name.getBaseName());
1279+
if (populateLookupTableEntryFromLazyIDCLoader(ctx, *LookupTable,
1280+
name.getBaseName(), this)) {
1281+
updateLookupTable(LookupTable);
1282+
} else {
1283+
populateLookupTableEntryFromExtensions(ctx, *LookupTable, this,
1284+
name.getBaseName());
1285+
}
13061286
}
13071287

1288+
// Look for a declaration with this name.
13081289
return tryCacheLookup(LookupTable, name)
13091290
.getValueOr(TinyPtrVector<ValueDecl *>());
13101291
}

0 commit comments

Comments
 (0)