Skip to content

Commit 1a9bdaf

Browse files
committed
Refactor Direct Name Lookup
The old name lookup would frequently try to flush and rebuild the name lookup cache. Instead, never flush the cache, and use the cache misses as an opportunity to load members and bring the lookup table up to date with any added extensions.
1 parent a50b940 commit 1a9bdaf

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
@@ -3278,28 +3278,16 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
32783278
/// its extensions.
32793279
///
32803280
/// The table itself is lazily constructed and updated when
3281-
/// lookupDirect() is called. The bit indicates whether the lookup
3282-
/// table has already added members by walking the declarations in
3283-
/// scope; it should be manipulated through \c isLookupTablePopulated()
3284-
/// and \c setLookupTablePopulated().
3285-
llvm::PointerIntPair<MemberLookupTable *, 1, bool> LookupTable;
3281+
/// lookupDirect() is called.
3282+
MemberLookupTable *LookupTable = nullptr;
32863283

32873284
/// Prepare the lookup table to make it ready for lookups.
32883285
void prepareLookupTable();
32893286

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

3299-
/// Note that we have added an extension into the nominal type,
3300-
/// so that its members can eventually be added to the lookup table.
3301-
void addedExtension(ExtensionDecl *ext);
3302-
33033291
/// A lookup table used to find the protocol conformances of
33043292
/// a given nominal type.
33053293
mutable ConformanceLookupTable *ConformanceTable = nullptr;
@@ -3319,7 +3307,7 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
33193307
friend class DeclContext;
33203308
friend class IterableDeclContext;
33213309
friend ArrayRef<ValueDecl *>
3322-
ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const;
3310+
ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const;
33233311

