Skip to content

Commit ce98d99

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 1fa0179 commit ce98d99

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
@@ -1332,4 +1332,10 @@ def disable_experimental_parser_round_trip : Flag<["-"],
13321332
"disable-experimental-parser-round-trip">,
13331333
HelpText<"Disable round trip through the new swift parser">;
13341334

1335+
def no_scanner_module_validation: Flag<["-"], "no-scanner-module-validation">,
1336+
HelpText<"Do not validate binary modules in scanner and delegate the validation to swift-frontend">;
1337+
def module_load_mode: Separate<["-"], "module-load-mode">,
1338+
MetaVarName<"only-interface|prefer-interface|prefer-serialized|only-serialized">,
1339+
HelpText<"Module loading mode">;
1340+
13351341
} // 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
@@ -266,13 +264,13 @@ static llvm::Error resolveExplicitModuleInputs(
266264
path);
267265
} break;
268266
case swift::ModuleDependencyKind::SwiftPlaceholder: {
269-
auto placeholderDetails = depInfo->getAsPlaceholderDependencyModule();
267+
auto placeholderDetails = depInfo.getAsPlaceholderDependencyModule();
270268
assert(placeholderDetails && "Expected Swift Placeholder dependency.");
271269
commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" +
272270
placeholderDetails->compiledModulePath);
273271
} break;
274272
case swift::ModuleDependencyKind::Clang: {
275-
auto clangDepDetails = depInfo->getAsClangModule();
273+
auto clangDepDetails = depInfo.getAsClangModule();
276274
assert(clangDepDetails && "Expected Clang Module dependency.");
277275
if (!resolvingDepInfo.isClangModule()) {
278276
commandLine.push_back("-Xcc");
@@ -296,13 +294,13 @@ static llvm::Error resolveExplicitModuleInputs(
296294
}
297295

298296
// Only need to merge the CASFS from clang importer.
299-
if (auto ID = depInfo->getCASFSRootID())
297+
if (auto ID = depInfo.getCASFSRootID())
300298
rootIDs.push_back(*ID);
301-
if (auto ID = depInfo->getClangIncludeTree())
299+
if (auto ID = depInfo.getClangIncludeTree())
302300
includeTrees.push_back(*ID);
303301
} break;
304302
case swift::ModuleDependencyKind::SwiftSource: {
305-
if (auto E = addBridgingHeaderDeps(*depInfo))
303+
if (auto E = addBridgingHeaderDeps(depInfo))
306304
return E;
307305
break;
308306
}
@@ -383,9 +381,8 @@ static llvm::Error resolveExplicitModuleInputs(
383381
std::vector<std::string> newCommandLine =
384382
dependencyInfoCopy.getBridgingHeaderCommandline();
385383
for (auto bridgingDep : *bridgingHeaderDeps) {
386-
auto dep = cache.findDependency(bridgingDep);
387-
assert(dep && "unknown clang dependency");
388-
auto *clangDep = (*dep)->getAsClangModule();
384+
auto &dep = cache.findKnownDependency(bridgingDep);
385+
auto *clangDep = dep.getAsClangModule();
389386
assert(clangDep && "wrong module dependency kind");
390387
if (!clangDep->moduleCacheKey.empty()) {
391388
newCommandLine.push_back("-Xcc");
@@ -399,19 +396,11 @@ static llvm::Error resolveExplicitModuleInputs(
399396
dependencyInfoCopy.updateBridgingHeaderCommandLine(newCommandLine);
400397
}
401398

402-
if (resolvingDepInfo.isClangModule() ||
403-
resolvingDepInfo.isSwiftInterfaceModule()) {
404-
// Compute and update module cache key.
405-
auto Key = updateModuleCacheKey(dependencyInfoCopy, cache, CAS);
406-
if (!Key)
407-
return Key.takeError();
408-
}
409-
410-
// For binary module, we need to make sure the lookup key is setup here in
411-
// action cache. We just use the CASID of the binary module itself as key.
412-
if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) {
413-
auto Ref =
414-
CASFS.getObjectRefForFileContent(binaryDep->compiledModulePath);
399+
// Compute and update module cache key.
400+
auto setupBinaryCacheKey = [&](StringRef path) -> llvm::Error {
401+
// For binary module, we need to make sure the lookup key is setup here in
402+
// action cache. We just use the CASID of the binary module itself as key.
403+
auto Ref = CASFS.getObjectRefForFileContent(path);
415404
if (!Ref)
416405
return llvm::errorCodeToError(Ref.getError());
417406
assert(*Ref && "Binary module should be loaded into CASFS already");
@@ -425,30 +414,44 @@ static llvm::Error resolveExplicitModuleInputs(
425414
if (auto E = instance.getActionCache().put(CAS.getID(**Ref),
426415
CAS.getID(*Result)))
427416
return E;
417+
return llvm::Error::success();
418+
};
419+
420+
if (resolvingDepInfo.isClangModule() ||
421+
resolvingDepInfo.isSwiftInterfaceModule()) {
422+
auto Key = updateModuleCacheKey(dependencyInfoCopy, cache, CAS);
423+
if (!Key)
424+
return Key.takeError();
425+
} else if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) {
426+
if (auto E = setupBinaryCacheKey(binaryDep->compiledModulePath))
427+
return E;
428428
}
429429
}
430+
430431
dependencyInfoCopy.setIsFinalized(true);
431432
cache.updateDependency(moduleID, dependencyInfoCopy);
432433

433434
return llvm::Error::success();
434435
}
435436

436-
static llvm::Error pruneUnusedVFSOverlays(
437-
ModuleDependencyID moduleID, const ModuleDependencyInfo &resolvingDepInfo,
438-
const std::set<ModuleDependencyID> &dependencies,
439-
ModuleDependenciesCache &cache, CompilerInstance &instance) {
437+
static llvm::Error
438+
pruneUnusedVFSOverlays(ModuleDependencyID moduleID,
439+
const std::set<ModuleDependencyID> &dependencies,
440+
ModuleDependenciesCache &cache,
441+
CompilerInstance &instance) {
442+
// Pruning of unused VFS overlay options for Clang dependencies
443+
// is performed by the Clang dependency scanner.
444+
if (moduleID.Kind == ModuleDependencyKind::Clang)
445+
return llvm::Error::success();
446+
440447
auto isVFSOverlayFlag = [](StringRef arg) {
441448
return arg == "-ivfsoverlay" || arg == "-vfsoverlay";
442449
};
443450
auto isXCCArg = [](StringRef arg) {
444451
return arg == "-Xcc";
445452
};
446453

447-
// Pruning of unused VFS overlay options for Clang dependencies
448-
// is performed by the Clang dependency scanner.
449-
if (!resolvingDepInfo.isSwiftModule())
450-
return llvm::Error::success();
451-
454+
auto &resolvingDepInfo = cache.findKnownDependency(moduleID);
452455
// If this Swift dependency contains any VFS overlay paths,
453456
// then attempt to prune the ones not used by any of the Clang dependencies.
454457
if (!llvm::any_of(resolvingDepInfo.getCommandline(),
@@ -462,10 +465,8 @@ static llvm::Error pruneUnusedVFSOverlays(
462465
// pruned by the Clang dependency scanner.
463466
llvm::StringSet<> usedVFSOverlayPaths;
464467
for (const auto &depModuleID : dependencies) {
465-
const auto optionalDepInfo = cache.findDependency(depModuleID);
466-
assert(optionalDepInfo.has_value());
467-
const auto depInfo = optionalDepInfo.value();
468-
if (auto clangDepDetails = depInfo->getAsClangModule()) {
468+
const auto &depInfo = cache.findKnownDependency(depModuleID);
469+
if (auto clangDepDetails = depInfo.getAsClangModule()) {
469470
const auto &depCommandLine = clangDepDetails->buildCommandLine;
470471
// true if the previous argument was the dash-option of an option pair
471472
bool getNext = false;
@@ -1151,24 +1152,17 @@ generateFullDependencyGraph(const CompilerInstance &instance,
11511152

11521153
for (size_t i = 0; i < allModules.size(); ++i) {
11531154
const auto &module = allModules[i];
1154-
// Grab the completed module dependencies.
1155-
auto moduleDepsQuery = cache.findDependency(module);
1156-
if (!moduleDepsQuery) {
1157-
llvm::report_fatal_error(Twine("Module Dependency Cache missing module") +
1158-
module.ModuleName);
1159-
}
1160-
1161-
auto moduleDeps = *moduleDepsQuery;
1155+
auto &moduleDeps = cache.findKnownDependency(module);
11621156
// Collect all the required pieces to build a ModuleInfo
1163-
auto swiftPlaceholderDeps = moduleDeps->getAsPlaceholderDependencyModule();
1164-
auto swiftTextualDeps = moduleDeps->getAsSwiftInterfaceModule();
1165-
auto swiftSourceDeps = moduleDeps->getAsSwiftSourceModule();
1166-
auto swiftBinaryDeps = moduleDeps->getAsSwiftBinaryModule();
1167-
auto clangDeps = moduleDeps->getAsClangModule();
1157+
auto swiftPlaceholderDeps = moduleDeps.getAsPlaceholderDependencyModule();
1158+
auto swiftTextualDeps = moduleDeps.getAsSwiftInterfaceModule();
1159+
auto swiftSourceDeps = moduleDeps.getAsSwiftSourceModule();
1160+
auto swiftBinaryDeps = moduleDeps.getAsSwiftBinaryModule();
1161+
auto clangDeps = moduleDeps.getAsClangModule();
11681162

11691163
// ModulePath
11701164
const char *modulePathSuffix =
1171-
moduleDeps->isSwiftModule() ? ".swiftmodule" : ".pcm";
1165+
moduleDeps.isSwiftModule() ? ".swiftmodule" : ".pcm";
11721166
std::string modulePath;
11731167
if (swiftTextualDeps)
11741168
modulePath = swiftTextualDeps->moduleOutputPath;
@@ -1189,10 +1183,8 @@ generateFullDependencyGraph(const CompilerInstance &instance,
11891183
sourceFiles = clangDeps->fileDependencies;
11901184
}
11911185

1192-
auto optionalDepInfo = cache.findDependency(module);
1193-
assert(optionalDepInfo.has_value() && "Missing dependency info during graph generation diagnosis.");
1194-
auto depInfo = optionalDepInfo.value();
1195-
auto directDependencies = depInfo->getDirectModuleDependencies();
1186+
auto &depInfo = cache.findKnownDependency(module);
1187+
auto directDependencies = depInfo.getDirectModuleDependencies();
11961188

11971189
// Generate a swiftscan_clang_details_t object based on the dependency kind
11981190
auto getModuleDetails = [&]() -> swiftscan_module_details_t {
@@ -1201,9 +1193,12 @@ generateFullDependencyGraph(const CompilerInstance &instance,
12011193
swiftscan_string_ref_t moduleInterfacePath =
12021194
create_clone(swiftTextualDeps->swiftInterfaceFile.c_str());
12031195
swiftscan_string_ref_t bridgingHeaderPath =
1204-
swiftTextualDeps->textualModuleDetails.bridgingHeaderFile.has_value()
1196+
swiftTextualDeps->textualModuleDetails.bridgingHeaderFile
1197+
.has_value()
12051198
? create_clone(
1206-
swiftTextualDeps->textualModuleDetails.bridgingHeaderFile.value().c_str())
1199+
swiftTextualDeps->textualModuleDetails.bridgingHeaderFile
1200+
.value()
1201+
.c_str())
12071202
: create_null();
12081203
details->kind = SWIFTSCAN_DEPENDENCY_INFO_SWIFT_TEXTUAL;
12091204
// Create an overlay dependencies set according to the output format
@@ -1407,12 +1402,12 @@ computeTransitiveClosureOfExplicitDependencies(
14071402
}
14081403

14091404
static std::set<ModuleDependencyID> computeBridgingHeaderTransitiveDependencies(
1410-
const ModuleDependencyInfo *dep,
1405+
const ModuleDependencyInfo &dep,
14111406
const std::unordered_map<ModuleDependencyID, std::set<ModuleDependencyID>>
14121407
&transitiveClosures,
14131408
const ModuleDependenciesCache &cache) {
14141409
std::set<ModuleDependencyID> result;
1415-
auto *sourceDep = dep->getAsSwiftSourceModule();
1410+
auto *sourceDep = dep.getAsSwiftSourceModule();
14161411
if (!sourceDep)
14171412
return result;
14181413

@@ -1863,22 +1858,19 @@ static void resolveDependencyCommandLineArguments(
18631858
// For main module or binary modules, no command-line to resolve.
18641859
// For Clang modules, their dependencies are resolved by the clang Scanner
18651860
// itself for us.
1866-
auto optionalDeps = cache.findDependency(modID);
1867-
assert(optionalDeps.has_value());
1868-
auto deps = optionalDeps.value();
1861+
auto &deps = cache.findKnownDependency(modID);
18691862
std::optional<std::set<ModuleDependencyID>> bridgingHeaderDeps;
18701863
if (modID.Kind == ModuleDependencyKind::SwiftSource)
18711864
bridgingHeaderDeps = computeBridgingHeaderTransitiveDependencies(
18721865
deps, moduleTransitiveClosures, cache);
18731866

1874-
if (auto E =
1875-
resolveExplicitModuleInputs(modID, *deps, dependencyClosure, cache,
1876-
instance, bridgingHeaderDeps))
1867+
if (auto E = resolveExplicitModuleInputs(modID, dependencyClosure, cache,
1868+
instance, bridgingHeaderDeps))
18771869
instance.getDiags().diagnose(SourceLoc(), diag::error_cas,
18781870
toString(std::move(E)));
18791871

1880-
if (auto E = pruneUnusedVFSOverlays(modID, *deps, dependencyClosure,
1881-
cache, instance))
1872+
if (auto E =
1873+
pruneUnusedVFSOverlays(modID, dependencyClosure, cache, instance))
18821874
instance.getDiags().diagnose(SourceLoc(), diag::error_cas,
18831875
toString(std::move(E)));
18841876
}

0 commit comments

Comments
 (0)