Skip to content

Commit 4a943ab

Browse files
authored
Merge pull request swiftlang#28845 from CodaFi/a-little-looksie
Refactor Direct Lookup
2 parents 71697c3 + 1a9bdaf commit 4a943ab

File tree

3 files changed

+92
-137
lines changed

3 files changed

+92
-137
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3281,28 +3281,16 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
32813281
/// its extensions.
32823282
///
32833283
/// The table itself is lazily constructed and updated when
3284-
/// lookupDirect() is called. The bit indicates whether the lookup
3285-
/// table has already added members by walking the declarations in
3286-
/// scope; it should be manipulated through \c isLookupTablePopulated()
3287-
/// and \c setLookupTablePopulated().
3288-
llvm::PointerIntPair<MemberLookupTable *, 1, bool> LookupTable;
3284+
/// lookupDirect() is called.
3285+
MemberLookupTable *LookupTable = nullptr;
32893286

32903287
/// Prepare the lookup table to make it ready for lookups.
32913288
void prepareLookupTable();
32923289

3293-
/// True if the entries in \c LookupTable are complete--that is, if a
3294-
/// name is present, it contains all members with that name.
3295-
bool isLookupTablePopulated() const;
3296-
void setLookupTablePopulated(bool value);
3297-
32983290
/// Note that we have added a member into the iterable declaration context,
32993291
/// so that it can also be added to the lookup table (if needed).
33003292
void addedMember(Decl *member);
33013293

3302-
/// Note that we have added an extension into the nominal type,
3303-
/// so that its members can eventually be added to the lookup table.
3304-
void addedExtension(ExtensionDecl *ext);
3305-
33063294
/// A lookup table used to find the protocol conformances of
33073295
/// a given nominal type.
33083296
mutable ConformanceLookupTable *ConformanceTable = nullptr;
@@ -3322,7 +3310,7 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
33223310
friend class DeclContext;
33233311
friend class IterableDeclContext;
33243312
friend ArrayRef<ValueDecl *>
3325-
ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const;
3313+
ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const;
33263314

33273315
protected:
33283316
Type DeclaredTy;

lib/AST/Decl.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3660,8 +3660,6 @@ void NominalTypeDecl::addExtension(ExtensionDecl *extension) {
36603660
// Add to the end of the list.
36613661
LastExtension->NextExtension.setPointer(extension);
36623662
LastExtension = extension;
3663-
3664-
addedExtension(extension);
36653663
}
36663664

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

lib/AST/NameLookup.cpp