33243312
protected:
33253313
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
@@ -1041,9 +1041,9 @@ void NominalTypeDecl::addedMember(Decl *member) {
10411041
if (!vd)
10421042
return;
10431043

1044-
// If we have a lookup table, add the new member to it.
1045-
auto *lookup = LookupTable.getPointer();
1046-
if (lookup && isLookupTablePopulated()) {
1044+
// If we have a lookup table, add the new member to it. If not, we'll pick up
1045+
// this member when we first create the table.
1046+
if (auto *lookup = LookupTable) {
10471047
if (hasLazyMembers()) {
10481048
// If we have lazy members, only add the new member to the lookup
10491049
// table if we already have another member with the same name.
@@ -1057,11 +1057,6 @@ void NominalTypeDecl::addedMember(Decl *member) {
10571057
}
10581058
}
10591059

1060-
void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
1061-
if (hasLazyMembers())
1062-
setLookupTablePopulated(false);
1063-
}
1064-
10651060
void ExtensionDecl::addedMember(Decl *member) {
10661061
// If this extension has already been bound to a nominal, add the new member
10671062
// to the nominal's lookup table.
@@ -1126,16 +1121,15 @@ void ExtensionDecl::addedMember(Decl *member) {
11261121
//
11271122
// If the IDC list is later populated and/or an extension is added _after_
11281123
// MemberLookupTable is constructed (and possibly has entries in it),
1129-
// MemberLookupTable is purged and reconstructed from IDC's list.
1124+
// MemberLookupTable is incrementally reconstituted with new members.
11301125

11311126
static bool
11321127
populateLookupTableEntryFromLazyIDCLoader(ASTContext &ctx,
11331128
MemberLookupTable &LookupTable,
11341129
DeclBaseName name,
11351130
IterableDeclContext *IDC) {
1136-
if (IDC->isLoadingLazyMembers()) {
1137-
return false;
1138-
}
1131+
assert(!IDC->isLoadingLazyMembers() &&
1132+
"Re-entrant member loading is not supported!");
11391133
IDC->setLoadingLazyMembers(true);
11401134
auto ci = ctx.getOrCreateLazyIterableContextData(IDC,
11411135
/*lazyLoader=*/nullptr);
@@ -1175,64 +1169,53 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx,
11751169
NominalTypeDecl *nominal,
11761170
DeclBaseName name) {
11771171
for (auto e : nominal->getExtensions()) {
1178-
if (e->wasDeserialized() || e->hasClangNode()) {
1179-
assert(!e->hasUnparsedMembers());
1180-
if (populateLookupTableEntryFromLazyIDCLoader(ctx, table,
1181-
name, e)) {
1182-
populateLookupTableEntryFromCurrentMembers(ctx, table, name, e);
1183-
}
1184-
} else {
1172+
// If we can retrieve the members of this extension without deserializing
1173+
// anything, do so now.
1174+
if (!e->wasDeserialized() && !e->hasClangNode()) {
11851175
populateLookupTableEntryFromCurrentMembers(ctx, table, name, e);
1176+
continue;
11861177
}
1187-
}
1188-
}
1189-
1190-
bool NominalTypeDecl::isLookupTablePopulated() const {
1191-
return LookupTable.getInt();
1192-
}
11931178

1194-
void NominalTypeDecl::setLookupTablePopulated(bool value) {
1195-
LookupTable.setInt(value);
1179+
assert(!e->hasUnparsedMembers());
1180+
if (populateLookupTableEntryFromLazyIDCLoader(ctx, table, name, e)) {
1181+
populateLookupTableEntryFromCurrentMembers(ctx, table, name, e);
1182+
}
1183+
}
11961184
}
11971185

11981186
void NominalTypeDecl::prepareLookupTable() {
1199-
// If we haven't allocated the lookup table yet, do so now.
1200-
if (!LookupTable.getPointer()) {
1201-
auto &ctx = getASTContext();
1202-
LookupTable.setPointer(new (ctx) MemberLookupTable(ctx));
1187+
// If we have already allocated the lookup table, then there's nothing further
1188+
// to do.
1189+
if (LookupTable) {
1190+
return;
12031191
}
12041192

1193+
// Otherwise start the first fill.
1194+
auto &ctx = getASTContext();
1195+
LookupTable = new (ctx) MemberLookupTable(ctx);
1196+
12051197
if (hasLazyMembers()) {
12061198
assert(!hasUnparsedMembers());
12071199

12081200
// Lazy members: if the table needs population, populate the table _only
12091201
// from those members already in the IDC member list_ such as implicits or
12101202
// globals-as-members, then update table entries from the extensions that
12111203
// have the same names as any such initial-population members.
1212-
if (!isLookupTablePopulated()) {
1213-
setLookupTablePopulated(true);
1214-
LookupTable.getPointer()->addMembers(getCurrentMembersWithoutLoading());
1204+
LookupTable->addMembers(getCurrentMembersWithoutLoading());
12151205

1216-
llvm::SetVector<DeclBaseName> baseNamesPresent;
1217-
for (auto entry : *LookupTable.getPointer()) {
1218-
baseNamesPresent.insert(entry.getFirst().getBaseName());
1219-
}
1206+
llvm::SmallSet<DeclBaseName, 4> baseNamesPresent;
1207+
for (auto entry : *LookupTable) {
1208+
auto baseName = entry.getFirst().getBaseName();
1209+
if (!baseNamesPresent.insert(baseName).second)
1210+
continue;
12201211

1221-
for (auto baseName : baseNamesPresent) {
1222-
populateLookupTableEntryFromExtensions(getASTContext(),
1223-
*LookupTable.getPointer(),
1224-
this, baseName);
1225-
}
1212+
populateLookupTableEntryFromExtensions(getASTContext(),
1213+
*LookupTable,
1214+
this, baseName);
12261215
}
1227-
12281216
} else {
1229-
// No lazy members: if the table needs population, populate the table
1230-
// en-masse; and in either case update the extensions.
1231-
if (!isLookupTablePopulated()) {
1232-
setLookupTablePopulated(true);
1233-
LookupTable.getPointer()->addMembers(getMembers());
1234-
}
1235-
LookupTable.getPointer()->updateLookupTable(this);
1217+
LookupTable->addMembers(getMembers());
1218+
LookupTable->updateLookupTable(this);
12361219
}
12371220
}
12381221

@@ -1258,96 +1241,82 @@ maybeFilterOutAttrImplements(TinyPtrVector<ValueDecl *> decls,
12581241
return result;
12591242
}
12601243

1261-
TinyPtrVector<ValueDecl *> NominalTypeDecl::lookupDirect(
1262-
DeclName name,
1263-
OptionSet<LookupDirectFlags> flags) {
1244+
TinyPtrVector<ValueDecl *>
1245+
NominalTypeDecl::lookupDirect(DeclName name,
1246+
OptionSet<LookupDirectFlags> flags) {
12641247
ASTContext &ctx = getASTContext();
12651248
if (auto s = ctx.Stats) {
12661249
++s->getFrontendCounters().NominalTypeLookupDirectCount;
12671250
}
12681251

12691252
// We only use NamedLazyMemberLoading when a user opts-in and we have
12701253
// not yet loaded all the members into the IDC list in the first place.
1271-
bool useNamedLazyMemberLoading = (ctx.LangOpts.NamedLazyMemberLoading &&
1272-
hasLazyMembers());
1254+
const bool useNamedLazyMemberLoading = (ctx.LangOpts.NamedLazyMemberLoading &&
1255+
hasLazyMembers());
12731256

1274-
bool includeAttrImplements =
1257+
const bool includeAttrImplements =
12751258
flags.contains(LookupDirectFlags::IncludeAttrImplements);
12761259

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

1312-
// Make sure we have the complete list of members (in this nominal and in
1313-
// all extensions).
1314-
for (auto E : getExtensions())
1315-
(void)E->getMembers();
1316-
}
13171266

1318-
// Next, in all cases, prepare the lookup table for use, possibly
1319-
// repopulating it from the IDC if the IDC member list has just grown.
1320-
prepareLookupTable();
1267+
prepareLookupTable();
13211268

1269+
auto tryCacheLookup =
1270+
[=](MemberLookupTable *table,
1271+
DeclName name) -> Optional<TinyPtrVector<ValueDecl *>> {
13221272
// Look for a declaration with this name.
1323-
auto known = LookupTable.getPointer()->find(name);
1273+
auto known = table->find(name);
1274+
if (known == table->end())
1275+
return None;
13241276

13251277
// We found something; return it.
1326-
if (known != LookupTable.getPointer()->end())
1327-
return maybeFilterOutAttrImplements(known->second, name,
1328-
includeAttrImplements);
1278+
return maybeFilterOutAttrImplements(known->second, name,
1279+
includeAttrImplements);
1280+
};
13291281

1330-
// If we have no more second chances, stop now.
1331-
if (!useNamedLazyMemberLoading || i > 0)
1332-
break;
1282+
auto updateLookupTable = [this](MemberLookupTable *table) {
1283+
// Make sure we have the complete list of members (in this nominal and in
1284+
// all extensions).
1285+
(void)getMembers();
13331286

1334-
// If we get here, we had a cache-miss and _are_ using
1335-
// NamedLazyMemberLoading. Try to populate a _single_ entry in the
1336-
// MemberLookupTable from both this nominal and all of its extensions, and
1337-
// retry. Any failure to load here flips the useNamedLazyMemberLoading to
1338-
// false, and we fall back to loading all members during the retry.
1339-
auto &Table = *LookupTable.getPointer();
1340-
if (populateLookupTableEntryFromLazyIDCLoader(ctx, Table,
1341-
name.getBaseName(), this)) {
1342-
useNamedLazyMemberLoading = false;
1343-
} else {
1344-
populateLookupTableEntryFromExtensions(ctx, Table, this,
1345-
name.getBaseName());
1346-
}
1287+
for (auto E : getExtensions())
1288+
(void)E->getMembers();
1289+
1290+
LookupTable->updateLookupTable(this);
1291+
};
1292+
1293+
if (!useNamedLazyMemberLoading) {
1294+
updateLookupTable(LookupTable);
13471295
}
13481296

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

13531322
void ClassDecl::createObjCMethodLookup() {

0 commit comments

Comments
 (0)