Skip to content

Commit af30902

Browse files
authored
Merge pull request swiftlang#26865 from slavapestov/faster-module-name-lookup
Faster module name lookup
2 parents 6e25fd9 + d280ae4 commit af30902

17 files changed

+217
-574
lines changed

include/swift/AST/ImportCache.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ class ImportSet final :
5151
public llvm::FoldingSetNode,
5252
private llvm::TrailingObjects<ImportSet, ModuleDecl::ImportedModule> {
5353
friend TrailingObjects;
54-
friend ImportCache;
54+
friend class ImportCache;
5555

56-
unsigned NumTopLevelImports;
56+
unsigned HasHeaderImportModule : 1;
57+
unsigned NumTopLevelImports : 31;
5758
unsigned NumTransitiveImports;
5859

59-
ImportSet(ArrayRef<ModuleDecl::ImportedModule> topLevelImports,
60+
ImportSet(bool hasHeaderImportModule,
61+
ArrayRef<ModuleDecl::ImportedModule> topLevelImports,
6062
ArrayRef<ModuleDecl::ImportedModule> transitiveImports);
6163

6264
ImportSet(const ImportSet &) = delete;
@@ -74,6 +76,13 @@ class ImportSet final :
7476
return NumTopLevelImports + NumTransitiveImports;
7577
}
7678

79+
/// This is a bit of a hack to make module name lookup work properly.
80+
/// If our import set includes the ClangImporter's special header import
81+
/// module, we have to check it first, before any other imported module.
82+
bool hasHeaderImportModule() const {
83+
return HasHeaderImportModule;
84+
}
85+
7786
ArrayRef<ModuleDecl::ImportedModule> getTopLevelImports() const {
7887
return {getTrailingObjects<ModuleDecl::ImportedModule>(),
7988
NumTopLevelImports};
@@ -184,6 +193,8 @@ class alignas(ModuleDecl::ImportedModule) ImportCache {
184193
}
185194
};
186195

196+
ArrayRef<ModuleDecl::ImportedModule> getAllImports(const DeclContext *dc);
197+
187198
} // namespace namelookup
188199

189200
} // namespace swift

