From 8ccee27db72e0ce6fbf236a8f13ab2e85984a482 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 29 Sep 2020 11:26:17 -0700 Subject: [PATCH] ModuleInterface: refactor ModuleInterfaceChecker out of ModuleInterfaceLoader This refactoring allows us to drop ModuleInterfaceLoader when explicit modules are enabled. Before this change, the dependencies scanner needs the loader to be present to access functionalities like collecting prebuilt module candidates. --- include/swift/AST/ASTContext.h | 9 ++- include/swift/AST/ModuleLoader.h | 17 +++++ .../swift/Frontend/ModuleInterfaceLoader.h | 68 +++++++++++-------- .../Serialization/SerializedModuleLoader.h | 12 ---- lib/AST/ASTContext.cpp | 20 ++++-- lib/Frontend/Frontend.cpp | 34 +++++----- lib/Frontend/ModuleInterfaceBuilder.cpp | 7 +- lib/Frontend/ModuleInterfaceLoader.cpp | 31 ++++----- lib/Serialization/ModuleDependencyScanner.cpp | 3 +- unittests/FrontendTool/ModuleLoadingTests.cpp | 7 +- 10 files changed, 117 insertions(+), 91 deletions(-) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 79a48b324e588..ff4cfafea73f0 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -762,6 +762,12 @@ class ASTContext final { bool isClang = false, bool isDWARF = false, bool IsInterface = false); + /// Add a module interface checker to use for this AST context. + void addModuleInterfaceChecker(std::unique_ptr checker); + + /// Retrieve the module interface checker associated with this AST context. + ModuleInterfaceChecker *getModuleInterfaceChecker() const; + /// Retrieve the module dependencies for the module with the given name. /// /// \param isUnderlyingClangModule When true, only look for a Clang module @@ -839,9 +845,6 @@ class ASTContext final { /// If there is no Clang module loader, returns a null pointer. /// The loader is owned by the AST context. ClangModuleLoader *getDWARFModuleLoader() const; - - /// Retrieve the module interface loader for this ASTContext. - ModuleLoader *getModuleInterfaceLoader() const; public: namelookup::ImportCache &getImportCache() const; diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index 9e5e836bac514..47d7682eca652 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -116,6 +116,23 @@ struct SubCompilerInstanceInfo { ArrayRef ExtraPCMArgs; }; +/// Abstract interface for a checker of module interfaces and prebuilt modules. +class ModuleInterfaceChecker { +public: + virtual std::vector + getCompiledModuleCandidatesForInterface(StringRef moduleName, + StringRef interfacePath) = 0; + + /// Given a list of potential ready-to-use compiled modules for \p interfacePath, + /// check if any one of them is up-to-date. If so, emit a forwarding module + /// to the candidate binary module to \p outPath. + virtual bool tryEmitForwardingModule(StringRef moduleName, + StringRef interfacePath, + ArrayRef candidates, + StringRef outPath) = 0; + virtual ~ModuleInterfaceChecker() = default; +}; + /// Abstract interface to run an action in a sub ASTContext. struct InterfaceSubContextDelegate { virtual std::error_code runInSubContext(StringRef moduleName, diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 2e0cc1760e7a1..56c63173fb661 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -309,6 +309,35 @@ struct ModuleInterfaceLoaderOptions { ModuleInterfaceLoaderOptions() = default; }; +class ModuleInterfaceCheckerImpl: public ModuleInterfaceChecker { + friend class ModuleInterfaceLoader; + ASTContext &Ctx; + std::string CacheDir; + std::string PrebuiltCacheDir; + ModuleInterfaceLoaderOptions Opts; + +public: + explicit ModuleInterfaceCheckerImpl(ASTContext &Ctx, + StringRef cacheDir, + StringRef prebuiltCacheDir, + ModuleInterfaceLoaderOptions Opts) + : Ctx(Ctx), CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir), + Opts(Opts) {} + + std::vector + getCompiledModuleCandidatesForInterface(StringRef moduleName, + StringRef interfacePath) override; + + /// Given a list of potential ready-to-use compiled modules for \p interfacePath, + /// check if any one of them is up-to-date. If so, emit a forwarding module + /// to the candidate binary module to \p outPath. + bool tryEmitForwardingModule(StringRef moduleName, + StringRef interfacePath, + ArrayRef candidates, + StringRef outPath) override; + bool isCached(StringRef DepPath); +}; + /// A ModuleLoader that runs a subordinate \c CompilerInvocation and /// \c CompilerInstance to convert .swiftinterface files to .swiftmodule /// files on the fly, caching the resulting .swiftmodules in the module cache @@ -316,20 +345,16 @@ struct ModuleInterfaceLoaderOptions { class ModuleInterfaceLoader : public SerializedModuleLoaderBase { friend class unittest::ModuleInterfaceLoaderTest; explicit ModuleInterfaceLoader( - ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir, + ASTContext &ctx, ModuleInterfaceCheckerImpl &InterfaceChecker, DependencyTracker *tracker, ModuleLoadingMode loadMode, ArrayRef PreferInterfaceForModules, - bool IgnoreSwiftSourceInfoFile, ModuleInterfaceLoaderOptions Opts) - : SerializedModuleLoaderBase(ctx, tracker, loadMode, - IgnoreSwiftSourceInfoFile), - CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir), - PreferInterfaceForModules(PreferInterfaceForModules), - Opts(Opts) {} + bool IgnoreSwiftSourceInfoFile) + : SerializedModuleLoaderBase(ctx, tracker, loadMode, IgnoreSwiftSourceInfoFile), + InterfaceChecker(InterfaceChecker), + PreferInterfaceForModules(PreferInterfaceForModules){} - std::string CacheDir; - std::string PrebuiltCacheDir; + ModuleInterfaceCheckerImpl &InterfaceChecker; ArrayRef PreferInterfaceForModules; - ModuleInterfaceLoaderOptions Opts; std::error_code findModuleFilesInDirectory( ImportPath::Element ModuleID, @@ -343,17 +368,14 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase { bool isCached(StringRef DepPath) override; public: static std::unique_ptr - create(ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir, + create(ASTContext &ctx, ModuleInterfaceCheckerImpl &InterfaceChecker, DependencyTracker *tracker, ModuleLoadingMode loadMode, ArrayRef PreferInterfaceForModules = {}, - ModuleInterfaceLoaderOptions Opts = ModuleInterfaceLoaderOptions(), bool IgnoreSwiftSourceInfoFile = false) { return std::unique_ptr( - new ModuleInterfaceLoader(ctx, cacheDir, prebuiltCacheDir, - tracker, loadMode, - PreferInterfaceForModules, - IgnoreSwiftSourceInfoFile, - Opts)); + new ModuleInterfaceLoader(ctx, InterfaceChecker, tracker, loadMode, + PreferInterfaceForModules, + IgnoreSwiftSourceInfoFile)); } /// Append visible module names to \p names. Note that names are possibly @@ -373,18 +395,6 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase { StringRef ModuleName, StringRef InPath, StringRef OutPath, bool SerializeDependencyHashes, bool TrackSystemDependencies, ModuleInterfaceLoaderOptions Opts); - - std::vector - getCompiledModuleCandidatesForInterface(StringRef moduleName, - StringRef interfacePath) override; - - /// Given a list of potential ready-to-use compiled modules for \p interfacePath, - /// check if any one of them is up-to-date. If so, emit a forwarding module - /// to the candidate binary module to \p outPath. - bool tryEmitForwardingModule(StringRef moduleName, - StringRef interfacePath, - ArrayRef candidates, - StringRef outPath) override; }; struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate { diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index f150c8481d1ef..e0aa714fd3914 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -201,18 +201,6 @@ class SerializedModuleLoaderBase : public ModuleLoader { virtual Optional getModuleDependencies( StringRef moduleName, ModuleDependenciesCache &cache, InterfaceSubContextDelegate &delegate) override; - - virtual std::vector - getCompiledModuleCandidatesForInterface(StringRef moduleName, - StringRef interfacePath) { - return std::vector(); - } - virtual bool tryEmitForwardingModule(StringRef moduleName, - StringRef interfacePath, - ArrayRef candidates, - StringRef outPath) { - return false; - } }; /// Imports serialized Swift modules into an ASTContext. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4b8be5ff67243..f47353247d4e2 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -255,6 +255,9 @@ struct ASTContext::Implementation { /// The set of known protocols, lazily populated as needed. ProtocolDecl *KnownProtocols[NumKnownProtocols] = { }; + /// The module interface checker owned by the ASTContext. + std::unique_ptr InterfaceChecker; + /// The various module loaders that import external modules into this /// ASTContext. SmallVector, 4> ModuleLoaders; @@ -268,9 +271,6 @@ struct ASTContext::Implementation { /// The module loader used to load Clang modules from DWARF. ClangModuleLoader *TheDWARFModuleLoader = nullptr; - /// The module loader used to load Swift textual interface. - ModuleLoader *TheModuleInterfaceLoader = nullptr; - /// Map from Swift declarations to raw comments. llvm::DenseMap RawComments; @@ -1519,11 +1519,15 @@ void ASTContext::addModuleLoader(std::unique_ptr loader, if (IsClang && IsDwarf && !getImpl().TheDWARFModuleLoader) getImpl().TheDWARFModuleLoader = static_cast(loader.get()); - if (IsInterface && !getImpl().TheModuleInterfaceLoader) - getImpl().TheModuleInterfaceLoader = loader.get(); getImpl().ModuleLoaders.push_back(std::move(loader)); } +void ASTContext::addModuleInterfaceChecker( + std::unique_ptr checker) { + assert(!getImpl().InterfaceChecker && "Checker has been set already"); + getImpl().InterfaceChecker = std::move(checker); +} + Optional ASTContext::getModuleDependencies( StringRef moduleName, bool isUnderlyingClangModule, ModuleDependenciesCache &cache, InterfaceSubContextDelegate &delegate) { @@ -1610,8 +1614,10 @@ ClangModuleLoader *ASTContext::getDWARFModuleLoader() const { return getImpl().TheDWARFModuleLoader; } -ModuleLoader *ASTContext::getModuleInterfaceLoader() const { - return getImpl().TheModuleInterfaceLoader; +ModuleInterfaceChecker *ASTContext::getModuleInterfaceChecker() const { + auto *result = getImpl().InterfaceChecker.get(); + assert(result); + return result; } ModuleDecl *ASTContext::getLoadedModule( diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index a337d876eedc1..8ca60ba422374 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -493,6 +493,14 @@ bool CompilerInstance::setUpModuleLoaders() { return true; } + // Configure ModuleInterfaceChecker for the ASTContext. + auto const &Clang = clangImporter->getClangInstance(); + std::string ModuleCachePath = getModuleCachePathFromClang(Clang); + auto &FEOpts = Invocation.getFrontendOptions(); + ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); + Context->addModuleInterfaceChecker( + std::make_unique(*Context, ModuleCachePath, + FEOpts.PrebuiltModuleCachePath, LoaderOpts)); // If implicit modules are disabled, we need to install an explicit module // loader. bool ExplicitModuleBuild = Invocation.getFrontendOptions().DisableImplicitModules; @@ -505,23 +513,15 @@ bool CompilerInstance::setUpModuleLoaders() { IgnoreSourceInfoFile); this->DefaultSerializedLoader = ESML.get(); Context->addModuleLoader(std::move(ESML)); - } - - if (MLM != ModuleLoadingMode::OnlySerialized) { - auto const &Clang = clangImporter->getClangInstance(); - std::string ModuleCachePath = getModuleCachePathFromClang(Clang); - auto &FEOpts = Invocation.getFrontendOptions(); - StringRef PrebuiltModuleCachePath = FEOpts.PrebuiltModuleCachePath; - ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); - auto PIML = ModuleInterfaceLoader::create( - *Context, ModuleCachePath, PrebuiltModuleCachePath, - getDependencyTracker(), MLM, FEOpts.PreferInterfaceForModules, - LoaderOpts, - IgnoreSourceInfoFile); - Context->addModuleLoader(std::move(PIML), false, false, true); - } - - if (!ExplicitModuleBuild) { + } else { + if (MLM != ModuleLoadingMode::OnlySerialized) { + // We only need ModuleInterfaceLoader for implicit modules. + auto PIML = ModuleInterfaceLoader::create( + *Context, *static_cast(Context + ->getModuleInterfaceChecker()), getDependencyTracker(), MLM, + FEOpts.PreferInterfaceForModules, IgnoreSourceInfoFile); + Context->addModuleLoader(std::move(PIML), false, false, true); + } std::unique_ptr ISML = ImplicitSerializedModuleLoader::create(*Context, getDependencyTracker(), MLM, IgnoreSourceInfoFile); diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 63ad78f6ecefd..45f9ea0867c55 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -170,10 +170,9 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( auto &SubInstance = *info.Instance; auto subInvocation = SubInstance.getInvocation(); // Try building forwarding module first. If succeed, return. - if (static_cast(SubInstance.getASTContext() - .getModuleInterfaceLoader())->tryEmitForwardingModule(moduleName, - interfacePath, - CompiledCandidates, OutPath)) { + if (SubInstance.getASTContext().getModuleInterfaceChecker() + ->tryEmitForwardingModule(moduleName, interfacePath, + CompiledCandidates, OutPath)) { return std::error_code(); } FrontendOptions &FEOpts = subInvocation.getFrontendOptions(); diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index ccbf279afcffa..ab054a3423ba8 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -335,6 +335,7 @@ struct ModuleRebuildInfo { /// a module that we'll build from a module interface. class ModuleInterfaceLoaderImpl { friend class swift::ModuleInterfaceLoader; + friend class swift::ModuleInterfaceCheckerImpl; ASTContext &ctx; llvm::vfs::FileSystem &fs; DiagnosticEngine &diags; @@ -907,10 +908,6 @@ class ModuleInterfaceLoaderImpl { return std::move(module.moduleBuffer); } - // If implicit module is disabled, we are done. - if (Opts.disableImplicitSwiftModule) { - return std::make_error_code(std::errc::not_supported); - } std::unique_ptr moduleBuffer; @@ -942,12 +939,16 @@ class ModuleInterfaceLoaderImpl { } // end anonymous namespace -bool ModuleInterfaceLoader::isCached(StringRef DepPath) { +bool ModuleInterfaceCheckerImpl::isCached(StringRef DepPath) { if (!CacheDir.empty() && DepPath.startswith(CacheDir)) return true; return !PrebuiltCacheDir.empty() && DepPath.startswith(PrebuiltCacheDir); } +bool ModuleInterfaceLoader::isCached(StringRef DepPath) { + return InterfaceChecker.isCached(DepPath); +} + /// Load a .swiftmodule associated with a .swiftinterface either from a /// cache or by converting it in a subordinate \c CompilerInstance, caching /// the results. @@ -990,8 +991,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( auto ModuleName = ModuleID.Item.str(); ModuleInterfaceLoaderImpl Impl( Ctx, ModPath, InPath, ModuleName, - CacheDir, PrebuiltCacheDir, ModuleID.Loc, - Opts, + InterfaceChecker.CacheDir, InterfaceChecker.PrebuiltCacheDir, + ModuleID.Loc, InterfaceChecker.Opts, dependencyTracker, llvm::is_contained(PreferInterfaceForModules, ModuleName) ? @@ -1024,8 +1025,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( } std::vector -ModuleInterfaceLoader::getCompiledModuleCandidatesForInterface(StringRef moduleName, - StringRef interfacePath) { +ModuleInterfaceCheckerImpl::getCompiledModuleCandidatesForInterface( + StringRef moduleName, StringRef interfacePath) { // Derive .swiftmodule path from the .swiftinterface path. auto newExt = file_types::getExtension(file_types::TY_SwiftModuleFile); llvm::SmallString<32> modulePath = interfacePath; @@ -1034,9 +1035,8 @@ ModuleInterfaceLoader::getCompiledModuleCandidatesForInterface(StringRef moduleN Ctx, modulePath, interfacePath, moduleName, CacheDir, PrebuiltCacheDir, SourceLoc(), Opts, - dependencyTracker, - llvm::is_contained(PreferInterfaceForModules, moduleName) ? - ModuleLoadingMode::PreferInterface : LoadMode); + nullptr, + ModuleLoadingMode::PreferSerialized); std::vector results; auto pair = Impl.getCompiledModuleCandidates(); // Add compiled module candidates only when they are non-empty. @@ -1047,7 +1047,7 @@ ModuleInterfaceLoader::getCompiledModuleCandidatesForInterface(StringRef moduleN return results; } -bool ModuleInterfaceLoader::tryEmitForwardingModule(StringRef moduleName, +bool ModuleInterfaceCheckerImpl::tryEmitForwardingModule(StringRef moduleName, StringRef interfacePath, ArrayRef candidates, StringRef outputPath) { @@ -1059,9 +1059,8 @@ bool ModuleInterfaceLoader::tryEmitForwardingModule(StringRef moduleName, Ctx, modulePath, interfacePath, moduleName, CacheDir, PrebuiltCacheDir, SourceLoc(), Opts, - dependencyTracker, - llvm::is_contained(PreferInterfaceForModules, moduleName) ? - ModuleLoadingMode::PreferInterface : LoadMode); + nullptr, + ModuleLoadingMode::PreferSerialized); SmallVector deps; std::unique_ptr moduleBuffer; for (auto mod: candidates) { diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index 6e4f82b6178ed..600744840648e 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -98,8 +98,7 @@ std::error_code PlaceholderSwiftModuleScanner::findModuleFilesInDirectory( static std::vector getCompiledCandidates(ASTContext &ctx, StringRef moduleName, StringRef interfacePath) { - return static_cast(ctx - .getModuleInterfaceLoader())->getCompiledModuleCandidatesForInterface( + return ctx.getModuleInterfaceChecker()->getCompiledModuleCandidatesForInterface( moduleName.str(), interfacePath); } diff --git a/unittests/FrontendTool/ModuleLoadingTests.cpp b/unittests/FrontendTool/ModuleLoadingTests.cpp index 0d80267cd90a9..30dd8553d16bb 100644 --- a/unittests/FrontendTool/ModuleLoadingTests.cpp +++ b/unittests/FrontendTool/ModuleLoadingTests.cpp @@ -103,8 +103,13 @@ class ModuleInterfaceLoaderTest : public testing::Test { ASTContext::get(langOpts, typeckOpts, searchPathOpts, clangImpOpts, sourceMgr, diags); + ctx->addModuleInterfaceChecker( + std::make_unique(*ctx, cacheDir, + prebuiltCacheDir, ModuleInterfaceLoaderOptions())); + auto loader = ModuleInterfaceLoader::create( - *ctx, cacheDir, prebuiltCacheDir, + *ctx, *static_cast( + ctx->getModuleInterfaceChecker()), /*dependencyTracker*/nullptr, ModuleLoadingMode::PreferSerialized);