Skip to content

Commit 0966277

Browse files
committed
[Dependency Scanning] Split the ModuleDependencyCache into two: current scan cache & global.
This change causes the cache to be layered with a local "cache" that wraps the global cache, which will serve as the source of truth. The local cache persists only for the duration of a given scanning action, and has a store of references to dependencies resolved as a part of the current scanning action only, while the global cache is the one that persists across scanning actions (e.g. in `DependencyScanningTool`) and stores actual module dependency info values. Only the local cache can answer dependency lookup queries, checking current scanning action results first, before falling back to querying the global cache, with queries disambiguated by the current scannning action's search paths, ensuring we never resolve a dependency lookup query with a module info that could not be found in the current action's search paths. This change is required because search-path disambiguation can lead to false-negatives: for example, the Clang dependency scanner may find modules relative to the compiler's path that are not on the compiler's direct search paths. While such false-negative query responses should be functionally safe, we rely on the current scanning action's results being always-present-in-the-cache for the scanner's functionality. This layering ensures that the cache use-sites remain unchanged and that we get both: preserved global state which can be queried disambiguated with the search path details, and an always-consistent local (current action) cache state.
1 parent 2d89d9f commit 0966277

13 files changed

+438
-243
lines changed

include/swift/AST/ModuleDependencies.h

Lines changed: 147 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/ADT/StringSet.h"
2626
#include <string>
2727
#include <vector>
28+
#include <unordered_map>
2829

