Skip to content

Commit 202bca3

Browse files
[ScanDependency] Move binary module validation into scanner
Improve swift dependency scanner by validating and selecting dependency module into scanner. This provides benefits that: * Build system does not need to schedule interface compilation task if the candidate module is picked, it can just use the candidate module directly. * There is no need for forwarding module in the explicit module build. Since the build system is coordinating the build, there is no need for the forwarding module in the module cache to avoid duplicated work, * This also correctly supports all the module loading modes in the dependency scanner. This is achieved by only adding validate and up-to-date binary module as the candidate module for swift interface module dependency. This allows caching build to construct the correct dependency in the CAS. If there is a candidate module for the interface module, dependency scanner will return a binary module dependency in the dependency graph. The legacy behavior is mostly preserved with a hidden frontend flag `-no-scanner-module-validation`, while the scanner output is mostly interchangeable with new scanner behavior with `prefer-interface` module loading mode except the candidate module will not be returned. rdar://123711823
1 parent d97c6ef commit 202bca3

File tree

53 files changed

+279
-186
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+279
-186
lines changed

include/swift/AST/ModuleDependencies.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,12 @@ class ModuleDependenciesCache {
11151115
std::optional<const ModuleDependencyInfo *>
11161116
findDependency(StringRef moduleName) const;
11171117

1118+
/// Look for known existing dependencies.
1119+
///
1120+
/// \returns the cached result.
1121+
const ModuleDependencyInfo &
1122+
findKnownDependency(const ModuleDependencyID &moduleID) const;
1123+
11181124
/// Record dependencies for the given module.
11191125
void recordDependency(StringRef moduleName,
11201126
ModuleDependencyInfo dependencies);

include/swift/AST/SearchPathOptions.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ enum class ModuleSearchPathKind {
3838
RuntimeLibrary,
3939
};
4040

41+
/// Specifies how to load modules when both a module interface and serialized
42+
/// AST are present, or whether to disallow one format or the other altogether.
43+
enum class ModuleLoadingMode {
44+
PreferInterface,
45+
PreferSerialized,
46+
OnlyInterface,
47+
OnlySerialized
48+
};
49+
4150
/// A single module search path that can come from different sources, e.g.
4251
/// framework search paths, import search path etc.
4352
class ModuleSearchPath : public llvm::RefCountedBase<ModuleSearchPath> {
@@ -499,6 +508,12 @@ class SearchPathOptions {
499508
/// original form.
500509
PathObfuscator DeserializedPathRecoverer;
501510

511+
/// Specify the module loading behavior of the compilation.
512+
ModuleLoadingMode ModuleLoadMode = ModuleLoadingMode::PreferSerialized;
513+
514+
/// Legacy scanner search behavior.
515+
bool NoScannerModuleValidation = false;
516+
502517
/// Return all module search paths that (non-recursively) contain a file whose
503518
/// name is in \p Filenames.
504519
SmallVector<const ModuleSearchPath *, 4>
@@ -546,7 +561,9 @@ class SearchPathOptions {
546561
RuntimeResourcePath,
547562
hash_combine_range(RuntimeLibraryImportPaths.begin(),
548563
RuntimeLibraryImportPaths.end()),
549-
DisableModulesValidateSystemDependencies);
564+
DisableModulesValidateSystemDependencies,
565+
NoScannerModuleValidation,
566+
ModuleLoadMode);
550567
}
551568

552569
/// Return a hash code of any components from these options that should

include/swift/Option/FrontendOptions.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,4 +1343,10 @@ def disable_experimental_parser_round_trip : Flag<["-"],
13431343
"disable-experimental-parser-round-trip">,
13441344
HelpText<"Disable round trip through the new swift parser">;
13451345

1346+
def no_scanner_module_validation: Flag<["-"], "no-scanner-module-validation">,
1347+
HelpText<"Do not validate binary modules in scanner and delegate the validation to swift-frontend">;
1348+
def module_load_mode: Separate<["-"], "module-load-mode">,
1349+
MetaVarName<"only-interface|prefer-interface|prefer-serialized|only-serialized">,
1350+
HelpText<"Module loading mode">;
1351+
13461352
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/FileUnit.h"
1717
#include "swift/AST/Module.h"
1818
#include "swift/AST/ModuleLoader.h"
19+
#include "swift/AST/SearchPathOptions.h"
1920
#include "llvm/Support/MemoryBuffer.h"
2021
#include "llvm/Support/PrefixMapper.h"
2122
#include "llvm/TargetParser/Triple.h"
@@ -28,15 +29,6 @@ namespace file_types {
2829
enum ID : uint8_t;
2930
}
3031

31-
/// Specifies how to load modules when both a module interface and serialized
32-
/// AST are present, or whether to disallow one format or the other altogether.
33-
enum class ModuleLoadingMode {
34-
PreferInterface,
35-
PreferSerialized,
36-
OnlyInterface,
37-
OnlySerialized
38-
};
39-
4032
/// How a dependency should be loaded.
4133
///
4234
/// \sa getTransitiveLoadingBehavior

lib/AST/ModuleDependencies.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,13 @@ ModuleDependenciesCache::findDependency(StringRef moduleName) const {
740740
return std::nullopt;
741741
}
742742

743+
const ModuleDependencyInfo &ModuleDependenciesCache::findKnownDependency(
744+
const ModuleDependencyID &moduleID) const {
745+
auto dep = findDependency(moduleID);
746+
assert(dep && "dependency unknown");
747+
return **dep;
748+
}
749+
743750
bool ModuleDependenciesCache::hasDependency(const ModuleDependencyID &moduleID) const {
744751
return hasDependency(moduleID.ModuleName, moduleID.Kind);
745752
}

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ ModuleDependencyScanningWorker::ModuleDependencyScanningWorker(
174174
ScanASTContext,
175175
*static_cast<ModuleInterfaceCheckerImpl *>(
176176
ScanASTContext.getModuleInterfaceChecker()),
177-
&DependencyTracker, ModuleLoadingMode::OnlyInterface);
177+
&DependencyTracker,
178+
ScanCompilerInvocation.getSearchPathOptions().ModuleLoadMode);
178179
}
179180

