mirror of
https://github.com/apple/swift.git
synced 2026-06-20 15:42:51 +02:00
[Serialization] Store the explicit module map in swiftmodules
Currently only the top level dependencies get serialized in Swift modules. In practice this is not enough information to fully replay a module import sequence, especially when the dependencies include binary SDK modules that were built elsewhere. In this case we cannot follow the links to its depenencies, since they refer to paths on a different machine or unavailable CAS. During an EBM build, the dependency scanner writes the complete list of dependencies into a json file called the explicit Swift module map -- including the local locations of the dependencies of binary SDK modules. Using this LLDB can replay a module import with 100% accuracy. rdar://170514919
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include "swift/Basic/Assertions.h"
|
||||
#include "swift/Basic/LangOptions.h"
|
||||
#include "swift/Basic/PrettyStackTrace.h"
|
||||
#include "swift/Frontend/ModuleInterfaceLoader.h"
|
||||
#include "swift/Parse/ParseVersion.h"
|
||||
#include "swift/Serialization/SerializedModuleLoader.h"
|
||||
#include "swift/Strings.h"
|
||||
@@ -27,6 +28,7 @@
|
||||
#include "llvm/Support/OnDiskHashTable.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include <optional>
|
||||
|
||||
using namespace swift;
|
||||
using namespace swift::serialization;
|
||||
@@ -503,7 +505,9 @@ static ValidationInfo validateControlBlock(
|
||||
static bool validateInputBlock(
|
||||
llvm::BitstreamCursor &cursor, SmallVectorImpl<uint64_t> &scratch,
|
||||
SmallVectorImpl<SerializationOptions::FileDependency> *dependencies,
|
||||
SmallVectorImpl<SearchPath> *searchPaths) {
|
||||
SmallVectorImpl<SearchPath> *searchPaths,
|
||||
ExplicitSwiftModuleMap *explicitSwiftModuleMap,
|
||||
ExplicitClangModuleMap *explicitClangModuleMap) {
|
||||
SmallVector<StringRef, 4> dependencyDirectories;
|
||||
SmallString<256> dependencyFullPathBuffer;
|
||||
|
||||
@@ -532,21 +536,21 @@ static bool validateInputBlock(
|
||||
}
|
||||
unsigned kind = maybeKind.get();
|
||||
switch (kind) {
|
||||
case input_block::FILE_DEPENDENCY:
|
||||
case input_block::FILE_DEPENDENCY: {
|
||||
StringRef path = blobData;
|
||||
size_t directoryIndex = scratch[4];
|
||||
if (directoryIndex != 0) {
|
||||
if (directoryIndex > dependencyDirectories.size())
|
||||
return true;
|
||||
dependencyFullPathBuffer = dependencyDirectories[directoryIndex - 1];
|
||||
llvm::sys::path::append(dependencyFullPathBuffer, blobData);
|
||||
path = dependencyFullPathBuffer;
|
||||
}
|
||||
|
||||
if (dependencies) {
|
||||
bool isHashBased = scratch[2] != 0;
|
||||
bool isSDKRelative = scratch[3] != 0;
|
||||
|
||||
StringRef path = blobData;
|
||||
size_t directoryIndex = scratch[4];
|
||||
if (directoryIndex != 0) {
|
||||
if (directoryIndex > dependencyDirectories.size())
|
||||
return true;
|
||||
dependencyFullPathBuffer = dependencyDirectories[directoryIndex - 1];
|
||||
llvm::sys::path::append(dependencyFullPathBuffer, blobData);
|
||||
path = dependencyFullPathBuffer;
|
||||
}
|
||||
|
||||
if (isHashBased)
|
||||
dependencies->push_back(
|
||||
SerializationOptions::FileDependency::hashBased(
|
||||
@@ -556,10 +560,9 @@ static bool validateInputBlock(
|
||||
SerializationOptions::FileDependency::modTimeBased(
|
||||
path, isSDKRelative, scratch[0], scratch[1]));
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case input_block::DEPENDENCY_DIRECTORY:
|
||||
if (dependencies)
|
||||
dependencyDirectories.push_back(blobData);
|
||||
dependencyDirectories.push_back(blobData);
|
||||
break;
|
||||
case input_block::SEARCH_PATH:
|
||||
if (searchPaths) {
|
||||
@@ -570,6 +573,77 @@ static bool validateInputBlock(
|
||||
searchPaths->push_back({std::string(blobData), isFramework, isSystem});
|
||||
}
|
||||
break;
|
||||
case input_block::EXPLICIT_MODULE_MAP_ENTRY: {
|
||||
if (!explicitSwiftModuleMap || !explicitClangModuleMap)
|
||||
break;
|
||||
bool isFramework;
|
||||
bool isSystem;
|
||||
bool isBridgedHeaderDependency;
|
||||
unsigned modPathIdx, modDocIdx, modSrcIdx, clangMapIdx;
|
||||
input_block::ExplicitModuleMapEntryLayout::readRecord(
|
||||
scratch, isFramework, isSystem, isBridgedHeaderDependency, modPathIdx,
|
||||
modDocIdx, modSrcIdx, clangMapIdx);
|
||||
StringRef rest, moduleName, moduleAlias, modulePath, moduleDocPath,
|
||||
moduleSourceInfoPath, moduleCacheKey, clangModuleMapPath,
|
||||
headerDependencyPath;
|
||||
std::string modulePathStr, moduleDocPathStr, moduleSourceInfoPathStr,
|
||||
clangModuleMapPathStr;
|
||||
std::tie(moduleName, rest) = blobData.split('\0');
|
||||
std::tie(modulePath, rest) = rest.split('\0');
|
||||
std::tie(moduleAlias, rest) = rest.split('\0');
|
||||
std::tie(moduleDocPath, rest) = rest.split('\0');
|
||||
std::tie(moduleSourceInfoPath, rest) = rest.split('\0');
|
||||
std::tie(moduleCacheKey, rest) = rest.split('\0');
|
||||
std::tie(clangModuleMapPath, rest) = rest.split('\0');
|
||||
auto updatePath = [&](std::string &out, StringRef path,
|
||||
unsigned directoryIndex) {
|
||||
if (!directoryIndex) {
|
||||
out = path.str();
|
||||
return false;
|
||||
}
|
||||
if (directoryIndex > dependencyDirectories.size())
|
||||
return true;
|
||||
dependencyFullPathBuffer = dependencyDirectories[directoryIndex - 1];
|
||||
llvm::sys::path::append(dependencyFullPathBuffer, path);
|
||||
out = dependencyFullPathBuffer.str();
|
||||
return false;
|
||||
};
|
||||
if (updatePath(modulePathStr, modulePath, modPathIdx) ||
|
||||
updatePath(moduleDocPathStr, moduleDocPath, modDocIdx) ||
|
||||
updatePath(moduleSourceInfoPathStr, moduleSourceInfoPath,
|
||||
modSrcIdx) ||
|
||||
updatePath(clangModuleMapPathStr, clangModuleMapPath, clangMapIdx))
|
||||
return true;
|
||||
|
||||
auto optStr = [](std::string s) -> std::optional<std::string> {
|
||||
if (s.empty())
|
||||
return std::nullopt;
|
||||
return s;
|
||||
};
|
||||
if (clangModuleMapPathStr.empty()) {
|
||||
std::vector<std::string> headerDependencyPaths;
|
||||
while (!rest.empty()) {
|
||||
std::tie(headerDependencyPath, rest) = rest.split('\0');
|
||||
headerDependencyPaths.push_back(headerDependencyPath.str());
|
||||
}
|
||||
ExplicitSwiftModuleInputInfo entry(
|
||||
modulePathStr, optStr(moduleAlias.str()), optStr(moduleDocPathStr),
|
||||
optStr(moduleSourceInfoPathStr),
|
||||
headerDependencyPaths.size()
|
||||
? std::optional<std::vector<std::string>>(headerDependencyPaths)
|
||||
: std::nullopt,
|
||||
isFramework, isSystem, optStr(moduleCacheKey.str()));
|
||||
|
||||
explicitSwiftModuleMap->insert({moduleName, std::move(entry)});
|
||||
} else {
|
||||
ExplicitClangModuleInputInfo entry(
|
||||
clangModuleMapPathStr, modulePathStr, optStr(moduleAlias.str()),
|
||||
isFramework, isSystem, isBridgedHeaderDependency,
|
||||
optStr(moduleCacheKey.str()));
|
||||
|
||||
explicitClangModuleMap->insert({moduleName, std::move(entry)});
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
// Unknown metadata record, possibly for use by a future version of the
|
||||
// module format.
|
||||
@@ -607,11 +681,11 @@ bool serialization::isSerializedAST(StringRef data) {
|
||||
}
|
||||
|
||||
ValidationInfo serialization::validateSerializedAST(
|
||||
StringRef data,
|
||||
StringRef requiredSDK,
|
||||
ExtendedValidationInfo *extendedInfo,
|
||||
StringRef data, StringRef requiredSDK, ExtendedValidationInfo *extendedInfo,
|
||||
SmallVectorImpl<SerializationOptions::FileDependency> *dependencies,
|
||||
SmallVectorImpl<SearchPath> *searchPaths,
|
||||
ExplicitSwiftModuleMap *explicitSwiftModuleMap,
|
||||
ExplicitClangModuleMap *explicitClangModuleMap,
|
||||
std::optional<llvm::Triple> target) {
|
||||
ValidationInfo result;
|
||||
|
||||
@@ -667,7 +741,8 @@ ValidationInfo serialization::validateSerializedAST(
|
||||
result.status = Status::Malformed;
|
||||
return result;
|
||||
}
|
||||
if (validateInputBlock(cursor, scratch, dependencies, searchPaths)) {
|
||||
if (validateInputBlock(cursor, scratch, dependencies, searchPaths,
|
||||
explicitSwiftModuleMap, explicitClangModuleMap)) {
|
||||
result.status = Status::Malformed;
|
||||
return result;
|
||||
}
|
||||
@@ -1561,9 +1636,8 @@ ModuleFileSharedCore::ModuleFileSharedCore(
|
||||
unsigned rawImportControl;
|
||||
bool scoped;
|
||||
bool hasSPI;
|
||||
bool hasPath;
|
||||
input_block::ImportedModuleLayout::readRecord(
|
||||
scratch, rawImportControl, scoped, hasSPI, hasPath);
|
||||
scratch, rawImportControl, scoped, hasSPI);
|
||||
auto importKind = getActualImportControl(rawImportControl);
|
||||
if (!importKind) {
|
||||
// We don't know how to import this dependency.
|
||||
@@ -1584,23 +1658,13 @@ ModuleFileSharedCore::ModuleFileSharedCore(
|
||||
(void)recordID;
|
||||
}
|
||||
|
||||
StringRef pathBlob;
|
||||
if (hasPath) {
|
||||
scratch.clear();
|
||||
|
||||
llvm::BitstreamEntry entry =
|
||||
fatalIfUnexpected(cursor.advance(AF_DontPopBlockAtEnd));
|
||||
unsigned recordID = fatalIfUnexpected(
|
||||
cursor.readRecord(entry.ID, scratch, &pathBlob));
|
||||
assert(recordID == input_block::IMPORTED_MODULE_PATH);
|
||||
input_block::ImportedModulePathLayout::readRecord(scratch);
|
||||
(void)recordID;
|
||||
}
|
||||
|
||||
Dependencies.push_back(
|
||||
{blobData, spiBlob, pathBlob, importKind.value(), scoped});
|
||||
{blobData, spiBlob, importKind.value(), scoped});
|
||||
break;
|
||||
}
|
||||
case input_block::EXPLICIT_MODULE_MAP_ENTRY:
|
||||
// Consumed by validateInputBlock.
|
||||
break;
|
||||
case input_block::LINK_LIBRARY: {
|
||||
uint8_t rawKind;
|
||||
bool isStaticLibrary;
|
||||
|
||||
Reference in New Issue
Block a user