Lines changed: 89 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,9 +1048,9 @@ void NominalTypeDecl::addedMember(Decl *member) {
10481048
if (!vd)
10491049
return;
10501050

1051-
// If we have a lookup table, add the new member to it.
1052-
auto *lookup = LookupTable.getPointer();
1053-
if (lookup && isLookupTablePopulated()) {
1051+
// If we have a lookup table, add the new member to it. If not, we'll pick up
1052+
// this member when we first create the table.
1053+
if (auto *lookup = LookupTable) {
10541054
if (hasLazyMembers()) {
10551055
// If we have lazy members, only add the new member to the lookup
10561056
// table if we already have another member with the same name.
@@ -1064,11 +1064,6 @@ void NominalTypeDecl::addedMember(Decl *member) {
10641064
}
10651065
}
10661066

1067-
void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
1068-
if (hasLazyMembers())
1069-
setLookupTablePopulated(false);
1070-
}
1071-
10721067
void ExtensionDecl::addedMember(Decl *member) {
10731068
// If this extension has already been bound to a nominal, add the new member
10741069
// to the nominal's lookup table.
@@ -1133,16 +1128,15 @@ void ExtensionDecl::addedMember(Decl *member) {
11331128
//
11341129
// If the IDC list is later populated and/or an extension is added _after_
11351130
// MemberLookupTable is constructed (and possibly has entries in it),
1136-
// MemberLookupTable is purged and reconstructed from IDC's list.
1131+
// MemberLookupTable is incrementally reconstituted with new members.
11371132

11381133
static bool
11391134
populateLookupTableEntryFromLazyIDCLoader(ASTContext &ctx,
11401135
MemberLookupTable &LookupTable,
11411136
DeclBaseName name,
11421137
IterableDeclContext *IDC) {
1143-
if (IDC->isLoadingLazyMembers()) {
1144-
return false;
1145-
}
1138+
assert(!IDC->isLoadingLazyMembers() &&
1139+
"Re-entrant member loading is not supported!");
11461140
IDC->setLoadingLazyMembers(true);
11471141
auto ci = ctx.getOrCreateLazyIterableContextData(IDC,
11481142
/*lazyLoader=*/nullptr);
@@ -1182,64 +1176,53 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx,
11821176
NominalTypeDecl *nominal,
11831177
DeclBaseName name) {
11841178
for (auto e : nominal->getExtensions()) {
1185-
if (e->wasDeserialized() || e->hasClangNode()) {
1186-
assert(!e->hasUnparsedMembers());
1187-
if (populateLookupTableEntryFromLazyIDCLoader(ctx, table,
1188-
name, e)) {
1189-
populateLookupTableEntryFromCurrentMembers(ctx, table, name, e);
1190-
}
1191-
} else {
1179+
// If we can retrieve the members of this extension without deserializing
1180+
// anything, do so now.
1181+
if (!e->wasDeserialized() && !e->hasClangNode()) {
11921182
populateLookupTableEntryFromCurrentMembers(ctx, table, name, e);
1183+
continue;
11931184
}
1194-
}
1195-
}
1196-
1197-
bool NominalTypeDecl::isLookupTablePopulated() const {
1198-
return LookupTable.getInt();
1199-
}
12001185

1201-
void NominalTypeDecl::setLookupTablePopulated(bool value) {
1202-
LookupTable.setInt(value);
1186+
assert(!e->hasUnparsedMembers());
1187+
if (populateLookupTableEntryFromLazyIDCLoader(ctx, table, name, e)) {
1188+
populateLookupTableEntryFromCurrentMembers(ctx, table, name, e);
1189+
}
1190+
}
12031191
}
12041192

12051193
void NominalTypeDecl::prepareLookupTable() {
1206-
// If we haven't allocated the lookup table yet, do so now.
1207-
if (!LookupTable.getPointer()) {
1208-
auto &ctx = getASTContext();
1209-
LookupTable.setPointer(new (ctx) MemberLookupTable(ctx));
1194+
// If we have already allocated the lookup table, then there's nothing further
1195+
// to do.
1196+
if (LookupTable) {
1197+
return;
12101198
}
12111199

1200+
// Otherwise start the first fill.
1201+
auto &ctx = getASTContext();
1202+
LookupTable = new (ctx) MemberLookupTable(ctx);
1203+
12121204
if (hasLazyMembers()) {
12131205
assert(!hasUnparsedMembers());
12141206

12151207
// Lazy members: if the table needs population, populate the table _only
12161208
// from those members already in the IDC member list_ such as implicits or
12171209
// globals-as-members, then update table entries from the extensions that
12181210
// have the same names as any such initial-population members.
1219-
if (!isLookupTablePopulated()) {
1220-
setLookupTablePopulated(true);
1221-
LookupTable.getPointer()->addMembers(getCurrentMembersWithoutLoading());
1211+
LookupTable->addMembers(getCurrentMembersWithoutLoading());
12221212

1223-
llvm::SetVector<DeclBaseName> baseNamesPresent;
1224-
for (auto entry : *LookupTable.getPointer()) {
1225-
baseNamesPresent.insert(entry.getFirst().getBaseName());
1226-
}
1213+
llvm::SmallSet<DeclBaseName, 4> baseNamesPresent;
1214+
for (auto entry : *LookupTable) {
1215+
auto baseName = entry.getFirst().getBaseName();
1216+
if (!baseNamesPresent.insert(baseName).second)
1217+
continue;
12271218

1228-
for (auto baseName : baseNamesPresent) {
1229-
populateLookupTableEntryFromExtensions(getASTContext(),
1230-
*LookupTable.getPointer(),
1231-
this, baseName);
1232-
}
1219+
populateLookupTableEntryFromExtensions(getASTContext(),
1220+
*LookupTable,
1221+
this, baseName);
12331222
}
1234-
12351223
} else {
1236-
// No lazy members: if the table needs population, populate the table
1237-
// en-masse; and in either case update the extensions.
1238-
if (!isLookupTablePopulated()) {
1239-
setLookupTablePopulated(true);
1240-
LookupTable.getPointer()->addMembers(getMembers());
1241-
}
1242-
LookupTable.getPointer()->updateLookupTable(this);
1224+
LookupTable->addMembers(getMembers());
1225+
LookupTable->updateLookupTable(this);
12431226
}
12441227
}
12451228

@@ -1265,96 +1248,82 @@ maybeFilterOutAttrImplements(TinyPtrVector<ValueDecl *> decls,
12651248
return result;
12661249
}
12671250

1268-
TinyPtrVector<ValueDecl *> NominalTypeDecl::lookupDirect(
1269-
DeclName name,
1270-
OptionSet<LookupDirectFlags> flags) {
1251+
TinyPtrVector<ValueDecl *>
1252+
NominalTypeDecl::lookupDirect(DeclName name,
1253+
OptionSet<LookupDirectFlags> flags) {
12711254
ASTContext &ctx = getASTContext();
12721255
if (auto s = ctx.Stats) {
12731256
++s->getFrontendCounters().NominalTypeLookupDirectCount;
12741257
}
12751258

12761259
// We only use NamedLazyMemberLoading when a user opts-in and we have
12771260
// not yet loaded all the members into the IDC list in the first place.
1278-
bool useNamedLazyMemberLoading = (ctx.LangOpts.NamedLazyMemberLoading &&
1279-
hasLazyMembers());
1261+
const bool useNamedLazyMemberLoading = (ctx.LangOpts.NamedLazyMemberLoading &&
1262+
hasLazyMembers());
12801263

1281-
bool includeAttrImplements =
1264+
const bool includeAttrImplements =
12821265
flags.contains(LookupDirectFlags::IncludeAttrImplements);
12831266

12841267
LLVM_DEBUG(llvm::dbgs() << getNameStr() << ".lookupDirect("
1285-
<< name << ")"
1286-
<< ", isLookupTablePopulated()=" << isLookupTablePopulated()
1287-
<< ", hasLazyMembers()=" << hasLazyMembers()
1288-
<< ", useNamedLazyMemberLoading=" << useNamedLazyMemberLoading
1289-
<< "\n");
1290-
1291-
// We check the LookupTable at most twice, possibly treating a miss in the
1292-
// first try as a cache-miss that we then do a cache-fill on, and retry.
1293-
for (int i = 0; i < 2; ++i) {
1294-
1295-
// First, if we're _not_ doing NamedLazyMemberLoading, we make sure we've
1296-
// populated the IDC and brought it up to date with any extensions. This
1297-
// will flip the hasLazyMembers() flag to false as well.
1298-
if (!useNamedLazyMemberLoading) {
1299-
// It's possible that the lookup table exists but has information in it
1300-
// that is either currently out of date or soon to be out of date.
1301-
// This can happen two ways:
1302-
//
1303-
// - We've not yet indexed the members we have (isLookupTablePopulated()
1304-
// is zero).
1305-
//
1306-
// - We've still got more lazy members left to load; this can happen
1307-
// even if we _did_ index some members.
1308-
//
1309-
// In either of these cases, we want to reset the table to empty and
1310-
// mark it as needing reconstruction.
1311-
if (LookupTable.getPointer() &&
1312-
(hasLazyMembers() || !isLookupTablePopulated())) {
1313-
LookupTable.getPointer()->clear();
1314-
setLookupTablePopulated(false);
1315-
}
1316-
1317-
(void)getMembers();
1268+
<< name << ")"
1269+
<< ", hasLazyMembers()=" << hasLazyMembers()
1270+
<< ", useNamedLazyMemberLoading=" << useNamedLazyMemberLoading
1271+
<< "\n");
13181272

1319-
// Make sure we have the complete list of members (in this nominal and in
1320-
// all extensions).
1321-
for (auto E : getExtensions())
1322-
(void)E->getMembers();
1323-
}
13241273

1325-
// Next, in all cases, prepare the lookup table for use, possibly
1326-
// repopulating it from the IDC if the IDC member list has just grown.
1327-
prepareLookupTable();
1274+
prepareLookupTable();
13281275

1276+
auto tryCacheLookup =
1277+
[=](MemberLookupTable *table,
1278+
DeclName name) -> Optional<TinyPtrVector<ValueDecl *>> {
13291279
// Look for a declaration with this name.
1330-
auto known = LookupTable.getPointer()->find(name);
1280+
auto known = table->find(name);
1281+
if (known == table->end())
1282+
return None;
13311283

13321284
// We found something; return it.
1333-
if (known != LookupTable.getPointer()->end())
1334-
return maybeFilterOutAttrImplements(known->second, name,
1335-
includeAttrImplements);
1285+
return maybeFilterOutAttrImplements(known->second, name,
1286+
includeAttrImplements);
1287+
};
13361288

1337-
// If we have no more second chances, stop now.
1338-
if (!useNamedLazyMemberLoading || i > 0)
1339-
break;
1289+
auto updateLookupTable = [this](MemberLookupTable *table) {
1290+
// Make sure we have the complete list of members (in this nominal and in
1291+
// all extensions).
1292+
(void)getMembers();
13401293

1341-
// If we get here, we had a cache-miss and _are_ using
1342-
// NamedLazyMemberLoading. Try to populate a _single_ entry in the
1343-
// MemberLookupTable from both this nominal and all of its extensions, and
1344-
// retry. Any failure to load here flips the useNamedLazyMemberLoading to
1345-
// false, and we fall back to loading all members during the retry.
1346-
auto &Table = *LookupTable.getPointer();
1347-
if (populateLookupTableEntryFromLazyIDCLoader(ctx, Table,
1348-
name.getBaseName(), this)) {
1349-
useNamedLazyMemberLoading = false;
1350-
} else {
1351-
populateLookupTableEntryFromExtensions(ctx, Table, this,
1352-
name.getBaseName());
1353-
}
1294+
for (auto E : getExtensions())
1295+
(void)E->getMembers();
1296+
1297+
LookupTable->updateLookupTable(this);
1298+
};
1299+
1300+
if (!useNamedLazyMemberLoading) {
1301+
updateLookupTable(LookupTable);
13541302
}
13551303

1356-
// None of our attempts found anything.
1357-
return { };
1304+
// Look for a declaration with this name.
1305+
if (auto lookup = tryCacheLookup(LookupTable, name))
1306+
return lookup.getValue();
1307+
1308+
if (!useNamedLazyMemberLoading) {
1309+
return { };
1310+
}
1311+
1312+
// If we get here, we had a cache-miss and _are_ using
1313+
// NamedLazyMemberLoading. Try to populate a _single_ entry in the
1314+
// MemberLookupTable from both this nominal and all of its extensions, and
1315+
// retry.
1316+
auto &Table = *LookupTable;
1317+
if (populateLookupTableEntryFromLazyIDCLoader(ctx, Table,
1318+
name.getBaseName(), this)) {
1319+
updateLookupTable(LookupTable);
1320+
} else {
1321+
populateLookupTableEntryFromExtensions(ctx, Table, this,
1322+
name.getBaseName());
1323+
}
1324+
1325+
return tryCacheLookup(LookupTable, name)
1326+
.getValueOr(TinyPtrVector<ValueDecl *>());
13581327
}
13591328

13601329
void ClassDecl::createObjCMethodLookup() {

0 commit comments

Comments
 (0)