include/swift/AST/Module.h

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -519,45 +519,6 @@ class ModuleDecl : public DeclContext, public TypeDecl {
519519
/// shadowed clang module.
520520
void getDisplayDecls(SmallVectorImpl<Decl*> &results) const;
521521

522-
/// @{
523-
524-
/// Perform an action for every module visible from this module.
525-
///
526-
/// This only includes modules with at least one declaration visible: if two
527-
/// import access paths are incompatible, the indirect module will be skipped.
528-
/// Modules that can't be used for lookup (including Clang submodules at the
529-
/// time this comment was written) are also skipped under certain
530-
/// circumstances.
531-
///
532-
/// \param topLevelAccessPath If present, include the top-level module in the
533-
/// results, with the given access path.
534-
/// \param fn A callback of type bool(ImportedModule) or void(ImportedModule).
535-
/// Return \c false to abort iteration.
536-
///
537-
/// \return True if the traversal ran to completion, false if it ended early
538-
/// due to the callback.
539-
bool forAllVisibleModules(AccessPathTy topLevelAccessPath,
540-
llvm::function_ref<bool(ImportedModule)> fn) const;
541-
542-
bool forAllVisibleModules(AccessPathTy topLevelAccessPath,
543-
llvm::function_ref<void(ImportedModule)> fn) const {
544-
return forAllVisibleModules(topLevelAccessPath,
545-
[=](const ImportedModule &import) -> bool {
546-
fn(import);
547-
return true;
548-
});
549-
}
550-
551-
template <typename Fn>
552-
bool forAllVisibleModules(AccessPathTy topLevelAccessPath,
553-
Fn &&fn) const {
554-
using RetTy = typename std::result_of<Fn(ImportedModule)>::type;
555-
llvm::function_ref<RetTy(ImportedModule)> wrapped{std::forward<Fn>(fn)};
556-
return forAllVisibleModules(topLevelAccessPath, wrapped);
557-
}
558-
559-
/// @}
560-
561522
using LinkLibraryCallback = llvm::function_ref<void(LinkLibrary)>;
562523

563524
/// Generate the list of libraries needed to link this module, based on its
@@ -817,39 +778,6 @@ class FileUnit : public DeclContext {
817778
virtual void
818779
collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {}
819780

820-
/// @{
821-
822-
/// Perform an action for every module visible from this file.
823-
///
824-
/// \param fn A callback of type bool(ImportedModule) or void(ImportedModule).
825-
/// Return \c false to abort iteration.
826-
///
827-
/// \return True if the traversal ran to completion, false if it ended early
828-
/// due to the callback.
829-
bool
830-
forAllVisibleModules(
831-
llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn) const;
832-
833-
bool
834-
forAllVisibleModules(
835-
llvm::function_ref<void(ModuleDecl::ImportedModule)> fn) const {
836-
return forAllVisibleModules([=](ModuleDecl::ImportedModule import) -> bool {
837-
fn(import);
838-
return true;
839-
});
840-
}
841-
842-
template <typename Fn>
843-
bool forAllVisibleModules(Fn &&fn) const {
844-
using RetTy = typename std::result_of<Fn(ModuleDecl::ImportedModule)>::type;
845-
llvm::function_ref<RetTy(ModuleDecl::ImportedModule)> wrapped{
846-
std::forward<Fn>(fn)
847-
};
848-
return forAllVisibleModules(wrapped);
849-
}
850-
851-
/// @}
852-
853781
/// True if this file contains the main class for the module.
854782
bool hasMainClass() const {
855783
return getMainClass();

include/swift/AST/ModuleNameLookup.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ enum class ResolutionKind {
3535
/// If non-overloadable decls are returned, this indicates ambiguous lookup.
3636
Overloadable,
3737

38-
/// Lookup should match a single decl.
39-
Exact,
40-
4138
/// Lookup should match a single decl that declares a type.
4239
TypesOnly
4340
};
@@ -62,16 +59,6 @@ void lookupInModule(const DeclContext *moduleOrFile,
6259
NLKind lookupKind, ResolutionKind resolutionKind,
6360
const DeclContext *moduleScopeContext);
6461

65-
template <typename Fn>
66-
void forAllVisibleModules(const DeclContext *DC, const Fn &fn) {
67-
DeclContext *moduleScope = DC->getModuleScopeContext();
68-
if (auto file = dyn_cast<FileUnit>(moduleScope))
69-
file->forAllVisibleModules(fn);
70-
else
71-
cast<ModuleDecl>(moduleScope)
72-
->forAllVisibleModules(ModuleDecl::AccessPathTy(), fn);
73-
}
74-
7562
/// Performs a qualified lookup into the given module and, if necessary, its
7663
/// reexports, observing proper shadowing rules.
7764
void

lib/AST/ImportCache.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
using namespace swift;
2424
using namespace namelookup;
2525

26-
ImportSet::ImportSet(ArrayRef<ModuleDecl::ImportedModule> topLevelImports,
26+
ImportSet::ImportSet(bool hasHeaderImportModule,
27+
ArrayRef<ModuleDecl::ImportedModule> topLevelImports,
2728
ArrayRef<ModuleDecl::ImportedModule> transitiveImports)
28-
: NumTopLevelImports(topLevelImports.size()),
29+
: HasHeaderImportModule(hasHeaderImportModule),
30+
NumTopLevelImports(topLevelImports.size()),
2931
NumTransitiveImports(transitiveImports.size()) {
3032
auto buffer = getTrailingObjects<ModuleDecl::ImportedModule>();
3133
std::uninitialized_copy(topLevelImports.begin(), topLevelImports.end(),
@@ -78,6 +80,11 @@ static void collectExports(ModuleDecl::ImportedModule next,
7880
ImportSet &
7981
ImportCache::getImportSet(ASTContext &ctx,
8082
ArrayRef<ModuleDecl::ImportedModule> imports) {
83+
bool hasHeaderImportModule = false;
84+
ModuleDecl *headerImportModule = nullptr;
85+
if (auto *loader = ctx.getClangModuleLoader())
86+
headerImportModule = loader->getImportedHeaderModule();
87+
8188
SmallVector<ModuleDecl::ImportedModule, 4> topLevelImports;
8289

8390
SmallVector<ModuleDecl::ImportedModule, 4> transitiveImports;
@@ -88,6 +95,8 @@ ImportCache::getImportSet(ASTContext &ctx,
8895
continue;
8996

9097
topLevelImports.push_back(next);
98+
if (next.second == headerImportModule)
99+
hasHeaderImportModule = true;
91100
}
92101

93102
void *InsertPos = nullptr;
@@ -116,6 +125,9 @@ ImportCache::getImportSet(ASTContext &ctx,
116125
continue;
117126

118127
transitiveImports.push_back(next);
128+
if (next.second == headerImportModule)
129+
hasHeaderImportModule = true;
130+
119131
collectExports(next, stack);
120132
}
121133

@@ -131,7 +143,9 @@ ImportCache::getImportSet(ASTContext &ctx,
131143
sizeof(ModuleDecl::ImportedModule) * transitiveImports.size(),
132144
alignof(ImportSet), AllocationArena::Permanent);
133145

134-
auto *result = new (mem) ImportSet(topLevelImports, transitiveImports);
146+
auto *result = new (mem) ImportSet(hasHeaderImportModule,
147+
topLevelImports,
148+
transitiveImports);
135149
ImportSets.InsertNode(result, InsertPos);
136150

137151
return *result;
@@ -277,4 +291,10 @@ ImportCache::getAllAccessPathsNotShadowedBy(const ModuleDecl *mod,
277291
auto result = allocateArray(ctx, accessPaths);
278292
ShadowCache[key] = result;
279293
return result;
280-
};
294+
};
295+
296+
ArrayRef<ModuleDecl::ImportedModule>
297+
swift::namelookup::getAllImports(const DeclContext *dc) {
298+
return dc->getASTContext().getImportCache().getImportSet(dc)
299+
.getAllImports();
300+
}

lib/AST/Module.cpp

Lines changed: 25 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,110 +1375,47 @@ bool ModuleDecl::registerEntryPointFile(FileUnit *file, SourceLoc diagLoc,
13751375
return true;
13761376
}
13771377

1378-
template<bool respectVisibility>
1379-
static bool
1380-
forAllImportedModules(const ModuleDecl *topLevel,
1381-
ModuleDecl::AccessPathTy thisPath,
1382-
llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn) {
1383-
using ImportedModule = ModuleDecl::ImportedModule;
1384-
using AccessPathTy = ModuleDecl::AccessPathTy;
1385-
1386-
llvm::SmallSet<ImportedModule, 32, ModuleDecl::OrderImportedModules> visited;
1387-
SmallVector<ImportedModule, 32> stack;
1378+
void ModuleDecl::collectLinkLibraries(LinkLibraryCallback callback) const {
1379+
// FIXME: The proper way to do this depends on the decls used.
1380+
FORWARD(collectLinkLibraries, (callback));
1381+
}
1382+
1383+
void
1384+
SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {
1385+
llvm::SmallDenseSet<ModuleDecl *, 32> visited;
1386+
SmallVector<ModuleDecl::ImportedModule, 32> stack;
13881387

13891388
ModuleDecl::ImportFilter filter = ModuleDecl::ImportFilterKind::Public;
1390-
if (!respectVisibility)
1391-
filter |= ModuleDecl::ImportFilterKind::Private;
1389+
filter |= ModuleDecl::ImportFilterKind::Private;
1390+
1391+
auto *topLevel = getParentModule();
13921392

13931393
ModuleDecl::ImportFilter topLevelFilter = filter;
1394-
if (!respectVisibility)
1395-
topLevelFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
1394+
topLevelFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
13961395
topLevel->getImportedModules(stack, topLevelFilter);
13971396

13981397
// Make sure the top-level module is first; we want pre-order-ish traversal.
1399-
AccessPathTy overridingPath;
1400-
if (respectVisibility)
1401-
overridingPath = thisPath;
1402-
stack.emplace_back(overridingPath, const_cast<ModuleDecl *>(topLevel));
1398+
stack.emplace_back(ModuleDecl::AccessPathTy(),
1399+
const_cast<ModuleDecl *>(topLevel));
14031400

14041401
while (!stack.empty()) {
1405-
auto next = stack.pop_back_val();
1406-
1407-
// Filter any whole-module imports, and skip specific-decl imports if the
1408-
// import path doesn't match exactly.
1409-
if (next.first.empty() || !respectVisibility)
1410-
next.first = overridingPath;
1411-
else if (!overridingPath.empty() &&
1412-
!ModuleDecl::isSameAccessPath(next.first, overridingPath)) {
1413-
// If we ever allow importing non-top-level decls, it's possible the rule
1414-
// above isn't what we want.
1415-
assert(next.first.size() == 1 && "import of non-top-level decl");
1416-
continue;
1417-
}
1402+
auto next = stack.pop_back_val().second;
14181403

14191404
if (!visited.insert(next).second)
14201405
continue;
14211406

1422-
if (!fn(next))
1423-
return false;
1424-
1425-
if (respectVisibility)
1426-
next.second->getImportedModulesForLookup(stack);
1427-
else
1428-
next.second->getImportedModules(stack, filter);
1429-
}
1430-
1431-
return true;
1432-
}
1433-
1434-
bool
1435-
ModuleDecl::forAllVisibleModules(AccessPathTy thisPath,
1436-
llvm::function_ref<bool(ImportedModule)> fn) const {
1437-
return forAllImportedModules<true>(this, thisPath, fn);
1438-
}
1407+
if (next->getName() != getParentModule()->getName()) {
1408+
// Hack: Assume other REPL files already have their libraries linked.
1409+
if (!next->getFiles().empty())
1410+
if (auto *nextSource = dyn_cast<SourceFile>(next->getFiles().front()))
1411+
if (nextSource->Kind == SourceFileKind::REPL)
1412+
continue;
14391413

1440-
bool FileUnit::forAllVisibleModules(
1441-
llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn) const {
1442-
if (!getParentModule()->forAllVisibleModules(ModuleDecl::AccessPathTy(), fn))
1443-
return false;
1414+
next->collectLinkLibraries(callback);
1415+
}
14441416

1445-
if (auto SF = dyn_cast<SourceFile>(this)) {
1446-
// Handle privately visible modules as well.
1447-
ModuleDecl::ImportFilter importFilter;
1448-
importFilter |= ModuleDecl::ImportFilterKind::Private;
1449-
importFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
1450-
SmallVector<ModuleDecl::ImportedModule, 4> imports;
1451-
SF->getImportedModules(imports, importFilter);
1452-
for (auto importPair : imports)
1453-
if (!importPair.second->forAllVisibleModules(importPair.first, fn))
1454-
return false;
1417+
next->getImportedModules(stack, filter);
14551418
}
1456-
1457-
return true;
1458-
}
1459-
1460-
void ModuleDecl::collectLinkLibraries(LinkLibraryCallback callback) const {
1461-
// FIXME: The proper way to do this depends on the decls used.
1462-
FORWARD(collectLinkLibraries, (callback));
1463-
}
1464-
1465-
void
1466-
SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {
1467-
forAllImportedModules<false>(getParentModule(), /*thisPath*/{},
1468-
[=](ModuleDecl::ImportedModule import) -> bool {
1469-
swift::ModuleDecl *next = import.second;
1470-
if (next->getName() == getParentModule()->getName())
1471-
return true;
1472-
1473-
// Hack: Assume other REPL files already have their libraries linked.
1474-
if (!next->getFiles().empty())
1475-
if (auto *nextSource = dyn_cast<SourceFile>(next->getFiles().front()))
1476-
if (nextSource->Kind == SourceFileKind::REPL)
1477-
return true;
1478-
1479-
next->collectLinkLibraries(callback);
1480-
return true;
1481-
});
14821419
}
14831420

14841421
bool ModuleDecl::walk(ASTWalker &Walker) {

0 commit comments

Comments
 (0)