Skip to content

Commit 84dd4db

Browse files
committed
Dependencies Scanner: report compiled Swift module paths if they are available
For the explicit module mode, swift-driver uses -compile-module-from-interface to generate modules from interfaces found by the dependency scanner. However, we don't need to build the binary module if up-to-date modules are available, either adjacent to the interface file or in the prebuilt module cache directory. This patch teaches dependencies scanner to report these ready-to-use binary modules.
1 parent d2bf447 commit 84dd4db

File tree

13 files changed

+165
-71
lines changed

13 files changed

+165
-71
lines changed

include/swift/AST/ASTContext.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,8 +716,11 @@ class ASTContext final {
716716
/// compiler.
717717
/// \param isDWARF \c true if this module loader can load Clang modules
718718
/// from DWARF.
719+
/// \param IsInterface \c true if this module loader can load Swift textual
720+
/// interface.
719721
void addModuleLoader(std::unique_ptr<ModuleLoader> loader,
720-
bool isClang = false, bool isDWARF = false);
722+
bool isClang = false, bool isDWARF = false,
723+
bool IsInterface = false);
721724

722725
/// Retrieve the module dependencies for the module with the given name.
723726
///
@@ -791,6 +794,8 @@ class ASTContext final {
791794
/// The loader is owned by the AST context.
792795
ClangModuleLoader *getDWARFModuleLoader() const;
793796

797+
/// Retrieve the module interface loader for this ASTContext.
798+
ModuleLoader *getModuleInterfaceLoader() const;
794799
public:
795800
namelookup::ImportCache &getImportCache() const;
796801

include/swift/AST/ModuleDependencies.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,11 @@ class ModuleDependencies {
180180
/// Describe the module dependencies for a Swift module that can be
181181
/// built from a Swift interface file (\c .swiftinterface).
182182
static ModuleDependencies forSwiftInterface(
183-
const std::string &compiledModulePath,
184183
const std::string &swiftInterfaceFile,
185184
ArrayRef<StringRef> buildCommands,
186185
ArrayRef<StringRef> extraPCMArgs,
187186
StringRef contextHash) {
187+
std::string compiledModulePath;
188188
return ModuleDependencies(
189189
std::make_unique<SwiftModuleDependenciesStorage>(
190190
compiledModulePath, swiftInterfaceFile, buildCommands,
@@ -201,9 +201,8 @@ class ModuleDependencies {
201201
}
202202

203203
/// Describe the main Swift module.
204-
static ModuleDependencies forMainSwiftModule(
205-
const std::string &compiledModulePath,
206-
ArrayRef<StringRef> extraPCMArgs) {
204+
static ModuleDependencies forMainSwiftModule(ArrayRef<StringRef> extraPCMArgs) {
205+
std::string compiledModulePath;
207206
return ModuleDependencies(
208207
std::make_unique<SwiftModuleDependenciesStorage>(
209208
compiledModulePath, None, ArrayRef<StringRef>(), extraPCMArgs,

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
202202
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer) override;
203203

204204
bool isCached(StringRef DepPath) override;
205-
206205
public:
207206
static std::unique_ptr<ModuleInterfaceLoader>
208207
create(ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir,
@@ -235,6 +234,9 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
235234
StringRef ModuleName, StringRef InPath, StringRef OutPath,
236235
bool SerializeDependencyHashes, bool TrackSystemDependencies,
237236
ModuleInterfaceLoaderOptions Opts);
237+
238+
std::string getUpToDateCompiledModuleForInterface(StringRef moduleName,
239+
StringRef interfacePath) override;
238240
};
239241

240242
struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ class SerializedModuleLoaderBase : public ModuleLoader {
200200
virtual Optional<ModuleDependencies> getModuleDependencies(
201201
StringRef moduleName, ModuleDependenciesCache &cache,
202202
InterfaceSubContextDelegate &delegate) override;
203+
204+
virtual std::string getUpToDateCompiledModuleForInterface(StringRef moduleName,
205+
StringRef interfacePath) {
206+
return std::string();
207+
}
203208
};
204209

205210
/// Imports serialized Swift modules into an ASTContext.

lib/AST/ASTContext.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ struct ASTContext::Implementation {
263263
/// The module loader used to load Clang modules from DWARF.
264264
ClangModuleLoader *TheDWARFModuleLoader = nullptr;
265265

266+
/// The module loader used to load Swift textual interface.
267+
ModuleLoader *TheModuleInterfaceLoader = nullptr;
268+
266269
/// Map from Swift declarations to raw comments.
267270
llvm::DenseMap<const Decl *, RawComment> RawComments;
268271

@@ -1450,14 +1453,15 @@ void ASTContext::addSearchPath(StringRef searchPath, bool isFramework,
14501453
}
14511454

14521455
void ASTContext::addModuleLoader(std::unique_ptr<ModuleLoader> loader,
1453-
bool IsClang, bool IsDwarf) {
1456+
bool IsClang, bool IsDwarf, bool IsInterface) {
14541457
if (IsClang && !IsDwarf && !getImpl().TheClangModuleLoader)
14551458
getImpl().TheClangModuleLoader =
14561459
static_cast<ClangModuleLoader *>(loader.get());
14571460
if (IsClang && IsDwarf && !getImpl().TheDWARFModuleLoader)
14581461
getImpl().TheDWARFModuleLoader =
14591462
static_cast<ClangModuleLoader *>(loader.get());
1460-
1463+
if (IsInterface && !getImpl().TheModuleInterfaceLoader)
1464+
getImpl().TheModuleInterfaceLoader = loader.get();
14611465
getImpl().ModuleLoaders.push_back(std::move(loader));
14621466
}
14631467

@@ -1532,6 +1536,10 @@ ClangModuleLoader *ASTContext::getDWARFModuleLoader() const {
15321536
return getImpl().TheDWARFModuleLoader;
15331537
}
15341538

1539+
ModuleLoader *ASTContext::getModuleInterfaceLoader() const {
1540+
return getImpl().TheModuleInterfaceLoader;
1541+
}
1542+
15351543
ModuleDecl *ASTContext::getLoadedModule(
15361544
ArrayRef<Located<Identifier>> ModulePath) const {
15371545
assert(!ModulePath.empty());

lib/Frontend/Frontend.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ bool CompilerInstance::setUpModuleLoaders() {
504504
getDependencyTracker(), MLM, FEOpts.PreferInterfaceForModules,
505505
LoaderOpts,
506506
IgnoreSourceInfoFile);
507-
Context->addModuleLoader(std::move(PIML));
507+
Context->addModuleLoader(std::move(PIML), false, false, true);
508508
}
509509

510510
std::unique_ptr<SerializedModuleLoader> SML =

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 76 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -590,11 +590,9 @@ class ModuleInterfaceLoaderImpl {
590590
return path.startswith(resourceDir);
591591
}
592592

593-
/// Finds the most appropriate .swiftmodule, whose dependencies are up to
594-
/// date, that we can load for the provided .swiftinterface file.
595-
llvm::ErrorOr<DiscoveredModule> discoverUpToDateModuleForInterface(
596-
StringRef modulePath, StringRef cachedOutputPath,
597-
SmallVectorImpl<FileDependency> &deps) {
593+
llvm::ErrorOr<DiscoveredModule>
594+
discoverUpToDateCompiledModuleForInterface(SmallVectorImpl<FileDependency> &deps,
595+
std::string &UsableModulePath) {
598596
auto notFoundError =
599597
std::make_error_code(std::errc::no_such_file_or_directory);
600598

@@ -619,50 +617,6 @@ class ModuleInterfaceLoaderImpl {
619617
case ModuleLoadingMode::OnlySerialized:
620618
llvm_unreachable("module interface loader should not have been created");
621619
}
622-
623-
624-
// First, check the cached module path. Whatever's in this cache represents
625-
// the most up-to-date knowledge we have about the module.
626-
if (auto cachedBufOrError = fs.getBufferForFile(cachedOutputPath)) {
627-
auto buf = std::move(*cachedBufOrError);
628-
629-
// Check to see if the module is a serialized AST. If it's not, then we're
630-
// probably dealing with a Forwarding Module, which is a YAML file.
631-
bool isForwardingModule =
632-
!serialization::isSerializedAST(buf->getBuffer());
633-
634-
// If it's a forwarding module, load the YAML file from disk and check
635-
// if it's up-to-date.
636-
if (isForwardingModule) {
637-
if (auto forwardingModule = ForwardingModule::load(*buf)) {
638-
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
639-
if (forwardingModuleIsUpToDate(cachedOutputPath,
640-
*forwardingModule, deps,
641-
moduleBuffer)) {
642-
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date forwarding module at "
643-
<< cachedOutputPath << "\n");
644-
return DiscoveredModule::forwarded(
645-
forwardingModule->underlyingModulePath, std::move(moduleBuffer));
646-
}
647-
648-
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date forwarding module at "
649-
<< cachedOutputPath << "\n");
650-
rebuildInfo.setModuleKind(cachedOutputPath,
651-
ModuleRebuildInfo::ModuleKind::Forwarding);
652-
}
653-
// Otherwise, check if the AST buffer itself is up to date.
654-
} else if (serializedASTBufferIsUpToDate(cachedOutputPath, *buf, deps)) {
655-
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date cached module at "
656-
<< cachedOutputPath << "\n");
657-
return DiscoveredModule::normal(cachedOutputPath, std::move(buf));
658-
} else {
659-
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date cached module at "
660-
<< cachedOutputPath << "\n");
661-
rebuildInfo.setModuleKind(cachedOutputPath,
662-
ModuleRebuildInfo::ModuleKind::Cached);
663-
}
664-
}
665-
666620
// [Note: ModuleInterfaceLoader-defer-to-SerializedModuleLoader]
667621
// If there's a module adjacent to the .swiftinterface that we can
668622
// _likely_ load (it validates OK and is up to date), bail early with
@@ -680,6 +634,7 @@ class ModuleInterfaceLoaderImpl {
680634
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date module at "
681635
<< modulePath
682636
<< "; deferring to serialized module loader\n");
637+
UsableModulePath = modulePath.str();
683638
return std::make_error_code(std::errc::not_supported);
684639
} else if (isInResourceDir(modulePath) &&
685640
loadMode == ModuleLoadingMode::PreferSerialized) {
@@ -725,6 +680,7 @@ class ModuleInterfaceLoaderImpl {
725680
if (swiftModuleIsUpToDate(*path, deps, moduleBuffer)) {
726681
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date prebuilt module at "
727682
<< path->str() << "\n");
683+
UsableModulePath = path->str();
728684
return DiscoveredModule::prebuilt(*path, std::move(moduleBuffer));
729685
} else {
730686
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date prebuilt module at "
@@ -740,6 +696,57 @@ class ModuleInterfaceLoaderImpl {
740696
return notFoundError;
741697
}
742698

699+
/// Finds the most appropriate .swiftmodule, whose dependencies are up to
700+
/// date, that we can load for the provided .swiftinterface file.
701+
llvm::ErrorOr<DiscoveredModule> discoverUpToDateModuleForInterface(
702+
StringRef cachedOutputPath,
703+
SmallVectorImpl<FileDependency> &deps) {
704+
705+
// First, check the cached module path. Whatever's in this cache represents
706+
// the most up-to-date knowledge we have about the module.
707+
if (auto cachedBufOrError = fs.getBufferForFile(cachedOutputPath)) {
708+
auto buf = std::move(*cachedBufOrError);
709+
710+
// Check to see if the module is a serialized AST. If it's not, then we're
711+
// probably dealing with a Forwarding Module, which is a YAML file.
712+
bool isForwardingModule =
713+
!serialization::isSerializedAST(buf->getBuffer());
714+
715+
// If it's a forwarding module, load the YAML file from disk and check
716+
// if it's up-to-date.
717+
if (isForwardingModule) {
718+
if (auto forwardingModule = ForwardingModule::load(*buf)) {
719+
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
720+
if (forwardingModuleIsUpToDate(cachedOutputPath,
721+
*forwardingModule, deps,
722+
moduleBuffer)) {
723+
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date forwarding module at "
724+
<< cachedOutputPath << "\n");
725+
return DiscoveredModule::forwarded(
726+
forwardingModule->underlyingModulePath, std::move(moduleBuffer));
727+
}
728+
729+
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date forwarding module at "
730+
<< cachedOutputPath << "\n");
731+
rebuildInfo.setModuleKind(cachedOutputPath,
732+
ModuleRebuildInfo::ModuleKind::Forwarding);
733+
}
734+
// Otherwise, check if the AST buffer itself is up to date.
735+
} else if (serializedASTBufferIsUpToDate(cachedOutputPath, *buf, deps)) {
736+
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date cached module at "
737+
<< cachedOutputPath << "\n");
738+
return DiscoveredModule::normal(cachedOutputPath, std::move(buf));
739+
} else {
740+
LLVM_DEBUG(llvm::dbgs() << "Found out-of-date cached module at "
741+
<< cachedOutputPath << "\n");
742+
rebuildInfo.setModuleKind(cachedOutputPath,
743+
ModuleRebuildInfo::ModuleKind::Cached);
744+
}
745+
}
746+
std::string usableModulePath;
747+
return discoverUpToDateCompiledModuleForInterface(deps, usableModulePath);
748+
}
749+
743750
/// Writes the "forwarding module" that will forward to a module in the
744751
/// prebuilt cache.
745752
///
@@ -847,7 +854,7 @@ class ModuleInterfaceLoaderImpl {
847854
// in the cache, or in the prebuilt cache.
848855
SmallVector<FileDependency, 16> allDeps;
849856
auto moduleOrErr =
850-
discoverUpToDateModuleForInterface(modulePath, cachedOutputPath, allDeps);
857+
discoverUpToDateModuleForInterface(cachedOutputPath, allDeps);
851858

852859
// If we errored with anything other than 'no such file or directory',
853860
// fail this load and let the other module loader diagnose it.
@@ -993,6 +1000,25 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory(
9931000
return std::error_code();
9941001
}
9951002

1003+
std::string
1004+
ModuleInterfaceLoader::getUpToDateCompiledModuleForInterface(StringRef moduleName,
1005+
StringRef interfacePath) {
1006+
// Derive .swiftmodule path from the .swiftinterface path.
1007+
auto newExt = file_types::getExtension(file_types::TY_SwiftModuleFile);
1008+
llvm::SmallString<32> modulePath = interfacePath;
1009+
llvm::sys::path::replace_extension(modulePath, newExt);
1010+
ModuleInterfaceLoaderImpl Impl(
1011+
Ctx, modulePath, interfacePath, moduleName,
1012+
CacheDir, PrebuiltCacheDir, SourceLoc(),
1013+
Opts,
1014+
dependencyTracker,
1015+
llvm::is_contained(PreferInterfaceForModules, moduleName) ?
1016+
ModuleLoadingMode::PreferInterface : LoadMode);
1017+
SmallVector<FileDependency, 16> allDeps;
1018+
std::string usableModulePath;
1019+
Impl.discoverUpToDateCompiledModuleForInterface(allDeps, usableModulePath);
1020+
return usableModulePath;
1021+
}
9961022

9971023
bool ModuleInterfaceLoader::buildSwiftModuleFromSwiftInterface(
9981024
SourceManager &SourceMgr, DiagnosticEngine &Diags,

lib/FrontendTool/ScanDependencies.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,12 @@ static void writeJSON(llvm::raw_ostream &out,
339339
}
340340
out.indent(5 * 2);
341341
out << "],\n";
342+
} else if (!swiftDeps->compiledModulePath.empty()) {
343+
writeJSONSingleField(
344+
out, "compiledModulePath",
345+
swiftDeps->compiledModulePath, 5,
346+
/*trailingComma=*/false);
342347
}
343-
344348
if (!swiftDeps->extraPCMArgs.empty()) {
345349
out.indent(5 * 2);
346350
out << "\"extraPcmArgs\": [\n";
@@ -354,7 +358,6 @@ static void writeJSON(llvm::raw_ostream &out,
354358
out.indent(5 * 2);
355359
out << (swiftDeps->bridgingHeaderFile.hasValue() ? "],\n" : "]\n");
356360
}
357-
358361
/// Bridging header and its source file dependencies, if any.
359362
if (swiftDeps->bridgingHeaderFile) {
360363
out.indent(5 * 2);
@@ -431,7 +434,7 @@ bool swift::scanDependencies(CompilerInstance &instance) {
431434
.asAPINotesVersionString()).str();
432435
// Compute the dependencies of the main module.
433436
auto mainDependencies =
434-
ModuleDependencies::forMainSwiftModule(mainModulePath.str().str(), {
437+
ModuleDependencies::forMainSwiftModule({
435438
// ExtraPCMArgs
436439
"-Xcc", "-target", "-Xcc", instance.getASTContext().LangOpts.Target.str(),
437440
"-Xcc", apinotesVer

lib/Serialization/ModuleDependencyScanner.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ class ModuleDependencyScanner : public SerializedModuleLoaderBase {
4444
/*IgnoreSwiftSourceInfoFile=*/true),
4545
moduleName(moduleName), astDelegate(astDelegate) { }
4646

47+
std::string getCompiledModulePath(const SerializedModuleBaseName &BaseName) {
48+
if (LoadMode == ModuleLoadingMode::OnlySerialized) {
49+
return BaseName.getName(file_types::TY_SwiftModuleFile);
50+
}
51+
return static_cast<SerializedModuleLoaderBase*>(Ctx
52+
.getModuleInterfaceLoader())->getUpToDateCompiledModuleForInterface(
53+
moduleName.str(),
54+
BaseName.getName(file_types::TY_SwiftModuleInterfaceFile));
55+
}
56+
4757
virtual std::error_code findModuleFilesInDirectory(
4858
AccessPathElem ModuleID,
4959
const SerializedModuleBaseName &BaseName,
@@ -56,12 +66,9 @@ class ModuleDependencyScanner : public SerializedModuleLoaderBase {
5666
auto &fs = *Ctx.SourceMgr.getFileSystem();
5767

5868
// Compute the full path of the module we're looking for.
59-
auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile);
60-
if (LoadMode == ModuleLoadingMode::OnlySerialized) {
61-
// If there is no module file, there's nothing we can do.
62-
if (!fs.exists(ModPath))
63-
return std::make_error_code(std::errc::no_such_file_or_directory);
69+
auto ModPath = getCompiledModulePath(BaseName);
6470

71+
if (fs.exists(ModPath)) {
6572
// The module file will be loaded directly.
6673
auto dependencies = scanModuleFile(ModPath);
6774
if (dependencies) {
@@ -110,8 +117,7 @@ ErrorOr<ModuleDependencies> ModuleDependencyScanner::scanInterfaceFile(
110117
SourceLoc(),
111118
[&](ASTContext &Ctx, ArrayRef<StringRef> Args,
112119
ArrayRef<StringRef> PCMArgs, StringRef Hash) {
113-
Result = ModuleDependencies::forSwiftInterface(modulePath.str().str(),
114-
moduleInterfacePath.str(),
120+
Result = ModuleDependencies::forSwiftInterface(moduleInterfacePath.str(),
115121
Args,
116122
PCMArgs,
117123
Hash);

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,13 +366,14 @@ llvm::ErrorOr<ModuleDependencies> SerializedModuleLoaderBase::scanModuleFile(
366366
// Load the module file without validation.
367367
std::unique_ptr<ModuleFile> loadedModuleFile;
368368
bool isFramework = false;
369+
serialization::ExtendedValidationInfo extInfo;
369370
serialization::ValidationInfo loadInfo =
370371
ModuleFile::load(modulePath.str(),
371372
std::move(moduleBuf.get()),
372373
nullptr,
373374
nullptr,
374375
isFramework, loadedModuleFile,
375-
nullptr);
376+
&extInfo);
376377

377378
// Map the set of dependencies over to the "module dependencies".
378379
auto dependencies = ModuleDependencies::forSwiftModule(modulePath.str());

test/ScanDependencies/Inputs/ModuleDependencyGraph.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ struct SwiftModuleDetails: Codable {
6363
/// The module interface from which this module was built, if any.
6464
var moduleInterfacePath: String?
6565

66+
/// The compiled Swift module to use.
67+
var compiledModulePath: String?
68+
6669
/// The bridging header, if any.
6770
var bridgingHeader: BridgingHeader?
6871

0 commit comments

Comments
 (0)