[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.
This commit is contained in:
Artem Chikin
2021-08-04 18:19:36 -07:00
parent 700b11daef
commit 9429136112
13 changed files with 433 additions and 238 deletions

View File

@@ -36,14 +36,14 @@ class Deserializer {
bool readSignature();
bool enterGraphBlock();
bool readMetadata();
bool readGraph(ModuleDependenciesCache &cache);
bool readGraph(GlobalModuleDependenciesCache &cache);
llvm::Optional<std::string> getIdentifier(unsigned n);
llvm::Optional<std::vector<std::string>> getArray(unsigned n);
public:
Deserializer(llvm::MemoryBufferRef Data) : Cursor(Data) {}
bool readInterModuleDependenciesCache(ModuleDependenciesCache &cache);
bool readInterModuleDependenciesCache(GlobalModuleDependenciesCache &cache);
};
} // end namespace
@@ -146,7 +146,7 @@ bool Deserializer::readMetadata() {
/// all of the file's identifiers and arrays of identifiers, followed by
/// consuming individual module info records and registering them into the
/// cache.
bool Deserializer::readGraph(ModuleDependenciesCache &cache) {
bool Deserializer::readGraph(GlobalModuleDependenciesCache &cache) {
using namespace graph_block;
bool hasCurrentModule = false;
@@ -406,7 +406,7 @@ bool Deserializer::readGraph(ModuleDependenciesCache &cache) {
}
bool Deserializer::readInterModuleDependenciesCache(
ModuleDependenciesCache &cache) {
GlobalModuleDependenciesCache &cache) {
using namespace graph_block;
if (readSignature())
@@ -460,14 +460,14 @@ llvm::Optional<std::vector<std::string>> Deserializer::getArray(unsigned n) {
bool swift::dependencies::module_dependency_cache_serialization::
readInterModuleDependenciesCache(llvm::MemoryBuffer &buffer,
ModuleDependenciesCache &cache) {
GlobalModuleDependenciesCache &cache) {
Deserializer deserializer(buffer.getMemBufferRef());
return deserializer.readInterModuleDependenciesCache(cache);
}
bool swift::dependencies::module_dependency_cache_serialization::
readInterModuleDependenciesCache(StringRef path,
ModuleDependenciesCache &cache) {
GlobalModuleDependenciesCache &cache) {
PrettyStackTraceStringAction stackTrace(
"loading inter-module dependency graph", path);
auto buffer = llvm::MemoryBuffer::getFile(path);
@@ -571,7 +571,7 @@ class Serializer {
AbbrCodes[Layout::Code] = Layout::emitAbbrev(Out);
}
void collectStringsAndArrays(const ModuleDependenciesCache &cache);
void collectStringsAndArrays(const GlobalModuleDependenciesCache &cache);
void emitBlockID(unsigned ID, StringRef name,
SmallVectorImpl<unsigned char> &nameBuffer);
@@ -593,7 +593,7 @@ public:
Serializer(llvm::BitstreamWriter &ExistingOut) : Out(ExistingOut) {}
public:
void writeInterModuleDependenciesCache(const ModuleDependenciesCache &cache);
void writeInterModuleDependenciesCache(const GlobalModuleDependenciesCache &cache);
};
} // end namespace
@@ -742,6 +742,8 @@ void Serializer::writeModuleInfo(ModuleDependencyID moduleID,
break;
}
default:
llvm_unreachable("Unhandled dependency kind.");
}
}
@@ -812,7 +814,7 @@ unsigned Serializer::getArray(ModuleDependencyID moduleID,
return arrayIter->second;
}
void Serializer::collectStringsAndArrays(const ModuleDependenciesCache &cache) {
void Serializer::collectStringsAndArrays(const GlobalModuleDependenciesCache &cache) {
for (auto &moduleID : cache.getAllModules()) {
auto dependencyInfos = cache.findAllDependenciesIrrespectiveOfSearchPaths(
moduleID.first, moduleID.second);
@@ -876,13 +878,15 @@ void Serializer::collectStringsAndArrays(const ModuleDependenciesCache &cache) {
clangDeps->fileDependencies);
break;
}
default:
llvm_unreachable("Unhandled dependency kind.");
}
}
}
}
void Serializer::writeInterModuleDependenciesCache(
const ModuleDependenciesCache &cache) {
const GlobalModuleDependenciesCache &cache) {
// Write the header
writeSignature();
writeBlockInfoBlock();
@@ -930,14 +934,14 @@ void Serializer::writeInterModuleDependenciesCache(
void swift::dependencies::module_dependency_cache_serialization::
writeInterModuleDependenciesCache(llvm::BitstreamWriter &Out,
const ModuleDependenciesCache &cache) {
const GlobalModuleDependenciesCache &cache) {
Serializer serializer{Out};
serializer.writeInterModuleDependenciesCache(cache);
}
bool swift::dependencies::module_dependency_cache_serialization::
writeInterModuleDependenciesCache(DiagnosticEngine &diags, StringRef path,
const ModuleDependenciesCache &cache) {
const GlobalModuleDependenciesCache &cache) {
PrettyStackTraceStringAction stackTrace(
"saving inter-module dependency graph", path);
return withOutputFile(diags, path, [&](llvm::raw_ostream &out) {