Skip to content

Commit 8676d58

Browse files
committed
AST: Optimize ModuleDecl::isImportedAsWeakLinked()
1 parent 9ed1cd6 commit 8676d58

File tree

5 files changed

+67
-48
lines changed

5 files changed

+67
-48
lines changed

include/swift/AST/FileUnit.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,6 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
125125
const ModuleDecl *importedModule,
126126
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {};
127127

128-
/// Checks whether this file imports \c module as \c @_weakLinked.
129-
virtual bool importsModuleAsWeakLinked(const ModuleDecl *module) const {
130-
// For source files, this should be overridden to inspect the import
131-
// declarations in the file. Other kinds of file units, like serialized
132-
// modules, can just use this default implementation since the @_weakLinked
133-
// attribute is not transitive. If module C is imported @_weakLinked by
134-
// module B, that does not imply that module A imports module C @_weakLinked
135-
// if it imports module B.
136-
return false;
137-
}
138-
139128
virtual std::optional<Fingerprint>
140129
loadFingerprint(const IterableDeclContext *IDC) const {
141130
return std::nullopt;

include/swift/AST/ImportCache.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,18 @@ class alignas(ImportedModule) ImportCache {
127127
llvm::DenseMap<std::tuple<const ModuleDecl *,
128128
const DeclContext *>,
129129
bool> SwiftOnlyCache;
130+
llvm::DenseMap<const ModuleDecl *, ArrayRef<ModuleDecl *>> WeakCache;
130131

131132
ImportPath::Access EmptyAccessPath;
132133

133134
ArrayRef<ImportPath::Access> allocateArray(
134135
ASTContext &ctx,
135136
SmallVectorImpl<ImportPath::Access> &results);
136137

138+
ArrayRef<ModuleDecl *> allocateArray(
139+
ASTContext &ctx,
140+
llvm::SetVector<ModuleDecl *> &results);
141+
137142
ImportSet &getImportSet(ASTContext &ctx,
138143
ArrayRef<ImportedModule> topLevelImports);
139144

@@ -167,6 +172,13 @@ class alignas(ImportedModule) ImportCache {
167172
const ModuleDecl *other,
168173
const DeclContext *dc);
169174

175+
/// Returns all weak-linked imported modules.
176+
ArrayRef<ModuleDecl *>
177+
getWeakImports(const ModuleDecl *mod);
178+
179+
bool isWeakImportedBy(const ModuleDecl *mod,
180+
const ModuleDecl *from);
181+
170182
/// This is a hack to cope with main file parsing and REPL parsing, where
171183
/// we can add ImportDecls after import resolution.
172184
void clear() {

include/swift/AST/SourceFile.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,6 @@ class SourceFile final : public FileUnit {
474474
const ModuleDecl *importedModule,
475475
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
476476

477-
/// Is \p module imported as \c @_weakLinked by this file?
478-
bool importsModuleAsWeakLinked(const ModuleDecl *module) const override;
479-
480477
// Is \p targetDecl accessible as an explicitly imported SPI from this file?
481478
bool isImportedAsSPI(const ValueDecl *targetDecl) const;
482479

lib/AST/ImportCache.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/FileUnit.h"
2222
#include "swift/AST/ImportCache.h"
2323
#include "swift/AST/Module.h"
24+
#include "swift/AST/SourceFile.h"
2425

2526
using namespace swift;
2627
using namespace namelookup;
@@ -391,3 +392,56 @@ swift::namelookup::getAllImports(const DeclContext *dc) {
391392
return dc->getASTContext().getImportCache().getImportSet(dc)
392393
.getAllImports();
393394
}
395+
396+
ArrayRef<ModuleDecl *> ImportCache::allocateArray(
397+
ASTContext &ctx,
398+
llvm::SetVector<ModuleDecl *> &results) {
399+
if (results.empty())
400+
return {};
401+
else
402+
return ctx.AllocateCopy(results.getArrayRef());
403+
}
404+
405+
ArrayRef<ModuleDecl *>
406+
ImportCache::getWeakImports(const ModuleDecl *mod) {
407+
auto found = WeakCache.find(mod);
408+
if (found != WeakCache.end())
409+
return found->second;
410+
411+
llvm::SetVector<ModuleDecl *> result;
412+
413+
for (auto file : mod->getFiles()) {
414+
auto *sf = dyn_cast<SourceFile>(file);
415+
// Other kinds of file units, like serialized modules, can just use this
416+
// default implementation since the @_weakLinked attribute is not
417+
// transitive. If module C is imported @_weakLinked by module B, that does
418+
// not imply that module A imports module C @_weakLinked if it imports
419+
// module B.
420+
if (!sf)
421+
continue;
422+
423+
for (auto &import : sf->getImports()) {
424+
if (!import.options.contains(ImportFlags::WeakLinked))
425+
continue;
426+
427+
ModuleDecl *importedModule = import.module.importedModule;
428+
result.insert(importedModule);
429+
430+
auto reexportedModules = getImportSet(importedModule).getAllImports();
431+
for (auto reexportedModule : reexportedModules) {
432+
result.insert(reexportedModule.importedModule);
433+
}
434+
}
435+
}
436+
437+
auto resultArray = allocateArray(mod->getASTContext(), result);
438+
WeakCache[mod] = resultArray;
439+
return resultArray;
440+
}
441+
442+
bool ImportCache::isWeakImportedBy(const ModuleDecl *mod,
443+
const ModuleDecl *from) {
444+
auto weakImports = getWeakImports(from);
445+
return std::find(weakImports.begin(), weakImports.end(), mod)
446+
!= weakImports.end();
447+
}

lib/AST/Module.cpp

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3102,35 +3102,6 @@ bool SourceFile::isImportedAsSPI(const ValueDecl *targetDecl) const {
31023102
return false;
31033103
}
31043104

3105-
bool SourceFile::importsModuleAsWeakLinked(const ModuleDecl *module) const {
3106-
for (auto &import : *Imports) {
3107-
if (!import.options.contains(ImportFlags::WeakLinked))
3108-
continue;
3109-
3110-
const ModuleDecl *importedModule = import.module.importedModule;
3111-
if (module == importedModule)
3112-
return true;
3113-
3114-
// Also check whether the target module is actually the underlyingClang
3115-
// module for this @_weakLinked import.
3116-
const ModuleDecl *clangModule =
3117-
importedModule->getUnderlyingModuleIfOverlay();
3118-
if (module == clangModule)
3119-
return true;
3120-
3121-
// Traverse the exported modules of this weakly-linked module to ensure
3122-
// that we weak-link declarations from its exported peers.
3123-
SmallVector<ImportedModule, 8> reexportedModules;
3124-
importedModule->getImportedModules(reexportedModules,
3125-
ModuleDecl::ImportFilterKind::Exported);
3126-
for (const ImportedModule &reexportedModule : reexportedModules) {
3127-
if (module == reexportedModule.importedModule)
3128-
return true;
3129-
}
3130-
}
3131-
return false;
3132-
}
3133-
31343105
bool ModuleDecl::isImportedAsSPI(const SpecializeAttr *attr,
31353106
const ValueDecl *targetDecl) const {
31363107
auto declSPIGroups = attr->getSPIGroups();
@@ -3162,11 +3133,7 @@ bool ModuleDecl::isImportedAsSPI(Identifier spiGroup,
31623133
}
31633134

31643135
bool ModuleDecl::isImportedAsWeakLinked(const ModuleDecl *module) const {
3165-
for (auto file : getFiles()) {
3166-
if (file->importsModuleAsWeakLinked(module))
3167-
return true;
3168-
}
3169-
return false;
3136+
return getASTContext().getImportCache().isWeakImportedBy(module, this);
31703137
}
31713138

31723139
bool Decl::isSPI() const {

0 commit comments

Comments
 (0)