2930
namespace swift {
3031

@@ -35,7 +36,8 @@ class Identifier;
3536

3637
/// Which kind of module dependencies we are looking for.
3738
enum class ModuleDependenciesKind : int8_t {
38-
SwiftTextual,
39+
FirstKind,
40+
SwiftTextual = FirstKind,
3941
SwiftBinary,
4042
// Placeholder dependencies are a kind of dependencies used only by the
4143
// dependency scanner. They are swift modules that the scanner will not be
@@ -61,6 +63,14 @@ enum class ModuleDependenciesKind : int8_t {
6163
// of all targets, individually, have been computed.
6264
SwiftPlaceholder,
6365
Clang,
66+
LastKind = Clang + 1
67+
};
68+
69+
struct ModuleDependenciesKindHash {
70+
std::size_t operator()(ModuleDependenciesKind k) const {
71+
using UnderlyingType = std::underlying_type<ModuleDependenciesKind>::type;
72+
return std::hash<UnderlyingType>{}(static_cast<UnderlyingType>(k));
73+
}
6474
};
6575

6676
/// Details of a given module used for dependency scanner cache queries.
@@ -409,29 +419,30 @@ class ModuleDependencies {
409419
};
410420

411421
using ModuleDependencyID = std::pair<std::string, ModuleDependenciesKind>;
422+
using ModuleDependenciesVector = llvm::SmallVector<ModuleDependencies, 1>;
412423

413424
/// A cache describing the set of module dependencies that has been queried
414-
/// thus far.
415-
class ModuleDependenciesCache {
416-
using ModuleDependenciesVector = llvm::SmallVector<ModuleDependencies, 1>;
417-
425+
/// thus far. This cache records/stores the actual Dependency values and can be
426+
/// preserved across different scanning actions (e.g. in
427+
/// `DependencyScanningTool`). It is not to be queried directly, but is rather
428+
/// meant to be wrapped in an instance of `ModuleDependenciesCache`, responsible
429+
/// for recording new dependencies and answering cache queries in a given scan.
430+
/// Queries to this cache must be disambiguated with a set of search paths to
431+
/// ensure that the returned cached dependency was one that can be found in the
432+
/// current scanning action's filesystem view.
433+
class GlobalModuleDependenciesCache {
418434
/// All cached module dependencies, in the order in which they were
419435
/// encountered.
420436
std::vector<ModuleDependencyID> AllModules;
421437

422-
/// Dependencies for Textual Swift modules that have already been computed.
423-
/// This maps a module's id (name, kind) to a vector of Dependency objects, which correspond
424-
/// to instances of the same module that may have been found in different sets of search paths.
425-
llvm::StringMap<ModuleDependenciesVector> SwiftTextualModuleDependencies;
426-
427-
/// Dependencies for Binary Swift modules that have already been computed.
428-
llvm::StringMap<ModuleDependenciesVector> SwiftBinaryModuleDependencies;
429-
430-
/// Dependencies for Swift placeholder dependency modules that have already been computed.
431-
llvm::StringMap<ModuleDependenciesVector> SwiftPlaceholderModuleDependencies;
432-
433-
/// Dependencies for Clang modules that have already been computed.
434-
llvm::StringMap<ModuleDependenciesVector> ClangModuleDependencies;
438+
/// Dependencies for modules that have already been computed.
439+
/// This maps a dependency kind to a map of a module's name to a vector of Dependency objects,
440+
/// which correspond to instances of the same module that may have been found
441+
/// in different sets of search paths.
442+
std::unordered_map<ModuleDependenciesKind,
443+
llvm::StringMap<ModuleDependenciesVector>,
444+
ModuleDependenciesKindHash>
445+
ModuleDependenciesKindMap;
435446

436447
/// Additional information needed for Clang dependency scanning.
437448
ClangModuleDependenciesCacheImpl *clangImpl = nullptr;
@@ -447,55 +458,148 @@ class ModuleDependenciesCache {
447458

448459
/// Retrieve the dependencies map that corresponds to the given dependency
449460
/// kind.
450-
llvm::StringMap<ModuleDependenciesVector> &getDependenciesMap(
451-
ModuleDependenciesKind kind);
452-
const llvm::StringMap<ModuleDependenciesVector> &getDependenciesMap(
453-
ModuleDependenciesKind kind) const;
461+
llvm::StringMap<ModuleDependenciesVector> &
462+
getDependenciesMap(ModuleDependenciesKind kind);
463+
const llvm::StringMap<ModuleDependenciesVector> &
464+
getDependenciesMap(ModuleDependenciesKind kind) const;
454465

455466
public:
456-
ModuleDependenciesCache() { }
467+
GlobalModuleDependenciesCache();
468+
GlobalModuleDependenciesCache(const GlobalModuleDependenciesCache &) = delete;
469+
GlobalModuleDependenciesCache &
470+
operator=(const GlobalModuleDependenciesCache &) = delete;
457471

458-
ModuleDependenciesCache(const ModuleDependenciesCache &) = delete;
459-
ModuleDependenciesCache &operator=(const ModuleDependenciesCache &) = delete;
472+
virtual ~GlobalModuleDependenciesCache() { destroyClangImpl(); }
460473

461-
~ModuleDependenciesCache() {
462-
destroyClangImpl();
463-
}
474+
private:
475+
/// Enforce clients not being allowed to query this cache directly, it must be
476+
/// wrapped in an instance of `ModuleDependenciesCache`.
477+
friend class ModuleDependenciesCache;
464478

465479
/// Set the Clang-specific implementation data.
466-
void setClangImpl(
467-
ClangModuleDependenciesCacheImpl *clangImpl,
468-
void (*clangImplDeleter)(ClangModuleDependenciesCacheImpl *)) {
480+
virtual void
481+
setClangImpl(ClangModuleDependenciesCacheImpl *clangImpl,
482+
void (*clangImplDeleter)(ClangModuleDependenciesCacheImpl *)) {
469483
destroyClangImpl();
470484

471485
this->clangImpl = clangImpl;
472486
this->clangImplDeleter = clangImplDeleter;
473487
}
474488

489+
/// Retrieve the Clang-specific implementation data;
490+
ClangModuleDependenciesCacheImpl *getClangImpl() const { return clangImpl; }
491+
492+
/// Whether we have cached dependency information for the given module.
493+
bool hasDependencies(StringRef moduleName,
494+
ModuleLookupSpecifics details) const;
495+
496+
/// Look for module dependencies for a module with the given name given
497+
/// current search paths.
498+
///
499+
/// \returns the cached result, or \c None if there is no cached entry.
500+
Optional<ModuleDependencies>
501+
findDependencies(StringRef moduleName, ModuleLookupSpecifics details) const;
502+
503+
public:
504+
/// Look for module dependencies for a module with the given name.
505+
/// This method has a deliberately-obtuse name to indicate that it is not to
506+
/// be used for general queries.
507+
///
508+
/// \returns the cached result, or \c None if there is no cached entry.
509+
Optional<ModuleDependenciesVector>
510+
findAllDependenciesIrrespectiveOfSearchPaths(
511+
StringRef moduleName, Optional<ModuleDependenciesKind> kind) const;
512+
513+
/// Record dependencies for the given module.
514+
const ModuleDependencies *recordDependencies(StringRef moduleName,
515+
ModuleDependencies dependencies);
516+
517+
/// Update stored dependencies for the given module.
518+
const ModuleDependencies *updateDependencies(ModuleDependencyID moduleID,
519+
ModuleDependencies dependencies);
520+
521+
/// Reference the list of all module dependencies.
522+
const std::vector<ModuleDependencyID> &getAllModules() const {
523+
return AllModules;
524+
}
525+
};
526+
527+
/// This "local" dependencies cache persists only for the duration of a given
528+
/// scanning action, and wraps an instance of a `GlobalModuleDependenciesCache`
529+
/// which may carry cached scanning information from prior scanning actions.
530+
/// This cache maintains a store of references to all dependencies found within
531+
/// the current scanning action (with their values stored in the global Cache),
532+
/// since these do not require clients to disambiguate them with search paths.
533+
class ModuleDependenciesCache {
534+
private:
535+
GlobalModuleDependenciesCache &globalCache;
536+
537+
/// References to data in `globalCache` for dependencies accimulated during
538+
/// the current scanning action.
539+
std::unordered_map<ModuleDependenciesKind,
540+
llvm::StringMap<const ModuleDependencies *>,
541+
ModuleDependenciesKindHash>
542+
ModuleDependenciesKindMap;
543+
544+
/// Retrieve the dependencies map that corresponds to the given dependency
545+
/// kind.
546+
llvm::StringMap<const ModuleDependencies *> &
547+
getDependencyReferencesMap(ModuleDependenciesKind kind);
548+
const llvm::StringMap<const ModuleDependencies *> &
549+
getDependencyReferencesMap(ModuleDependenciesKind kind) const;
550+
551+
/// Local cache results lookup, only for modules which were discovered during
552+
/// the current scanner invocation.
553+
bool hasDependencies(StringRef moduleName,
554+
Optional<ModuleDependenciesKind> kind) const;
555+
556+
/// Local cache results lookup, only for modules which were discovered during
557+
/// the current scanner invocation.
558+
Optional<const ModuleDependencies *>
559+
findDependencies(StringRef moduleName,
560+
Optional<ModuleDependenciesKind> kind) const;
561+
562+
public:
563+
ModuleDependenciesCache(GlobalModuleDependenciesCache &globalCache);
564+
ModuleDependenciesCache(const ModuleDependenciesCache &) = delete;
565+
ModuleDependenciesCache &operator=(const ModuleDependenciesCache &) = delete;
566+
virtual ~ModuleDependenciesCache() {}
567+
568+
public:
569+
/// Set the Clang-specific implementation data.
570+
void
571+
setClangImpl(ClangModuleDependenciesCacheImpl *clangImpl,
572+
void (*clangImplDeleter)(ClangModuleDependenciesCacheImpl *)) {
573+
globalCache.setClangImpl(clangImpl, clangImplDeleter);
574+
}
575+
475576
/// Retrieve the Clang-specific implementation data;
476577
ClangModuleDependenciesCacheImpl *getClangImpl() const {
477-
return clangImpl;
578+
return globalCache.getClangImpl();
478579
}
479580

480581
/// Whether we have cached dependency information for the given module.
481582
bool hasDependencies(StringRef moduleName,
482583
ModuleLookupSpecifics details) const;
483584

484-
/// Look for module dependencies for a module with the given name given current search paths.
585+
/// Look for module dependencies for a module with the given name given
586+
/// current search paths.
485587
///
486588
/// \returns the cached result, or \c None if there is no cached entry.
487-
Optional<ModuleDependencies> findDependencies(
488-
StringRef moduleName,
489-
ModuleLookupSpecifics details) const;
589+
Optional<ModuleDependencies>
590+
findDependencies(StringRef moduleName, ModuleLookupSpecifics details) const;
490591

491592
/// Look for module dependencies for a module with the given name.
492-
/// This method has a deliberately-obtuse name to indicate that it is not to be used for general
493-
/// queries.
593+
/// This method has a deliberately-obtuse name to indicate that it is not to
594+
/// be used for general queries.
494595
///
495596
/// \returns the cached result, or \c None if there is no cached entry.
496-
Optional<ModuleDependenciesVector> findAllDependenciesIrrespectiveOfSearchPaths(
497-
StringRef moduleName,
498-
Optional<ModuleDependenciesKind> kind) const;
597+
Optional<ModuleDependenciesVector>
598+
findAllDependenciesIrrespectiveOfSearchPaths(
599+
StringRef moduleName, Optional<ModuleDependenciesKind> kind) const {
600+
return globalCache.findAllDependenciesIrrespectiveOfSearchPaths(moduleName,
601+
kind);
602+
}
499603

500604
/// Record dependencies for the given module.
501605
void recordDependencies(StringRef moduleName,
@@ -507,10 +611,10 @@ class ModuleDependenciesCache {
507611

508612
/// Reference the list of all module dependencies.
509613
const std::vector<ModuleDependencyID> &getAllModules() const {
510-
return AllModules;
614+
return globalCache.getAllModules();
511615
}
512616
};
513617

514-
}
618+
} // namespace swift
515619

516620
#endif /* SWIFT_AST_MODULE_DEPENDENCIES_H */

include/swift/DependencyScan/DependencyScanningTool.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class DependencyScanningTool {
5959

6060
/// Writes the current `SharedCache` instance to a specified FileSystem path.
6161
void serializeCache(llvm::StringRef path);
62-
/// Loads an instance of a `ModuleDependenciesCache` to serve as the `SharedCache`
62+
/// Loads an instance of a `GlobalModuleDependenciesCache` to serve as the `SharedCache`
6363
/// from a specified FileSystem path.
6464
bool loadCache(llvm::StringRef path);
6565
/// Discard the tool's current `SharedCache` and start anew.
@@ -73,7 +73,7 @@ class DependencyScanningTool {
7373

7474
/// Shared cache of module dependencies, re-used by individual full-scan queries
7575
/// during the lifetime of this Tool.
76-
std::unique_ptr<ModuleDependenciesCache> SharedCache;
76+
std::unique_ptr<GlobalModuleDependenciesCache> SharedCache;
7777

7878
/// Shared cache of compiler instances created during batch scanning, corresponding to
7979
/// command-line options specified in the batch scan input entry.

include/swift/DependencyScan/ScanDependencies.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,18 @@ namespace swift {
2727
class CompilerInvocation;
2828
class CompilerInstance;
2929
class ModuleDependenciesCache;
30+
class GlobalModuleDependenciesCache;
3031

3132
namespace dependencies {
3233

34+
//using CompilerArgInstanceCacheMap =
35+
// llvm::StringMap<std::pair<std::unique_ptr<CompilerInstance>,
36+
// std::unique_ptr<ModuleDependenciesCache>>>;
37+
3338
using CompilerArgInstanceCacheMap =
34-
llvm::StringMap<std::pair<std::unique_ptr<CompilerInstance>,
35-
std::unique_ptr<ModuleDependenciesCache>>>;
39+
llvm::StringMap<std::tuple<std::unique_ptr<CompilerInstance>,
40+
std::unique_ptr<GlobalModuleDependenciesCache>,
41+
std::unique_ptr<ModuleDependenciesCache>>>;
3642

3743
struct BatchScanInput {
3844
llvm::StringRef moduleName;

include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class MemoryBuffer;
2323
namespace swift {
2424

2525
class DiagnosticEngine;
26-
class ModuleDependenciesCache;
26+
class GlobalModuleDependenciesCache;
2727

2828
namespace dependencies {
2929
namespace module_dependency_cache_serialization {
@@ -160,23 +160,23 @@ using ClangModuleDetailsLayout =
160160
/// Tries to read the dependency graph from the given buffer.
161161
/// Returns \c true if there was an error.
162162
bool readInterModuleDependenciesCache(llvm::MemoryBuffer &buffer,
163-
ModuleDependenciesCache &cache);
163+
GlobalModuleDependenciesCache &cache);
164164

165165
/// Tries to read the dependency graph from the given path name.
166166
/// Returns true if there was an error.
167167
bool readInterModuleDependenciesCache(llvm::StringRef path,
168-
ModuleDependenciesCache &cache);
168+
GlobalModuleDependenciesCache &cache);
169169

170170
/// Tries to write the dependency graph to the given path name.
171171
/// Returns true if there was an error.
172172
bool writeInterModuleDependenciesCache(DiagnosticEngine &diags,
173173
llvm::StringRef path,
174-
const ModuleDependenciesCache &cache);
174+
const GlobalModuleDependenciesCache &cache);
175175

176176
/// Tries to write out the given dependency cache with the given
177177
/// bitstream writer.
178178
void writeInterModuleDependenciesCache(llvm::BitstreamWriter &Out,
179-
const ModuleDependenciesCache &cache);
179+
const GlobalModuleDependenciesCache &cache);
180180

181181
} // end namespace module_dependency_cache_serialization
182182
} // end namespace dependencies

include/swift/Frontend/FrontendOptions.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,10 +309,6 @@ class FrontendOptions {
309309
/// Emit remarks indicating use of the serialized module dependency scanning cache
310310
bool EmitDependencyScannerCacheRemarks = false;
311311

312-
/// After performing a dependency scanning action, serialize and deserialize the
313-
/// dependency cache before producing the result.
314-
bool TestDependencyScannerCacheSerialization = false;
315-
316312
/// When performing an incremental build, ensure that cross-module incremental
317313
/// build metadata is available in any swift modules emitted by this frontend
318314
/// job.

0 commit comments

Comments
 (0)