180181
ModuleDependencyVector

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 63 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,15 @@ updateModuleCacheKey(ModuleDependencyInfo &depInfo,
192192
}
193193

194194
static llvm::Error resolveExplicitModuleInputs(
195-
ModuleDependencyID moduleID, const ModuleDependencyInfo &resolvingDepInfo,
195+
ModuleDependencyID moduleID,
196196
const std::set<ModuleDependencyID> &dependencies,
197197
ModuleDependenciesCache &cache, CompilerInstance &instance,
198198
std::optional<std::set<ModuleDependencyID>> bridgingHeaderDeps) {
199199
// Only need to resolve dependency for following dependencies.
200200
if (moduleID.Kind == ModuleDependencyKind::SwiftPlaceholder)
201201
return llvm::Error::success();
202202

203+
auto &resolvingDepInfo = cache.findKnownDependency(moduleID);
203204
// If the dependency is already finalized, nothing needs to be done.
204205
if (resolvingDepInfo.isFinalized())
205206
return llvm::Error::success();
@@ -242,13 +243,10 @@ static llvm::Error resolveExplicitModuleInputs(
242243

243244
std::vector<std::string> commandLine = resolvingDepInfo.getCommandline();
244245
for (const auto &depModuleID : dependencies) {
245-
const auto optionalDepInfo =
246-
cache.findDependency(depModuleID);
247-
assert(optionalDepInfo.has_value());
248-
const auto depInfo = optionalDepInfo.value();
246+
const auto &depInfo = cache.findKnownDependency(depModuleID);
249247
switch (depModuleID.Kind) {
250248
case swift::ModuleDependencyKind::SwiftInterface: {
251-
auto interfaceDepDetails = depInfo->getAsSwiftInterfaceModule();
249+
auto interfaceDepDetails = depInfo.getAsSwiftInterfaceModule();
252250
assert(interfaceDepDetails && "Expected Swift Interface dependency.");
253251
auto &path = interfaceDepDetails->moduleCacheKey.empty()
254252
? interfaceDepDetails->moduleOutputPath
@@ -257,7 +255,7 @@ static llvm::Error resolveExplicitModuleInputs(
257255
path);
258256
} break;
259257
case swift::ModuleDependencyKind::SwiftBinary: {
260-
auto binaryDepDetails = depInfo->getAsSwiftBinaryModule();
258+
auto binaryDepDetails = depInfo.getAsSwiftBinaryModule();
261259
assert(binaryDepDetails && "Expected Swift Binary Module dependency.");
262260
auto &path = binaryDepDetails->moduleCacheKey.empty()
263261
? binaryDepDetails->compiledModulePath
@@ -280,13 +278,13 @@ static llvm::Error resolveExplicitModuleInputs(
280278
}
281279
} break;
282280
case swift::ModuleDependencyKind::SwiftPlaceholder: {
283-
auto placeholderDetails = depInfo->getAsPlaceholderDependencyModule();
281+
auto placeholderDetails = depInfo.getAsPlaceholderDependencyModule();
284282
assert(placeholderDetails && "Expected Swift Placeholder dependency.");
285283
commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" +
286284
placeholderDetails->compiledModulePath);
287285
} break;
288286
case swift::ModuleDependencyKind::Clang: {
289-
auto clangDepDetails = depInfo->getAsClangModule();
287+
auto clangDepDetails = depInfo.getAsClangModule();
290288
assert(clangDepDetails && "Expected Clang Module dependency.");
291289
if (!resolvingDepInfo.isClangModule()) {
292290
commandLine.push_back("-Xcc");
@@ -303,13 +301,13 @@ static llvm::Error resolveExplicitModuleInputs(
303301
}
304302

305303
// Only need to merge the CASFS from clang importer.
306-
if (auto ID = depInfo->getCASFSRootID())
304+
if (auto ID = depInfo.getCASFSRootID())
307305
rootIDs.push_back(*ID);
308-
if (auto ID = depInfo->getClangIncludeTree())
306+
if (auto ID = depInfo.getClangIncludeTree())
309307
includeTrees.push_back(*ID);
310308
} break;
311309
case swift::ModuleDependencyKind::SwiftSource: {
312-
if (auto E = addBridgingHeaderDeps(*depInfo))
310+
if (auto E = addBridgingHeaderDeps(depInfo))
313311
return E;
314312
break;
315313
}
@@ -390,9 +388,8 @@ static llvm::Error resolveExplicitModuleInputs(
390388
std::vector<std::string> newCommandLine =
391389
dependencyInfoCopy.getBridgingHeaderCommandline();
392390
for (auto bridgingDep : *bridgingHeaderDeps) {
393-
auto dep = cache.findDependency(bridgingDep);
394-
assert(dep && "unknown clang dependency");
395-
auto *clangDep = (*dep)->getAsClangModule();
391+
auto &dep = cache.findKnownDependency(bridgingDep);
392+
auto *clangDep = dep.getAsClangModule();
396393
assert(clangDep && "wrong module dependency kind");
397394
if (!clangDep->moduleCacheKey.empty()) {
398395
newCommandLine.push_back("-Xcc");
@@ -406,19 +403,11 @@ static llvm::Error resolveExplicitModuleInputs(
406403
dependencyInfoCopy.updateBridgingHeaderCommandLine(newCommandLine);
407404
}
408405

409-
if (resolvingDepInfo.isClangModule() ||
410-
resolvingDepInfo.isSwiftInterfaceModule()) {
411-
// Compute and update module cache key.
412-
auto Key = updateModuleCacheKey(dependencyInfoCopy, cache, CAS);
413-
if (!Key)
414-
return Key.takeError();
415-
}
416-
417-
// For binary module, we need to make sure the lookup key is setup here in
418-
// action cache. We just use the CASID of the binary module itself as key.
419-
if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) {
420-
auto Ref =
421-
CASFS.getObjectRefForFileContent(binaryDep->compiledModulePath);
406+
// Compute and update module cache key.
407+
auto setupBinaryCacheKey = [&](StringRef path) -> llvm::Error {
408+
// For binary module, we need to make sure the lookup key is setup here in
409+
// action cache. We just use the CASID of the binary module itself as key.
410+
auto Ref = CASFS.getObjectRefForFileContent(path);
422411
if (!Ref)
423412
return llvm::errorCodeToError(Ref.getError());
424413
assert(*Ref && "Binary module should be loaded into CASFS already");
@@ -432,30 +421,44 @@ static llvm::Error resolveExplicitModuleInputs(
432421
if (auto E = instance.getActionCache().put(CAS.getID(**Ref),
433422
CAS.getID(*Result)))
434423
return E;
424+
return llvm::Error::success();
425+
};
426+
427+
if (resolvingDepInfo.isClangModule() ||
428+
resolvingDepInfo.isSwiftInterfaceModule()) {
429+
auto Key = updateModuleCacheKey(dependencyInfoCopy, cache, CAS);
430+
if (!Key)
431+
return Key.takeError();
432+
} else if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) {
433+
if (auto E = setupBinaryCacheKey(binaryDep->compiledModulePath))
434+
return E;
435435
}
436436
}
437+
437438
dependencyInfoCopy.setIsFinalized(true);
438439
cache.updateDependency(moduleID, dependencyInfoCopy);
439440

440441
return llvm::Error::success();
441442
}
442443

443-
static llvm::Error pruneUnusedVFSOverlays(
444-
ModuleDependencyID moduleID, const ModuleDependencyInfo &resolvingDepInfo,
445-
const std::set<ModuleDependencyID> &dependencies,
446-
ModuleDependenciesCache &cache, CompilerInstance &instance) {
444+
static llvm::Error
445+
pruneUnusedVFSOverlays(ModuleDependencyID moduleID,
446+
const std::set<ModuleDependencyID> &dependencies,
447+
ModuleDependenciesCache &cache,
448+
CompilerInstance &instance) {
449+
// Pruning of unused VFS overlay options for Clang dependencies
450+
// is performed by the Clang dependency scanner.
451+
if (moduleID.Kind == ModuleDependencyKind::Clang)
452+
return llvm::Error::success();
453+
447454
auto isVFSOverlayFlag = [](StringRef arg) {
448455
return arg == "-ivfsoverlay" || arg == "-vfsoverlay";
449456
};
450457
auto isXCCArg = [](StringRef arg) {
451458
return arg == "-Xcc";
452459
};
453460

454-
// Pruning of unused VFS overlay options for Clang dependencies
455-
// is performed by the Clang dependency scanner.
456-
if (!resolvingDepInfo.isSwiftModule())
457-
return llvm::Error::success();
458-
461+
auto &resolvingDepInfo = cache.findKnownDependency(moduleID);
459462
// If this Swift dependency contains any VFS overlay paths,
460463
// then attempt to prune the ones not used by any of the Clang dependencies.
461464
if (!llvm::any_of(resolvingDepInfo.getCommandline(),
@@ -469,10 +472,8 @@ static llvm::Error pruneUnusedVFSOverlays(
469472
// pruned by the Clang dependency scanner.
470473
llvm::StringSet<> usedVFSOverlayPaths;
471474
for (const auto &depModuleID : dependencies) {
472-
const auto optionalDepInfo = cache.findDependency(depModuleID);
473-
assert(optionalDepInfo.has_value());
474-
const auto depInfo = optionalDepInfo.value();
475-
if (auto clangDepDetails = depInfo->getAsClangModule()) {
475+
const auto &depInfo = cache.findKnownDependency(depModuleID);
476+
if (auto clangDepDetails = depInfo.getAsClangModule()) {
476477
const auto &depCommandLine = clangDepDetails->buildCommandLine;
477478
// true if the previous argument was the dash-option of an option pair
478479
bool getNext = false;
@@ -1158,24 +1159,17 @@ generateFullDependencyGraph(const CompilerInstance &instance,
11581159

11591160
for (size_t i = 0; i < allModules.size(); ++i) {
11601161
const auto &module = allModules[i];
1161-
// Grab the completed module dependencies.
1162-
auto moduleDepsQuery = cache.findDependency(module);
1163-
if (!moduleDepsQuery) {
1164-
llvm::report_fatal_error(Twine("Module Dependency Cache missing module") +
1165-
module.ModuleName);
1166-
}
1167-
1168-
auto moduleDeps = *moduleDepsQuery;
1162+
auto &moduleDeps = cache.findKnownDependency(module);
11691163
// Collect all the required pieces to build a ModuleInfo
1170-
auto swiftPlaceholderDeps = moduleDeps->getAsPlaceholderDependencyModule();
1171-
auto swiftTextualDeps = moduleDeps->getAsSwiftInterfaceModule();
1172-
auto swiftSourceDeps = moduleDeps->getAsSwiftSourceModule();
1173-
auto swiftBinaryDeps = moduleDeps->getAsSwiftBinaryModule();
1174-
auto clangDeps = moduleDeps->getAsClangModule();
1164+
auto swiftPlaceholderDeps = moduleDeps.getAsPlaceholderDependencyModule();
1165+
auto swiftTextualDeps = moduleDeps.getAsSwiftInterfaceModule();
1166+
auto swiftSourceDeps = moduleDeps.getAsSwiftSourceModule();
1167+
auto swiftBinaryDeps = moduleDeps.getAsSwiftBinaryModule();
1168+
auto clangDeps = moduleDeps.getAsClangModule();
11751169

11761170
// ModulePath
11771171
const char *modulePathSuffix =
1178-
moduleDeps->isSwiftModule() ? ".swiftmodule" : ".pcm";
1172+
moduleDeps.isSwiftModule() ? ".swiftmodule" : ".pcm";
11791173
std::string modulePath;
11801174
if (swiftTextualDeps)
11811175
modulePath = swiftTextualDeps->moduleOutputPath;
@@ -1196,10 +1190,8 @@ generateFullDependencyGraph(const CompilerInstance &instance,
11961190
sourceFiles = clangDeps->fileDependencies;
11971191
}
11981192

1199-
auto optionalDepInfo = cache.findDependency(module);
1200-
assert(optionalDepInfo.has_value() && "Missing dependency info during graph generation diagnosis.");
1201-
auto depInfo = optionalDepInfo.value();
1202-
auto directDependencies = depInfo->getDirectModuleDependencies();
1193+
auto &depInfo = cache.findKnownDependency(module);
1194+
auto directDependencies = depInfo.getDirectModuleDependencies();
12031195

12041196
// Generate a swiftscan_clang_details_t object based on the dependency kind
12051197
auto getModuleDetails = [&]() -> swiftscan_module_details_t {
@@ -1208,9 +1200,12 @@ generateFullDependencyGraph(const CompilerInstance &instance,
12081200
swiftscan_string_ref_t moduleInterfacePath =
12091201
create_clone(swiftTextualDeps->swiftInterfaceFile.c_str());
12101202
swiftscan_string_ref_t bridgingHeaderPath =
1211-
swiftTextualDeps->textualModuleDetails.bridgingHeaderFile.has_value()
1203+
swiftTextualDeps->textualModuleDetails.bridgingHeaderFile
1204+
.has_value()
12121205
? create_clone(
1213-
swiftTextualDeps->textualModuleDetails.bridgingHeaderFile.value().c_str())
1206+
swiftTextualDeps->textualModuleDetails.bridgingHeaderFile
1207+
.value()
1208+
.c_str())
12141209
: create_null();
12151210
details->kind = SWIFTSCAN_DEPENDENCY_INFO_SWIFT_TEXTUAL;
12161211
// Create an overlay dependencies set according to the output format
@@ -1414,12 +1409,12 @@ computeTransitiveClosureOfExplicitDependencies(
14141409
}
14151410

14161411
static std::set<ModuleDependencyID> computeBridgingHeaderTransitiveDependencies(
1417-
const ModuleDependencyInfo *dep,
1412+
const ModuleDependencyInfo &dep,
14181413
const std::unordered_map<ModuleDependencyID, std::set<ModuleDependencyID>>
14191414
&transitiveClosures,
14201415
const ModuleDependenciesCache &cache) {
14211416
std::set<ModuleDependencyID> result;
1422-
auto *sourceDep = dep->getAsSwiftSourceModule();
1417+
auto *sourceDep = dep.getAsSwiftSourceModule();
14231418
if (!sourceDep)
14241419
return result;
14251420

@@ -1871,22 +1866,19 @@ static void resolveDependencyCommandLineArguments(
18711866
// For main module or binary modules, no command-line to resolve.
18721867
// For Clang modules, their dependencies are resolved by the clang Scanner
18731868
// itself for us.
1874-
auto optionalDeps = cache.findDependency(modID);
1875-
assert(optionalDeps.has_value());
1876-
auto deps = optionalDeps.value();
1869+
auto &deps = cache.findKnownDependency(modID);
18771870
std::optional<std::set<ModuleDependencyID>> bridgingHeaderDeps;
18781871
if (modID.Kind == ModuleDependencyKind::SwiftSource)
18791872
bridgingHeaderDeps = computeBridgingHeaderTransitiveDependencies(
18801873
deps, moduleTransitiveClosures, cache);
18811874

1882-
if (auto E =
1883-
resolveExplicitModuleInputs(modID, *deps, dependencyClosure, cache,
1884-
instance, bridgingHeaderDeps))
1875+
if (auto E = resolveExplicitModuleInputs(modID, dependencyClosure, cache,
1876+
instance, bridgingHeaderDeps))
18851877
instance.getDiags().diagnose(SourceLoc(), diag::error_cas,
18861878
toString(std::move(E)));
18871879

1888-
if (auto E = pruneUnusedVFSOverlays(modID, *deps, dependencyClosure,
1889-
cache, instance))
1880+
if (auto E =
1881+
pruneUnusedVFSOverlays(modID, dependencyClosure, cache, instance))
18901882
instance.getDiags().diagnose(SourceLoc(), diag::error_cas,
18911883
toString(std::move(E)));
18921884
}

0 commit comments

Comments
 (0)