Files
swift-mirror/lib/Serialization/ModuleDependencyScanner.cpp
Ben Barham 6269643b4d [Index] Prevent re-indexing system modules repeatedly
If a module was first read using the adjacent swiftmodule and then
reloaded using the swiftinterface, we would do an up to date check on
the adjacent module but write out the unit using the swiftinterface.
This would cause the same modules to be indexed repeatedly for the first
invocation using a new SDK. On the next run we would instead raad the
swiftmodule from the cache and thus the out of date check would match
up.

The impact of this varies depending on the size of the module graph in
the initial compilation and the number of jobs started at the same time.
Each SDK dependency is re-indexed *and* reloaded, which is a drain on
both CPU and memory. Thus, if many jobs are initially started and
they're all going down this path, it can cause the system to run out of
memory very quickly.

Resolves rdar://103119964.
2023-02-09 11:49:13 -08:00

212 lines
8.8 KiB
C++

//===--- ModuleDependencyScanner.cpp - Compute module dependencies --------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticSuppression.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/ModuleDependencies.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/FileTypes.h"
#include "swift/Frontend/ModuleInterfaceLoader.h"
#include "swift/Serialization/SerializedModuleLoader.h"
#include "swift/Serialization/ModuleDependencyScanner.h"
#include "swift/Subsystems.h"
using namespace swift;
using llvm::ErrorOr;
std::error_code ModuleDependencyScanner::findModuleFilesInDirectory(
ImportPath::Element ModuleID, const SerializedModuleBaseName &BaseName,
SmallVectorImpl<char> *ModuleInterfacePath,
SmallVectorImpl<char> *ModuleInterfaceSourcePath,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
bool skipBuildingInterface, bool IsFramework) {
using namespace llvm::sys;
auto &fs = *Ctx.SourceMgr.getFileSystem();
auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile);
auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile);
if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) {
if (fs.exists(ModPath)) {
// The module file will be loaded directly.
auto dependencies = scanModuleFile(ModPath, IsFramework);
if (dependencies) {
this->dependencies = std::move(dependencies.get());
return std::error_code();
}
return dependencies.getError();
} else {
return std::make_error_code(std::errc::no_such_file_or_directory);
}
}
assert(fs.exists(InPath));
// Use the private interface file if exits.
auto PrivateInPath =
BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile);
if (fs.exists(PrivateInPath)) {
InPath = PrivateInPath;
}
auto dependencies = scanInterfaceFile(InPath, IsFramework);
if (dependencies) {
this->dependencies = std::move(dependencies.get());
return std::error_code();
}
return dependencies.getError();
}
bool PlaceholderSwiftModuleScanner::findModule(
ImportPath::Element moduleID, SmallVectorImpl<char> *moduleInterfacePath,
SmallVectorImpl<char> *moduleInterfaceSourcePath,
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *moduleSourceInfoBuffer,
bool skipBuildingInterface, bool &isFramework, bool &isSystemModule) {
StringRef moduleName = Ctx.getRealModuleName(moduleID.Item).str();
auto it = PlaceholderDependencyModuleMap.find(moduleName);
if (it == PlaceholderDependencyModuleMap.end()) {
return false;
}
auto &moduleInfo = it->getValue();
auto dependencies = ModuleDependencyInfo::forPlaceholderSwiftModuleStub(
moduleInfo.modulePath, moduleInfo.moduleDocPath,
moduleInfo.moduleSourceInfoPath);
this->dependencies = std::move(dependencies);
return true;
}
static std::vector<std::string> getCompiledCandidates(ASTContext &ctx,
StringRef moduleName,
StringRef interfacePath) {
return ctx.getModuleInterfaceChecker()->getCompiledModuleCandidatesForInterface(
moduleName.str(), interfacePath);
}
ErrorOr<ModuleDependencyInfo> ModuleDependencyScanner::scanInterfaceFile(
Twine moduleInterfacePath, bool isFramework) {
// Create a module filename.
// FIXME: Query the module interface loader to determine an appropriate
// name for the module, which includes an appropriate hash.
auto newExt = file_types::getExtension(file_types::TY_SwiftModuleFile);
auto realModuleName = Ctx.getRealModuleName(moduleName);
llvm::SmallString<32> modulePath = realModuleName.str();
llvm::sys::path::replace_extension(modulePath, newExt);
Optional<ModuleDependencyInfo> Result;
std::error_code code =
astDelegate.runInSubContext(realModuleName.str(),
moduleInterfacePath.str(),
StringRef(),
SourceLoc(),
[&](ASTContext &Ctx, ModuleDecl *mainMod,
ArrayRef<StringRef> BaseArgs,
ArrayRef<StringRef> PCMArgs, StringRef Hash) {
assert(mainMod);
std::string InPath = moduleInterfacePath.str();
auto compiledCandidates = getCompiledCandidates(Ctx, realModuleName.str(),
InPath);
std::vector<std::string> Args(BaseArgs.begin(), BaseArgs.end());
// Add explicit Swift dependency compilation flags
Args.push_back("-explicit-interface-module-build");
Args.push_back("-disable-implicit-swift-modules");
Args.push_back("-Xcc"); Args.push_back("-fno-implicit-modules");
Args.push_back("-Xcc"); Args.push_back("-fno-implicit-module-maps");
for (const auto &candidate : compiledCandidates) {
Args.push_back("-candidate-module-file");
Args.push_back(candidate);
}
// Compute the output path and add it to the command line
SmallString<128> outputPathBase(moduleCachePath);
llvm::sys::path::append(
outputPathBase,
moduleName.str() + "-" + Hash + "." +
file_types::getExtension(file_types::TY_SwiftModuleFile));
Args.push_back("-o");
Args.push_back(outputPathBase.str().str());
std::vector<StringRef> ArgsRefs(Args.begin(), Args.end());
Result = ModuleDependencyInfo::forSwiftInterfaceModule(
outputPathBase.str().str(), InPath, compiledCandidates, ArgsRefs, PCMArgs,
Hash, isFramework);
// Open the interface file.
auto &fs = *Ctx.SourceMgr.getFileSystem();
auto interfaceBuf = fs.getBufferForFile(moduleInterfacePath);
if (!interfaceBuf) {
return interfaceBuf.getError();
}
// Create a source file.
unsigned bufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(interfaceBuf.get()));
auto moduleDecl = ModuleDecl::create(realModuleName, Ctx);
auto sourceFile = new (Ctx) SourceFile(
*moduleDecl, SourceFileKind::Interface, bufferID);
moduleDecl->addAuxiliaryFile(*sourceFile);
// Walk the source file to find the import declarations.
llvm::StringSet<> alreadyAddedModules;
Result->addModuleImport(*sourceFile, alreadyAddedModules);
// Collect implicitly imported modules in case they are not explicitly
// printed in the interface file, e.g. SwiftOnoneSupport.
auto &imInfo = mainMod->getImplicitImportInfo();
for (auto import: imInfo.AdditionalUnloadedImports) {
Result->addModuleImport(import.module.getModulePath(), &alreadyAddedModules);
}
return std::error_code();
});
if (code) {
return code;
}
return *Result;
}
Optional<const ModuleDependencyInfo*> SerializedModuleLoaderBase::getModuleDependencies(
StringRef moduleName, ModuleDependenciesCache &cache,
InterfaceSubContextDelegate &delegate) {
ImportPath::Module::Builder builder(Ctx, moduleName, /*separator=*/'.');
auto modulePath = builder.get();
auto moduleId = modulePath.front().Item;
// Instantiate dependency scanning "loaders".
SmallVector<std::unique_ptr<ModuleDependencyScanner>, 2> scanners;
// Placeholder dependencies must be resolved first, to prevent the
// ModuleDependencyScanner from first discovering artifacts of a previous
// build. Such artifacts are captured as compiledModuleCandidates in the
// dependency graph of the placeholder dependency module itself.
// FIXME: submodules?
scanners.push_back(std::make_unique<PlaceholderSwiftModuleScanner>(
Ctx, LoadMode, moduleId, Ctx.SearchPathOpts.PlaceholderDependencyModuleMap,
delegate));
scanners.push_back(std::make_unique<ModuleDependencyScanner>(
Ctx, LoadMode, moduleId, delegate));
// Check whether there is a module with this name that we can import.
assert(isa<PlaceholderSwiftModuleScanner>(scanners[0].get()) &&
"Expected PlaceholderSwiftModuleScanner as the first dependency scanner loader.");
for (auto &scanner : scanners) {
if (scanner->canImportModule(modulePath, nullptr)) {
// Record the dependencies.
cache.recordDependency(moduleName, *(scanner->dependencies));
return cache.findDependency(moduleName, scanner->dependencies->getKind());
}
}
return None;
}