Skip to content

Commit 5e30f6a

Browse files
committed
AST: Optimize ModuleDecl::isImportedAsWeakLinked()
1 parent 403bb98 commit 5e30f6a

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
@@ -478,9 +478,6 @@ class SourceFile final : public FileUnit {
478478
const ModuleDecl *importedModule,
479479
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
480480

481-
/// Is \p module imported as \c @_weakLinked by this file?
482-
bool importsModuleAsWeakLinked(const ModuleDecl *module) const override;
483-
484481
// Is \p targetDecl accessible as an explicitly imported SPI from this file?
485482
bool isImportedAsSPI(const ValueDecl *targetDecl) const;
486483

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
#include "swift/Basic/Assertions.h"
2526

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

lib/AST/Module.cpp

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

3124-
bool SourceFile::importsModuleAsWeakLinked(const ModuleDecl *module) const {
3125-
for (auto &import : *Imports) {
3126-
if (!import.options.contains(ImportFlags::WeakLinked))
3127-
continue;
3128-
3129-
const ModuleDecl *importedModule = import.module.importedModule;
3130-
if (module == importedModule)
3131-
return true;
3132-
3133-
// Also check whether the target module is actually the underlyingClang
3134-
// module for this @_weakLinked import.
3135-
const ModuleDecl *clangModule =
3136-
importedModule->getUnderlyingModuleIfOverlay();
3137-
if (module == clangModule)
3138-
return true;
3139-
3140-
// Traverse the exported modules of this weakly-linked module to ensure
3141-
// that we weak-link declarations from its exported peers.
3142-
SmallVector<ImportedModule, 8> reexportedModules;
3143-
importedModule->getImportedModules(reexportedModules,
3144-
ModuleDecl::ImportFilterKind::Exported);
3145-
for (const ImportedModule &reexportedModule : reexportedModules) {
3146-
if (module == reexportedModule.importedModule)
3147-
return true;
3148-
}
3149-
}
3150-
return false;
3151-
}
3152-
31533124
bool ModuleDecl::isImportedAsSPI(const SpecializeAttr *attr,
31543125
const ValueDecl *targetDecl) const {
31553126
auto declSPIGroups = attr->getSPIGroups();
@@ -3181,11 +3152,7 @@ bool ModuleDecl::isImportedAsSPI(Identifier spiGroup,
31813152
}
31823153

31833154
bool ModuleDecl::isImportedAsWeakLinked(const ModuleDecl *module) const {
3184-
for (auto file : getFiles()) {
3185-
if (file->importsModuleAsWeakLinked(module))
3186-
return true;
3187-
}
3188-
return false;
3155+
return getASTContext().getImportCache().isWeakImportedBy(module, this);
31893156
}
31903157

31913158
bool Decl::isSPI() const {

0 commit comments

Comments
 (0)