//=== ModuleDependencyCacheSerialization.cpp - serialized format -*- C++ -*-==// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/AST/FileSystem.h" #include "swift/AST/ModuleDependencies.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/PrettyStackTrace.h" #include "swift/Basic/Version.h" #include "swift/DependencyScan/SerializedModuleDependencyCacheFormat.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/VirtualOutputBackend.h" #include using namespace swift; using namespace dependencies; using namespace module_dependency_cache_serialization; namespace { ModuleDependencyKind &operator++(ModuleDependencyKind &e) { if (e == ModuleDependencyKind::LastKind) { llvm_unreachable( "Attempting to increment last enum value on ModuleDependencyKind"); } e = ModuleDependencyKind( static_cast::type>(e) + 1); return e; } } // namespace // MARK: Deserialization namespace swift { class ModuleDependenciesCacheDeserializer { std::vector Identifiers; std::vector> ArraysOfIdentifierIDs; std::vector LinkLibraries; std::vector> ArraysOfLinkLibraryIDs; std::vector> MacroDependencies; std::vector> ArraysOfMacroDependenciesIDs; std::vector ImportStatements; std::vector> ArraysOfImportStatementIDs; std::vector> ArraysOfOptionalImportStatementIDs; llvm::BitstreamCursor Cursor; SmallVector Scratch; StringRef BlobData; // These return true if there was an error. bool readSignature(); bool enterGraphBlock(); bool readMetadata(StringRef scannerContextHash); bool readSerializationTime(llvm::sys::TimePoint<> &SerializationTimeStamp); bool readGraph(ModuleDependenciesCache &cache); std::optional getIdentifier(unsigned n); std::optional> getStringArray(unsigned n); std::optional> getLinkLibraryArray(unsigned n); std::optional>> getMacroDependenciesArray(unsigned n); std::optional> getImportStatementInfoArray(unsigned n); std::optional> getOptionalImportStatementInfoArray(unsigned n); std::optional> getModuleDependencyIDArray(unsigned n); public: ModuleDependenciesCacheDeserializer(llvm::MemoryBufferRef Data) : Cursor(Data) {} bool readInterModuleDependenciesCache(ModuleDependenciesCache &cache, llvm::sys::TimePoint<> &serializedCacheTimeStamp); }; } // namespace swift /// Read in the expected signature: IMDC bool ModuleDependenciesCacheDeserializer::readSignature() { for (unsigned char byte : MODULE_DEPENDENCY_CACHE_FORMAT_SIGNATURE) { if (Cursor.AtEndOfStream()) return true; if (auto maybeRead = Cursor.Read(8)) { if (maybeRead.get() != byte) return true; } else { return true; } } return false; } /// Read in the info block and enter the top-level block which represents the /// graph bool ModuleDependenciesCacheDeserializer::enterGraphBlock() { // Read the BLOCKINFO_BLOCK, which contains metadata used when dumping // the binary data with llvm-bcanalyzer. { auto next = Cursor.advance(); if (!next) { consumeError(next.takeError()); return true; } if (next->Kind != llvm::BitstreamEntry::SubBlock) return true; if (next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID) return true; if (!Cursor.ReadBlockInfoBlock()) return true; } // Enters our top-level subblock, // which contains the actual module dependency information. { auto next = Cursor.advance(); if (!next) { consumeError(next.takeError()); return true; } if (next->Kind != llvm::BitstreamEntry::SubBlock) return true; if (next->ID != GRAPH_BLOCK_ID) return true; if (auto err = Cursor.EnterSubBlock(GRAPH_BLOCK_ID)) { consumeError(std::move(err)); return true; } } return false; } /// Read in the serialized file's format version, error/exit if not matching /// current version. bool ModuleDependenciesCacheDeserializer::readMetadata(StringRef scannerContextHash) { using namespace graph_block; auto entry = Cursor.advance(); if (!entry) { consumeError(entry.takeError()); return true; } if (entry->Kind != llvm::BitstreamEntry::Record) return true; auto recordID = Cursor.readRecord(entry->ID, Scratch, &BlobData); if (!recordID) { consumeError(recordID.takeError()); return true; } if (*recordID != METADATA) return true; unsigned majorVersion, minorVersion; MetadataLayout::readRecord(Scratch, majorVersion, minorVersion); if (majorVersion != MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MAJOR || minorVersion != MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR) return true; std::string readScannerContextHash = BlobData.str(); if (readScannerContextHash != scannerContextHash) return true; return false; } bool ModuleDependenciesCacheDeserializer::readSerializationTime(llvm::sys::TimePoint<> &SerializationTimeStamp) { using namespace graph_block; auto entry = Cursor.advance(); if (!entry) { consumeError(entry.takeError()); return true; } if (entry->Kind != llvm::BitstreamEntry::Record) return true; auto recordID = Cursor.readRecord(entry->ID, Scratch, &BlobData); if (!recordID) { consumeError(recordID.takeError()); return true; } if (*recordID != TIME_NODE) return true; TimeLayout::readRecord(Scratch); std::string serializedTimeStamp = BlobData.str(); SerializationTimeStamp = llvm::sys::TimePoint<>(llvm::sys::TimePoint<>::duration(std::stoll(serializedTimeStamp))); return SerializationTimeStamp == llvm::sys::TimePoint<>(); } /// Read in the top-level block's graph structure by first reading in /// all of the file's identifiers and arrays of identifiers, followed by /// consuming individual module info records and registering them into the /// cache. bool ModuleDependenciesCacheDeserializer::readGraph( ModuleDependenciesCache &cache) { using namespace graph_block; bool hasCurrentModule = false; std::string currentModuleName; std::vector currentModuleImports; std::vector currentOptionalModuleImports; std::vector importedSwiftDependenciesIDs; std::vector importedClangDependenciesIDs; std::vector crossImportOverlayDependenciesIDs; std::vector swiftOverlayDependenciesIDs; std::vector linkLibraries; std::vector> macroDependencies; std::vector importStatements; std::vector optionalImportStatements; std::vector auxiliaryFiles; auto addCommonDependencyInfo = [¤tModuleImports, ¤tOptionalModuleImports, &importedClangDependenciesIDs, &auxiliaryFiles, ¯oDependencies](ModuleDependencyInfo &moduleDep) { // Add imports of this module for (const auto &moduleName : currentModuleImports) moduleDep.addModuleImport(moduleName.importIdentifier); // Add optional imports of this module for (const auto &moduleName : currentOptionalModuleImports) moduleDep.addOptionalModuleImport(moduleName.importIdentifier); // Add qualified dependencies of this module moduleDep.setImportedClangDependencies(importedClangDependenciesIDs); // Add any auxiliary files moduleDep.setAuxiliaryFiles(auxiliaryFiles); // Add macro dependencies for (const auto &md : macroDependencies) moduleDep.addMacroDependency(md.first, md.second.LibraryPath, md.second.ExecutablePath); moduleDep.setIsFinalized(true); }; auto addSwiftCommonDependencyInfo = [&importedSwiftDependenciesIDs, &crossImportOverlayDependenciesIDs, &swiftOverlayDependenciesIDs](ModuleDependencyInfo &moduleDep) { moduleDep.setImportedSwiftDependencies(importedSwiftDependenciesIDs); moduleDep.setCrossImportOverlayDependencies( crossImportOverlayDependenciesIDs); moduleDep.setSwiftOverlayDependencies(swiftOverlayDependenciesIDs); }; auto addSwiftTextualDependencyInfo = [this](ModuleDependencyInfo &moduleDep, unsigned bridgingHeaderFileID, unsigned bridgingSourceFilesArrayID, unsigned bridgingModuleDependenciesArrayID, unsigned bridgingHeaderIncludeTreeID) { // Add bridging header file path if (bridgingHeaderFileID != 0) { auto bridgingHeaderFile = getIdentifier(bridgingHeaderFileID); if (!bridgingHeaderFile) llvm::report_fatal_error("Bad bridging header path"); moduleDep.addBridgingHeader(*bridgingHeaderFile); } // Add bridging source files auto bridgingSourceFiles = getStringArray(bridgingSourceFilesArrayID); if (!bridgingSourceFiles) llvm::report_fatal_error("Bad bridging source files"); moduleDep.setHeaderSourceFiles(*bridgingSourceFiles); // Add bridging module dependencies auto bridgingModuleDeps = getStringArray(bridgingModuleDependenciesArrayID); if (!bridgingModuleDeps) llvm::report_fatal_error("Bad bridging module dependencies"); llvm::StringSet<> alreadyAdded; std::vector bridgingModuleDepIDs; for (const auto &mod : bridgingModuleDeps.value()) bridgingModuleDepIDs.push_back( ModuleDependencyID{mod, ModuleDependencyKind::Clang}); moduleDep.setHeaderClangDependencies(bridgingModuleDepIDs); // Add bridging header include tree auto bridgingHeaderIncludeTree = getIdentifier(bridgingHeaderIncludeTreeID); if (!bridgingHeaderIncludeTree) llvm::report_fatal_error("Bad bridging header include tree"); if (!bridgingHeaderIncludeTree->empty()) moduleDep.addBridgingHeaderIncludeTree(*bridgingHeaderIncludeTree); }; while (!Cursor.AtEndOfStream()) { auto entry = cantFail(Cursor.advance(), "Advance bitstream cursor"); if (entry.Kind == llvm::BitstreamEntry::EndBlock) { Cursor.ReadBlockEnd(); assert(Cursor.GetCurrentBitNo() % CHAR_BIT == 0); break; } if (entry.Kind != llvm::BitstreamEntry::Record) llvm::report_fatal_error("Bad bitstream entry kind"); Scratch.clear(); unsigned recordID = cantFail(Cursor.readRecord(entry.ID, Scratch, &BlobData), "Read bitstream record"); switch (recordID) { case METADATA: { // METADATA must appear at the beginning and is read by readMetadata(). llvm::report_fatal_error("Unexpected METADATA record"); break; } case IDENTIFIER_NODE: { // IDENTIFIER_NODE must come before MODULE_NODEs. if (hasCurrentModule) llvm::report_fatal_error("Unexpected IDENTIFIER_NODE record"); IdentifierNodeLayout::readRecord(Scratch); Identifiers.push_back(BlobData.str()); break; } case IDENTIFIER_ARRAY_NODE: { // IDENTIFIER_ARRAY_NODE must come before MODULE_NODEs. if (hasCurrentModule) llvm::report_fatal_error("Unexpected IDENTIFIER_NODE record"); ArrayRef identifierIDs; IdentifierArrayLayout::readRecord(Scratch, identifierIDs); ArraysOfIdentifierIDs.push_back(identifierIDs.vec()); break; } case LINK_LIBRARY_NODE: { unsigned libraryIdentifierID; bool isFramework, isStatic, shouldForceLoad; LinkLibraryLayout::readRecord(Scratch, libraryIdentifierID, isFramework, isStatic, shouldForceLoad); auto libraryIdentifier = getIdentifier(libraryIdentifierID); if (!libraryIdentifier) llvm::report_fatal_error("Bad link library identifier"); LinkLibraries.emplace_back( libraryIdentifier.value(), isFramework ? LibraryKind::Framework : LibraryKind::Library, isStatic, shouldForceLoad); break; } case LINK_LIBRARY_ARRAY_NODE: { ArrayRef identifierIDs; LinkLibraryArrayLayout::readRecord(Scratch, identifierIDs); ArraysOfLinkLibraryIDs.push_back(identifierIDs.vec()); break; } case MACRO_DEPENDENCY_NODE: { unsigned macroModuleNameID, libraryPathID, executablePathID; MacroDependencyLayout::readRecord(Scratch, macroModuleNameID, libraryPathID, executablePathID); auto macroModuleName = getIdentifier(macroModuleNameID); if (!macroModuleName) llvm::report_fatal_error("Bad macro dependency: no module name"); auto libraryPath = getIdentifier(libraryPathID); if (!libraryPath) llvm::report_fatal_error("Bad macro dependency: no library path"); auto executablePath = getIdentifier(executablePathID); if (!executablePath) llvm::report_fatal_error("Bad macro dependency: no executable path"); MacroDependencies.push_back( {macroModuleName.value(), MacroPluginDependency{libraryPath.value(), executablePath.value()}}); break; } case MACRO_DEPENDENCY_ARRAY_NODE: { ArrayRef identifierIDs; MacroDependencyArrayLayout::readRecord(Scratch, identifierIDs); ArraysOfMacroDependenciesIDs.push_back(identifierIDs.vec()); break; } case IMPORT_STATEMENT_NODE: { unsigned importIdentifierID, bufferIdentifierID; unsigned lineNumber, columnNumber; bool isOptional; ImportStatementLayout::readRecord(Scratch, importIdentifierID, bufferIdentifierID, lineNumber, columnNumber, isOptional); auto importIdentifier = getIdentifier(importIdentifierID); if (!importIdentifier) llvm::report_fatal_error("Bad import statement info: no import name"); auto bufferIdentifier = getIdentifier(bufferIdentifierID); if (!bufferIdentifier) llvm::report_fatal_error( "Bad import statement info: no buffer identifier"); ImportStatements.push_back(ScannerImportStatementInfo( importIdentifier.value(), ScannerImportStatementInfo::ImportDiagnosticLocationInfo( bufferIdentifier.value(), lineNumber, columnNumber))); break; } case IMPORT_STATEMENT_ARRAY_NODE: { ArrayRef identifierIDs; ImportStatementArrayLayout::readRecord(Scratch, identifierIDs); ArraysOfImportStatementIDs.push_back(identifierIDs.vec()); break; } case OPTIONAL_IMPORT_STATEMENT_ARRAY_NODE: { ArrayRef identifierIDs; OptionalImportStatementArrayLayout::readRecord(Scratch, identifierIDs); ArraysOfOptionalImportStatementIDs.push_back(identifierIDs.vec()); break; } case MODULE_NODE: { hasCurrentModule = true; unsigned moduleNameID, moduleImportsArrayID, optionalImportsArrayID, linkLibraryArrayID, macroDependencyArrayID, importedSwiftDependenciesIDsArrayID, importedClangDependenciesIDsArrayID, crossImportOverlayDependenciesIDsArrayID, swiftOverlayDependenciesIDsArrayID, moduleCacheKeyID, AuxiliaryFilesArrayID; ModuleInfoLayout::readRecord(Scratch, moduleNameID, moduleImportsArrayID, optionalImportsArrayID, linkLibraryArrayID, macroDependencyArrayID, importedSwiftDependenciesIDsArrayID, importedClangDependenciesIDsArrayID, crossImportOverlayDependenciesIDsArrayID, swiftOverlayDependenciesIDsArrayID, moduleCacheKeyID, AuxiliaryFilesArrayID); auto moduleName = getIdentifier(moduleNameID); if (!moduleName) llvm::report_fatal_error("Bad module name"); currentModuleName = *moduleName; auto optionalImportStatementInfos = getImportStatementInfoArray(moduleImportsArrayID); if (!optionalImportStatementInfos) llvm::report_fatal_error("Bad direct Swift dependencies: no imports"); importStatements = optionalImportStatementInfos.value(); auto optionalOptionalImportStatementInfos = getOptionalImportStatementInfoArray(optionalImportsArrayID); if (!optionalOptionalImportStatementInfos) llvm::report_fatal_error( "Bad direct Swift dependencies: no optional imports"); optionalImportStatements = optionalOptionalImportStatementInfos.value(); auto optionalAuxiliaryFiles = getStringArray(AuxiliaryFilesArrayID); if (optionalAuxiliaryFiles.has_value()) for (const auto &af : optionalAuxiliaryFiles.value()) auxiliaryFiles.push_back(af); auto optionalImportedSwiftDependenciesIDs = getModuleDependencyIDArray(importedSwiftDependenciesIDsArrayID); if (!optionalImportedSwiftDependenciesIDs) llvm::report_fatal_error( "Bad direct Swift dependencies: no qualified dependencies"); importedSwiftDependenciesIDs = optionalImportedSwiftDependenciesIDs.value(); auto optionalImportedClangDependenciesIDs = getModuleDependencyIDArray(importedClangDependenciesIDsArrayID); if (!optionalImportedClangDependenciesIDs) llvm::report_fatal_error( "Bad direct Clang dependencies: no qualified dependencies"); importedClangDependenciesIDs = optionalImportedClangDependenciesIDs.value(); auto optionalCrossImportOverlayDependenciesIDs = getModuleDependencyIDArray(crossImportOverlayDependenciesIDsArrayID); if (!optionalCrossImportOverlayDependenciesIDs) llvm::report_fatal_error( "Bad Cross-Import Overlay dependencies: no qualified dependencies"); crossImportOverlayDependenciesIDs = optionalCrossImportOverlayDependenciesIDs.value(); auto optionalSwiftOverlayDependenciesIDs = getModuleDependencyIDArray(swiftOverlayDependenciesIDsArrayID); if (!optionalSwiftOverlayDependenciesIDs) llvm::report_fatal_error( "Bad Swift Overlay dependencies: no qualified dependencies"); swiftOverlayDependenciesIDs = optionalSwiftOverlayDependenciesIDs.value(); auto optionalLinkLibraries = getLinkLibraryArray(linkLibraryArrayID); if (!optionalLinkLibraries) llvm::report_fatal_error("Bad Link Libraries info"); linkLibraries = *optionalLinkLibraries; auto optionalMacroDependencies = getMacroDependenciesArray(macroDependencyArrayID); if (!optionalMacroDependencies) llvm::report_fatal_error("Bad Macro Dependencies info"); macroDependencies = *optionalMacroDependencies; break; } case SWIFT_INTERFACE_MODULE_DETAILS_NODE: { if (!hasCurrentModule) llvm::report_fatal_error( "Unexpected SWIFT_TEXTUAL_MODULE_DETAILS_NODE record"); unsigned outputPathFileID, interfaceFileID, compiledModuleCandidatesArrayID, buildCommandLineArrayID, contextHashID, isFramework, isStatic, bridgingHeaderFileID, sourceFilesArrayID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, CASFileSystemRootID, bridgingHeaderIncludeTreeID, moduleCacheKeyID, userModuleVersionID; SwiftInterfaceModuleDetailsLayout::readRecord( Scratch, outputPathFileID, interfaceFileID, compiledModuleCandidatesArrayID, buildCommandLineArrayID, contextHashID, isFramework, isStatic, bridgingHeaderFileID, sourceFilesArrayID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, CASFileSystemRootID, bridgingHeaderIncludeTreeID, moduleCacheKeyID, userModuleVersionID); auto outputModulePath = getIdentifier(outputPathFileID); if (!outputModulePath) llvm::report_fatal_error("Bad .swiftmodule output path"); std::optional optionalSwiftInterfaceFile; if (interfaceFileID != 0) { auto swiftInterfaceFile = getIdentifier(interfaceFileID); if (!swiftInterfaceFile) llvm::report_fatal_error("Bad swift interface file path"); optionalSwiftInterfaceFile = *swiftInterfaceFile; } auto compiledModuleCandidates = getStringArray(compiledModuleCandidatesArrayID); if (!compiledModuleCandidates) llvm::report_fatal_error("Bad compiled module candidates"); auto commandLine = getStringArray(buildCommandLineArrayID); if (!commandLine) llvm::report_fatal_error("Bad command line"); auto contextHash = getIdentifier(contextHashID); if (!contextHash) llvm::report_fatal_error("Bad context hash"); // forSwiftInterface API demands references here. std::vector buildCommandRefs; for (auto &arg : *commandLine) buildCommandRefs.push_back(arg); std::vector compiledCandidatesRefs; for (auto &cc : compiledCandidatesRefs) compiledCandidatesRefs.push_back(cc); auto rootFileSystemID = getIdentifier(CASFileSystemRootID); if (!rootFileSystemID) llvm::report_fatal_error("Bad CASFileSystem RootID"); auto moduleCacheKey = getIdentifier(moduleCacheKeyID); if (!moduleCacheKey) llvm::report_fatal_error("Bad moduleCacheKey"); auto userModuleVersion = getIdentifier(userModuleVersionID); if (!userModuleVersion) llvm::report_fatal_error("Bad userModuleVersion"); // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftInterfaceModule( outputModulePath.value(), optionalSwiftInterfaceFile.value(), compiledCandidatesRefs, buildCommandRefs, importStatements, optionalImportStatements, linkLibraries, *contextHash, isFramework, isStatic, *rootFileSystemID, *moduleCacheKey, *userModuleVersion); addCommonDependencyInfo(moduleDep); addSwiftCommonDependencyInfo(moduleDep); addSwiftTextualDependencyInfo( moduleDep, bridgingHeaderFileID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, bridgingHeaderIncludeTreeID); cache.recordDependency(currentModuleName, std::move(moduleDep)); hasCurrentModule = false; break; } case SWIFT_SOURCE_MODULE_DETAILS_NODE: { if (!hasCurrentModule) llvm::report_fatal_error( "Unexpected SWIFT_SOURCE_MODULE_DETAILS_NODE record"); unsigned bridgingHeaderFileID, sourceFilesArrayID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, CASFileSystemRootID, bridgingHeaderIncludeTreeID, buildCommandLineArrayID, bridgingHeaderBuildCommandLineArrayID, chainedBridgingHeaderPathID, chainedBridgingHeaderContentID; SwiftSourceModuleDetailsLayout::readRecord( Scratch, bridgingHeaderFileID, sourceFilesArrayID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, CASFileSystemRootID, bridgingHeaderIncludeTreeID, buildCommandLineArrayID, bridgingHeaderBuildCommandLineArrayID, chainedBridgingHeaderPathID, chainedBridgingHeaderContentID); auto rootFileSystemID = getIdentifier(CASFileSystemRootID); if (!rootFileSystemID) llvm::report_fatal_error("Bad CASFileSystem RootID"); auto commandLine = getStringArray(buildCommandLineArrayID); if (!commandLine) llvm::report_fatal_error("Bad command line"); std::vector buildCommandRefs; for (auto &arg : *commandLine) buildCommandRefs.push_back(arg); std::vector bridgingHeaderBuildCommandRefs; auto bridgingHeaderCommandLine = getStringArray(bridgingHeaderBuildCommandLineArrayID); if (!bridgingHeaderCommandLine) llvm::report_fatal_error("Bad bridging header command line"); for (auto &arg : *bridgingHeaderCommandLine) bridgingHeaderBuildCommandRefs.push_back(arg); // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftSourceModule( *rootFileSystemID, buildCommandRefs, importStatements, optionalImportStatements, bridgingHeaderBuildCommandRefs); // Add source files auto sourceFiles = getStringArray(sourceFilesArrayID); if (!sourceFiles) llvm::report_fatal_error("Bad bridging source files"); for (const auto &file : *sourceFiles) moduleDep.addSourceFile(file); // Add chained bridging header. auto chainedBridgingHeaderPath = getIdentifier(chainedBridgingHeaderPathID); auto chainedBridgingHeaderContent = getIdentifier(chainedBridgingHeaderContentID); if (chainedBridgingHeaderPath && chainedBridgingHeaderContent) moduleDep.setChainedBridgingHeaderBuffer(*chainedBridgingHeaderPath, *chainedBridgingHeaderContent); addCommonDependencyInfo(moduleDep); addSwiftCommonDependencyInfo(moduleDep); addSwiftTextualDependencyInfo( moduleDep, bridgingHeaderFileID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, bridgingHeaderIncludeTreeID); cache.recordDependency(currentModuleName, std::move(moduleDep)); hasCurrentModule = false; break; } case SWIFT_BINARY_MODULE_DETAILS_NODE: { if (!hasCurrentModule) llvm::report_fatal_error( "Unexpected SWIFT_BINARY_MODULE_DETAILS_NODE record"); unsigned compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID, headerImportID, definingInterfacePathID, headerModuleDependenciesArrayID, headerImportsSourceFilesArrayID, isFramework, isStatic, moduleCacheKeyID, userModuleVersionID; SwiftBinaryModuleDetailsLayout::readRecord( Scratch, compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID, headerImportID, definingInterfacePathID, headerModuleDependenciesArrayID, headerImportsSourceFilesArrayID, isFramework, isStatic, moduleCacheKeyID, userModuleVersionID); auto compiledModulePath = getIdentifier(compiledModulePathID); if (!compiledModulePath) llvm::report_fatal_error("Bad compiled module path"); auto moduleDocPath = getIdentifier(moduleDocPathID); if (!moduleDocPath) llvm::report_fatal_error("Bad module doc path"); auto moduleSourceInfoPath = getIdentifier(moduleSourceInfoPathID); if (!moduleSourceInfoPath) llvm::report_fatal_error("Bad module source info path"); auto moduleCacheKey = getIdentifier(moduleCacheKeyID); if (!moduleCacheKey) llvm::report_fatal_error("Bad moduleCacheKey"); auto userModuleVersion = getIdentifier(userModuleVersionID); if (!userModuleVersion) llvm::report_fatal_error("Bad userModuleVersion"); auto headerImport = getIdentifier(headerImportID); if (!headerImport) llvm::report_fatal_error( "Bad binary direct dependencies: no header import"); auto definingInterfacePath = getIdentifier(definingInterfacePathID); if (!definingInterfacePath) llvm::report_fatal_error( "Bad binary direct dependencies: no defining interface path"); // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftBinaryModule( *compiledModulePath, *moduleDocPath, *moduleSourceInfoPath, currentModuleImports, currentOptionalModuleImports, linkLibraries, *headerImport, *definingInterfacePath, isFramework, isStatic, *moduleCacheKey, *userModuleVersion); addCommonDependencyInfo(moduleDep); addSwiftCommonDependencyInfo(moduleDep); auto headerModuleDependencies = getStringArray(headerModuleDependenciesArrayID); if (!headerModuleDependencies) llvm::report_fatal_error("Bad binary direct dependencies: no header " "import module dependencies"); llvm::StringSet<> alreadyAdded; std::vector clangHeaderDependencyIDs; for (const auto &headerDepName : *headerModuleDependencies) clangHeaderDependencyIDs.push_back( ModuleDependencyID{headerDepName, ModuleDependencyKind::Clang}); moduleDep.setHeaderClangDependencies(clangHeaderDependencyIDs); auto headerImportsSourceFiles = getStringArray(headerImportsSourceFilesArrayID); if (!headerImportsSourceFiles) llvm::report_fatal_error( "Bad binary direct dependencies: no header import source files"); moduleDep.setHeaderSourceFiles(*headerImportsSourceFiles); cache.recordDependency(currentModuleName, std::move(moduleDep)); hasCurrentModule = false; break; } case SWIFT_PLACEHOLDER_MODULE_DETAILS_NODE: { if (!hasCurrentModule) llvm::report_fatal_error( "Unexpected SWIFT_PLACEHOLDER_MODULE_DETAILS_NODE record"); unsigned compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID; SwiftPlaceholderModuleDetailsLayout::readRecord( Scratch, compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID); auto compiledModulePath = getIdentifier(compiledModulePathID); if (!compiledModulePath) llvm::report_fatal_error("Bad compiled module path"); auto moduleDocPath = getIdentifier(moduleDocPathID); if (!moduleDocPath) llvm::report_fatal_error("Bad module doc path"); auto moduleSourceInfoPath = getIdentifier(moduleSourceInfoPathID); if (!moduleSourceInfoPath) llvm::report_fatal_error("Bad module source info path"); // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forPlaceholderSwiftModuleStub( *compiledModulePath, *moduleDocPath, *moduleSourceInfoPath); cache.recordDependency(currentModuleName, std::move(moduleDep)); hasCurrentModule = false; break; } case CLANG_MODULE_DETAILS_NODE: { if (!hasCurrentModule) llvm::report_fatal_error("Unexpected CLANG_MODULE_DETAILS_NODE record"); unsigned pcmOutputPathID, mappedPCMPathID, moduleMapPathID, contextHashID, commandLineArrayID, fileDependenciesArrayID, CASFileSystemRootID, clangIncludeTreeRootID, moduleCacheKeyID, isSystem; ClangModuleDetailsLayout::readRecord( Scratch, pcmOutputPathID, mappedPCMPathID, moduleMapPathID, contextHashID, commandLineArrayID, fileDependenciesArrayID, CASFileSystemRootID, clangIncludeTreeRootID, moduleCacheKeyID, isSystem); auto pcmOutputPath = getIdentifier(pcmOutputPathID); if (!pcmOutputPath) llvm::report_fatal_error("Bad pcm output path"); auto mappedPCMPath = getIdentifier(mappedPCMPathID); if (!mappedPCMPath) llvm::report_fatal_error("Bad mapped pcm path"); auto moduleMapPath = getIdentifier(moduleMapPathID); if (!moduleMapPath) llvm::report_fatal_error("Bad module map path"); auto contextHash = getIdentifier(contextHashID); if (!contextHash) llvm::report_fatal_error("Bad context hash"); auto commandLineArgs = getStringArray(commandLineArrayID); if (!commandLineArgs) llvm::report_fatal_error("Bad command line"); auto fileDependencies = getStringArray(fileDependenciesArrayID); if (!fileDependencies) llvm::report_fatal_error("Bad file dependencies"); auto rootFileSystemID = getIdentifier(CASFileSystemRootID); if (!rootFileSystemID) llvm::report_fatal_error("Bad CASFileSystem RootID"); auto clangIncludeTreeRoot = getIdentifier(clangIncludeTreeRootID); if (!clangIncludeTreeRoot) llvm::report_fatal_error("Bad clang include tree ID"); auto moduleCacheKey = getIdentifier(moduleCacheKeyID); if (!moduleCacheKey) llvm::report_fatal_error("Bad moduleCacheKey"); // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forClangModule( *pcmOutputPath, *mappedPCMPath, *moduleMapPath, *contextHash, *commandLineArgs, *fileDependencies, linkLibraries, *rootFileSystemID, *clangIncludeTreeRoot, *moduleCacheKey, isSystem); addCommonDependencyInfo(moduleDep); cache.recordDependency(currentModuleName, std::move(moduleDep)); hasCurrentModule = false; break; } default: { llvm::report_fatal_error("Unknown record ID"); } } } return false; } bool ModuleDependenciesCacheDeserializer::readInterModuleDependenciesCache( ModuleDependenciesCache &cache, llvm::sys::TimePoint<> &serializedCacheTimeStamp) { using namespace graph_block; if (readSignature()) return true; if (enterGraphBlock()) return true; if (readMetadata(cache.scannerContextHash)) return true; if (readSerializationTime(serializedCacheTimeStamp)) return true; if (readGraph(cache)) return true; return false; } std::optional ModuleDependenciesCacheDeserializer::getIdentifier(unsigned n) { if (n == 0) return std::string(); --n; if (n >= Identifiers.size()) return std::nullopt; return Identifiers[n]; } std::optional> ModuleDependenciesCacheDeserializer::getStringArray(unsigned n) { if (n == 0) return std::vector(); --n; if (n >= ArraysOfIdentifierIDs.size()) return std::nullopt; auto &identifierIDs = ArraysOfIdentifierIDs[n]; auto IDtoStringMap = [this](unsigned id) { auto identifier = getIdentifier(id); if (!identifier) llvm::report_fatal_error("Bad identifier array element"); return *identifier; }; std::vector result; result.reserve(identifierIDs.size()); std::transform(identifierIDs.begin(), identifierIDs.end(), std::back_inserter(result), IDtoStringMap); return result; } std::optional> ModuleDependenciesCacheDeserializer::getLinkLibraryArray(unsigned n) { if (n == 0) return std::vector(); --n; if (n >= ArraysOfLinkLibraryIDs.size()) return std::nullopt; auto &llIDs = ArraysOfLinkLibraryIDs[n]; auto IDtoLLMap = [this](unsigned index) { return LinkLibraries[index]; }; std::vector result; result.reserve(llIDs.size()); std::transform(llIDs.begin(), llIDs.end(), std::back_inserter(result), IDtoLLMap); return result; } std::optional>> ModuleDependenciesCacheDeserializer::getMacroDependenciesArray(unsigned n) { if (n == 0) return std::vector>(); --n; if (n >= ArraysOfMacroDependenciesIDs.size()) return std::nullopt; auto &llIDs = ArraysOfMacroDependenciesIDs[n]; auto IDtoLLMap = [this](unsigned index) { return MacroDependencies[index]; }; std::vector> result; result.reserve(llIDs.size()); std::transform(llIDs.begin(), llIDs.end(), std::back_inserter(result), IDtoLLMap); return result; } std::optional> ModuleDependenciesCacheDeserializer::getImportStatementInfoArray(unsigned n) { if (n == 0) return std::vector(); --n; if (n >= ArraysOfImportStatementIDs.size()) return std::nullopt; auto &ISIDs = ArraysOfImportStatementIDs[n]; llvm::StringMap addedImports; for (const auto &importID : ISIDs) { const auto &entry = ImportStatements[importID]; if (addedImports.contains(entry.importIdentifier)) { auto entryIt = addedImports.find(entry.importIdentifier); for (const auto &importLoc : entry.importLocations) entryIt->second.addImportLocation(importLoc); } else addedImports.insert({entry.importIdentifier, entry}); } std::vector result; result.reserve(addedImports.size()); for (const auto &keyValPair : addedImports) { result.push_back(keyValPair.second); } return result; } std::optional> ModuleDependenciesCacheDeserializer::getOptionalImportStatementInfoArray( unsigned n) { if (n == 0) return std::vector(); --n; if (n >= ArraysOfOptionalImportStatementIDs.size()) return std::nullopt; auto &ISIDs = ArraysOfOptionalImportStatementIDs[n]; auto IDtoISMap = [this](unsigned index) { return ImportStatements[index]; }; std::vector result; result.reserve(ISIDs.size()); std::transform(ISIDs.begin(), ISIDs.end(), std::back_inserter(result), IDtoISMap); return result; } std::optional> ModuleDependenciesCacheDeserializer::getModuleDependencyIDArray(unsigned n) { auto encodedIdentifierStringArray = getStringArray(n); if (encodedIdentifierStringArray.has_value()) { static const std::string textualPrefix("swiftTextual"); static const std::string binaryPrefix("swiftBinary"); static const std::string placeholderPrefix("swiftPlaceholder"); static const std::string clangPrefix("clang"); std::vector result; for (const auto &encodedIdentifierString : *encodedIdentifierStringArray) { ModuleDependencyID id; if (!encodedIdentifierString.compare(0, textualPrefix.size(), textualPrefix)) { auto moduleName = encodedIdentifierString.substr(textualPrefix.size() + 1); id = {moduleName, ModuleDependencyKind::SwiftInterface}; } else if (!encodedIdentifierString.compare(0, binaryPrefix.size(), binaryPrefix)) { auto moduleName = encodedIdentifierString.substr(binaryPrefix.size() + 1); id = {moduleName, ModuleDependencyKind::SwiftBinary}; } else if (!encodedIdentifierString.compare(0, placeholderPrefix.size(), placeholderPrefix)) { auto moduleName = encodedIdentifierString.substr(placeholderPrefix.size() + 1); id = {moduleName, ModuleDependencyKind::SwiftPlaceholder}; } else { auto moduleName = encodedIdentifierString.substr(clangPrefix.size() + 1); id = {moduleName, ModuleDependencyKind::Clang}; } result.push_back(id); } return result; } return std::nullopt; } bool swift::dependencies::module_dependency_cache_serialization:: readInterModuleDependenciesCache(llvm::MemoryBuffer &buffer, ModuleDependenciesCache &cache, llvm::sys::TimePoint<> &serializedCacheTimeStamp) { ModuleDependenciesCacheDeserializer deserializer(buffer.getMemBufferRef()); return deserializer.readInterModuleDependenciesCache(cache, serializedCacheTimeStamp); } bool swift::dependencies::module_dependency_cache_serialization:: readInterModuleDependenciesCache(StringRef path, ModuleDependenciesCache &cache, llvm::sys::TimePoint<> &serializedCacheTimeStamp) { PrettyStackTraceStringAction stackTrace( "loading inter-module dependency graph", path); auto buffer = llvm::MemoryBuffer::getFile(path); if (!buffer) return true; return readInterModuleDependenciesCache(*buffer.get(), cache, serializedCacheTimeStamp); } // MARK: Serialization /// Kinds of arrays that we track being serialized. Used to query serialized /// array ID for a given module. enum ModuleIdentifierArrayKind : uint8_t { Empty = 0, DependencyImports, OptionalDependencyImports, ImportedSwiftDependenciesIDs, ImportedClangDependenciesIDs, CrossImportOverlayDependenciesIDs, SwiftOverlayDependenciesIDs, AuxiliaryFileIDs, CompiledModuleCandidates, BuildCommandLine, SourceFiles, BridgingSourceFiles, BridgingModuleDependencies, HeaderInputDependencySourceFiles, HeaderInputModuleDependencies, BridgingHeaderBuildCommandLine, NonPathCommandLine, FileDependencies, LastArrayKind }; using ModuleIdentifierArrayKey = std::pair; // DenseMap Infos for hashing of ModuleIdentifierArrayKind template <> struct llvm::DenseMapInfo { using UnderlyingType = std::underlying_type::type; using UnderlyingInfo = DenseMapInfo; static inline ModuleIdentifierArrayKind getEmptyKey() { return ModuleIdentifierArrayKind::Empty; } static inline ModuleIdentifierArrayKind getTombstoneKey() { return ModuleIdentifierArrayKind::LastArrayKind; } static unsigned getHashValue(const ModuleIdentifierArrayKind &arrKind) { auto underlyingValue = static_cast(arrKind); return UnderlyingInfo::getHashValue(underlyingValue); } static bool isEqual(const ModuleIdentifierArrayKind &LHS, const ModuleIdentifierArrayKind &RHS) { return LHS == RHS; } }; namespace swift { class ModuleDependenciesCacheSerializer { llvm::StringMap IdentifierIDs; std::unordered_map> IdentifierArrayIDsMap; unsigned LastIdentifierID = 0; unsigned LastIdentifierArrayID = 0; std::vector Identifiers; std::vector> ArraysOfIdentifiers; std::unordered_map LinkLibraryArrayIDsMap; std::unordered_map MacroDependenciesArrayIDsMap; std::unordered_map ImportInfosArrayIDsMap; std::unordered_map OptionalImportInfosArrayIDsMap; llvm::BitstreamWriter &Out; /// A reusable buffer for emitting records. SmallVector ScratchRecord; std::array AbbrCodes; // Returns the identifier ID of the added identifier, either // new or previously-hashed unsigned addIdentifier(const std::string &str); unsigned getIdentifier(const std::string &str) const; // Returns the array ID of the added array void addStringArray(ModuleDependencyID moduleID, ModuleIdentifierArrayKind arrayKind, const std::vector &vec); void addDependencyIDArray(ModuleDependencyID moduleID, ModuleIdentifierArrayKind arrayKind, const ArrayRef vec); unsigned getIdentifierArrayID(ModuleDependencyID moduleID, ModuleIdentifierArrayKind arrayKind) const; unsigned getLinkLibrariesArrayID(ModuleDependencyID moduleID) const; unsigned getMacroDependenciesArrayID(ModuleDependencyID moduleID) const; unsigned getImportStatementsArrayID(ModuleDependencyID moduleID) const; unsigned getOptionalImportStatementsArrayID(ModuleDependencyID moduleID) const; template void registerRecordAbbr() { using AbbrArrayTy = decltype(AbbrCodes); static_assert(Layout::Code <= std::tuple_size::value, "layout has invalid record code"); AbbrCodes[Layout::Code] = Layout::emitAbbrev(Out); } void collectStringsAndArrays(const ModuleDependenciesCache &cache); void emitBlockID(unsigned ID, StringRef name, SmallVectorImpl &nameBuffer); void emitRecordID(unsigned ID, StringRef name, SmallVectorImpl &nameBuffer); void writeSignature(); void writeBlockInfoBlock(); void writeMetadata(StringRef scanningContextHash); void writeSerializationTime(const llvm::sys::TimePoint<> &scanInitializationTime); void writeIdentifiers(); void writeArraysOfIdentifiers(); void writeLinkLibraries(const ModuleDependenciesCache &cache); unsigned writeLinkLibraryInfos(const ModuleDependencyInfo &dependencyInfo); void writeLinkLibraryInfoArray(unsigned startIndex, unsigned count); void writeMacroDependencies(const ModuleDependenciesCache &cache); unsigned writeMacroDependencies(const ModuleDependencyInfo &dependencyInfo); void writeMacroDependenciesArray(unsigned startIndex, unsigned count); void writeImportStatementInfos(const ModuleDependenciesCache &cache); unsigned writeImportStatementInfos(const ModuleDependencyInfo &dependencyInfo, bool optional); void writeImportStatementInfosArray(unsigned startIndex, unsigned count); void writeModuleInfo(ModuleDependencyID moduleID, const ModuleDependencyInfo &dependencyInfo); public: ModuleDependenciesCacheSerializer(llvm::BitstreamWriter &ExistingOut) : Out(ExistingOut) {} public: void writeInterModuleDependenciesCache(const ModuleDependenciesCache &cache); }; } // namespace swift /// Record the name of a block. void ModuleDependenciesCacheSerializer::emitBlockID( unsigned ID, StringRef name, SmallVectorImpl &nameBuffer) { SmallVector idBuffer; idBuffer.push_back(ID); Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, idBuffer); // Emit the block name if present. if (name.empty()) return; nameBuffer.resize(name.size()); memcpy(nameBuffer.data(), name.data(), name.size()); Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, nameBuffer); } /// Record the name of a record. void ModuleDependenciesCacheSerializer::emitRecordID( unsigned ID, StringRef name, SmallVectorImpl &nameBuffer) { assert(ID < 256 && "can't fit record ID in next to name"); nameBuffer.resize(name.size() + 1); nameBuffer[0] = ID; memcpy(nameBuffer.data() + 1, name.data(), name.size()); Out.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, nameBuffer); } void ModuleDependenciesCacheSerializer::writeBlockInfoBlock() { llvm::BCBlockRAII restoreBlock(Out, llvm::bitc::BLOCKINFO_BLOCK_ID, 2); SmallVector nameBuffer; #define BLOCK(X) emitBlockID(X##_ID, #X, nameBuffer) #define BLOCK_RECORD(K, X) emitRecordID(K::X, #X, nameBuffer) BLOCK(GRAPH_BLOCK); BLOCK_RECORD(graph_block, METADATA); BLOCK_RECORD(graph_block, TIME_NODE); BLOCK_RECORD(graph_block, IDENTIFIER_NODE); BLOCK_RECORD(graph_block, IDENTIFIER_ARRAY_NODE); BLOCK_RECORD(graph_block, LINK_LIBRARY_NODE); BLOCK_RECORD(graph_block, LINK_LIBRARY_ARRAY_NODE); BLOCK_RECORD(graph_block, MACRO_DEPENDENCY_NODE); BLOCK_RECORD(graph_block, MACRO_DEPENDENCY_ARRAY_NODE); BLOCK_RECORD(graph_block, IMPORT_STATEMENT_NODE); BLOCK_RECORD(graph_block, IMPORT_STATEMENT_ARRAY_NODE); BLOCK_RECORD(graph_block, OPTIONAL_IMPORT_STATEMENT_ARRAY_NODE); BLOCK_RECORD(graph_block, MODULE_NODE); BLOCK_RECORD(graph_block, SWIFT_INTERFACE_MODULE_DETAILS_NODE); BLOCK_RECORD(graph_block, SWIFT_SOURCE_MODULE_DETAILS_NODE); BLOCK_RECORD(graph_block, SWIFT_BINARY_MODULE_DETAILS_NODE); BLOCK_RECORD(graph_block, SWIFT_PLACEHOLDER_MODULE_DETAILS_NODE); BLOCK_RECORD(graph_block, CLANG_MODULE_DETAILS_NODE); } void ModuleDependenciesCacheSerializer::writeSignature() { for (auto c : MODULE_DEPENDENCY_CACHE_FORMAT_SIGNATURE) Out.Emit((unsigned)c, 8); } void ModuleDependenciesCacheSerializer::writeMetadata(StringRef scanningContextHash) { using namespace graph_block; MetadataLayout::emitRecord(Out, ScratchRecord, AbbrCodes[MetadataLayout::Code], MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MAJOR, MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR, scanningContextHash); } void ModuleDependenciesCacheSerializer::writeSerializationTime(const llvm::sys::TimePoint<> &scanInitializationTime) { using namespace graph_block; auto timeSinceEpoch = scanInitializationTime.time_since_epoch().count(); std::string serializationData = std::to_string(timeSinceEpoch); TimeLayout::emitRecord(Out, ScratchRecord, AbbrCodes[TimeLayout::Code], serializationData); } void ModuleDependenciesCacheSerializer::writeIdentifiers() { using namespace graph_block; for (auto str : Identifiers) { IdentifierNodeLayout::emitRecord( Out, ScratchRecord, AbbrCodes[IdentifierNodeLayout::Code], str); } } void ModuleDependenciesCacheSerializer::writeArraysOfIdentifiers() { using namespace graph_block; for (auto vec : ArraysOfIdentifiers) { IdentifierArrayLayout::emitRecord( Out, ScratchRecord, AbbrCodes[IdentifierArrayLayout::Code], vec); } } void ModuleDependenciesCacheSerializer::writeLinkLibraries( const ModuleDependenciesCache &cache) { unsigned lastLLIndex = 0; std::map> moduleLLArrayMap; for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { auto modMap = cache.getDependenciesMap(kind); for (const auto &entry : modMap) { ModuleDependencyID moduleID = {entry.getKey().str(), kind}; auto optionalDependencyInfo = cache.findDependency(moduleID); assert(optionalDependencyInfo.has_value() && "Expected dependency info."); auto dependencyInfo = optionalDependencyInfo.value(); unsigned numLLs = writeLinkLibraryInfos(*dependencyInfo); moduleLLArrayMap.insert({moduleID, std::make_pair(lastLLIndex, numLLs)}); lastLLIndex += numLLs; } } unsigned lastLLArrayIndex = 1; for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { auto modMap = cache.getDependenciesMap(kind); for (const auto &entry : modMap) { ModuleDependencyID moduleID = {entry.getKey().str(), kind}; auto entries = moduleLLArrayMap.at(moduleID); if (entries.second == 0) continue; writeLinkLibraryInfoArray(entries.first, entries.second); LinkLibraryArrayIDsMap.insert({moduleID, lastLLArrayIndex++}); } } } unsigned ModuleDependenciesCacheSerializer::writeLinkLibraryInfos( const ModuleDependencyInfo &dependencyInfo) { using namespace graph_block; for (auto &linkLibrary : dependencyInfo.getLinkLibraries()) LinkLibraryLayout::emitRecord( Out, ScratchRecord, AbbrCodes[LinkLibraryLayout::Code], getIdentifier(linkLibrary.getName().str()), linkLibrary.getKind() == LibraryKind::Framework, linkLibrary.isStaticLibrary(), linkLibrary.shouldForceLoad()); return dependencyInfo.getLinkLibraries().size(); } void ModuleDependenciesCacheSerializer::writeLinkLibraryInfoArray( unsigned startIndex, unsigned count) { using namespace graph_block; std::vector vec(count); std::iota(vec.begin(), vec.end(), startIndex); LinkLibraryArrayLayout::emitRecord( Out, ScratchRecord, AbbrCodes[LinkLibraryArrayLayout::Code], vec); } void ModuleDependenciesCacheSerializer::writeMacroDependencies( const ModuleDependenciesCache &cache) { unsigned lastMDIndex = 0; std::map> moduleMacroDepArrayMap; for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { auto modMap = cache.getDependenciesMap(kind); for (const auto &entry : modMap) { ModuleDependencyID moduleID = {entry.getKey().str(), kind}; auto optionalDependencyInfo = cache.findDependency(moduleID); assert(optionalDependencyInfo.has_value() && "Expected dependency info."); auto dependencyInfo = optionalDependencyInfo.value(); unsigned numMDs = writeMacroDependencies(*dependencyInfo); moduleMacroDepArrayMap.insert( {moduleID, std::make_pair(lastMDIndex, numMDs)}); lastMDIndex += numMDs; } } unsigned lastMDArrayIndex = 1; for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { auto modMap = cache.getDependenciesMap(kind); for (const auto &entry : modMap) { ModuleDependencyID moduleID = {entry.getKey().str(), kind}; auto entries = moduleMacroDepArrayMap.at(moduleID); if (entries.second == 0) continue; writeMacroDependenciesArray(entries.first, entries.second); MacroDependenciesArrayIDsMap.insert({moduleID, lastMDArrayIndex++}); } } } unsigned ModuleDependenciesCacheSerializer::writeMacroDependencies( const ModuleDependencyInfo &dependencyInfo) { using namespace graph_block; for (auto ¯oDependency : dependencyInfo.getMacroDependencies()) { MacroDependencyLayout::emitRecord( Out, ScratchRecord, AbbrCodes[MacroDependencyLayout::Code], getIdentifier(macroDependency.first), getIdentifier(macroDependency.second.LibraryPath), getIdentifier(macroDependency.second.ExecutablePath)); } return dependencyInfo.getMacroDependencies().size(); } void ModuleDependenciesCacheSerializer::writeMacroDependenciesArray( unsigned startIndex, unsigned count) { using namespace graph_block; std::vector vec(count); std::iota(vec.begin(), vec.end(), startIndex); MacroDependencyArrayLayout::emitRecord( Out, ScratchRecord, AbbrCodes[MacroDependencyArrayLayout::Code], vec); } void ModuleDependenciesCacheSerializer::writeImportStatementInfos( const ModuleDependenciesCache &cache) { unsigned lastImportInfoIndex = 0; std::map> importInfoArrayMap; std::map> optionalImportInfoArrayMap; for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { auto modMap = cache.getDependenciesMap(kind); for (const auto &entry : modMap) { ModuleDependencyID moduleID = {entry.getKey().str(), kind}; auto optionalDependencyInfo = cache.findDependency(moduleID); assert(optionalDependencyInfo.has_value() && "Expected dependency info."); auto dependencyInfo = optionalDependencyInfo.value(); auto numImportInfos = writeImportStatementInfos(*dependencyInfo, /* optional */ false); importInfoArrayMap.insert( {moduleID, std::make_pair(lastImportInfoIndex, numImportInfos)}); lastImportInfoIndex += numImportInfos; auto numOptionalImportInfos = writeImportStatementInfos(*dependencyInfo, /* optional */ true); optionalImportInfoArrayMap.insert( {moduleID, std::make_pair(lastImportInfoIndex, numImportInfos)}); lastImportInfoIndex += numOptionalImportInfos; } } unsigned lastImportInfoArrayIndex = 1; for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { auto modMap = cache.getDependenciesMap(kind); for (const auto &entry : modMap) { ModuleDependencyID moduleID = {entry.getKey().str(), kind}; auto entries = importInfoArrayMap.at(moduleID); if (entries.second == 0) continue; writeImportStatementInfosArray(entries.first, entries.second); ImportInfosArrayIDsMap.insert({moduleID, lastImportInfoArrayIndex++}); } } } unsigned ModuleDependenciesCacheSerializer::writeImportStatementInfos( const ModuleDependencyInfo &dependencyInfo, bool optional) { using namespace graph_block; size_t count = 0; auto emitImportStatementInfo = [this, &count](const auto &importInfo, bool isOptional) { for (auto &importLoc : importInfo.importLocations) { ImportStatementLayout::emitRecord( Out, ScratchRecord, AbbrCodes[ImportStatementLayout::Code], getIdentifier(importInfo.importIdentifier), getIdentifier(importLoc.bufferIdentifier), importLoc.lineNumber, importLoc.columnNumber, isOptional); count++; } }; for (auto &importInfo : dependencyInfo.getModuleImports()) emitImportStatementInfo(importInfo, false); for (auto &importInfo : dependencyInfo.getOptionalModuleImports()) emitImportStatementInfo(importInfo, true); return count; } void ModuleDependenciesCacheSerializer::writeImportStatementInfosArray( unsigned startIndex, unsigned count) { using namespace graph_block; std::vector vec(count); std::iota(vec.begin(), vec.end(), startIndex); ImportStatementArrayLayout::emitRecord( Out, ScratchRecord, AbbrCodes[ImportStatementArrayLayout::Code], vec); } void ModuleDependenciesCacheSerializer::writeModuleInfo( ModuleDependencyID moduleID, const ModuleDependencyInfo &dependencyInfo) { using namespace graph_block; ModuleInfoLayout::emitRecord( Out, ScratchRecord, AbbrCodes[ModuleInfoLayout::Code], getIdentifier(moduleID.ModuleName), getImportStatementsArrayID(moduleID), getOptionalImportStatementsArrayID(moduleID), getLinkLibrariesArrayID(moduleID), getMacroDependenciesArrayID(moduleID), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::ImportedSwiftDependenciesIDs), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::ImportedClangDependenciesIDs), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::CrossImportOverlayDependenciesIDs), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::SwiftOverlayDependenciesIDs), getIdentifier(dependencyInfo.getModuleCacheKey()), getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::AuxiliaryFileIDs)); switch (dependencyInfo.getKind()) { case swift::ModuleDependencyKind::SwiftInterface: { auto swiftTextDeps = dependencyInfo.getAsSwiftInterfaceModule(); assert(swiftTextDeps); unsigned outputModulePathFileId = getIdentifier(swiftTextDeps->moduleOutputPath); unsigned swiftInterfaceFileId = getIdentifier(swiftTextDeps->swiftInterfaceFile); unsigned bridgingHeaderFileId = swiftTextDeps->textualModuleDetails.bridgingHeaderFile ? getIdentifier(swiftTextDeps->textualModuleDetails .bridgingHeaderFile.value()) : 0; SwiftInterfaceModuleDetailsLayout::emitRecord( Out, ScratchRecord, AbbrCodes[SwiftInterfaceModuleDetailsLayout::Code], outputModulePathFileId, swiftInterfaceFileId, getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::CompiledModuleCandidates), getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::BuildCommandLine), getIdentifier(swiftTextDeps->contextHash), swiftTextDeps->isFramework, swiftTextDeps->isStatic, bridgingHeaderFileId, getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::SourceFiles), getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::BridgingSourceFiles), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::BridgingModuleDependencies), getIdentifier(swiftTextDeps->textualModuleDetails.CASFileSystemRootID), getIdentifier(swiftTextDeps->textualModuleDetails .CASBridgingHeaderIncludeTreeRootID), getIdentifier(swiftTextDeps->moduleCacheKey), getIdentifier(swiftTextDeps->userModuleVersion)); break; } case swift::ModuleDependencyKind::SwiftSource: { auto swiftSourceDeps = dependencyInfo.getAsSwiftSourceModule(); assert(swiftSourceDeps); unsigned bridgingHeaderFileId = swiftSourceDeps->textualModuleDetails.bridgingHeaderFile ? getIdentifier(swiftSourceDeps->textualModuleDetails .bridgingHeaderFile.value()) : 0; SwiftSourceModuleDetailsLayout::emitRecord( Out, ScratchRecord, AbbrCodes[SwiftSourceModuleDetailsLayout::Code], bridgingHeaderFileId, getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::SourceFiles), getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::BridgingSourceFiles), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::BridgingModuleDependencies), getIdentifier( swiftSourceDeps->textualModuleDetails.CASFileSystemRootID), getIdentifier(swiftSourceDeps->textualModuleDetails .CASBridgingHeaderIncludeTreeRootID), getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::BuildCommandLine), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::BridgingHeaderBuildCommandLine), getIdentifier(swiftSourceDeps->chainedBridgingHeaderPath), getIdentifier(swiftSourceDeps->chainedBridgingHeaderContent)); break; } case swift::ModuleDependencyKind::SwiftBinary: { auto swiftBinDeps = dependencyInfo.getAsSwiftBinaryModule(); assert(swiftBinDeps); SwiftBinaryModuleDetailsLayout::emitRecord( Out, ScratchRecord, AbbrCodes[SwiftBinaryModuleDetailsLayout::Code], getIdentifier(swiftBinDeps->compiledModulePath), getIdentifier(swiftBinDeps->moduleDocPath), getIdentifier(swiftBinDeps->sourceInfoPath), getIdentifier(swiftBinDeps->headerImport), getIdentifier(swiftBinDeps->definingModuleInterfacePath), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::HeaderInputModuleDependencies), getIdentifierArrayID( moduleID, ModuleIdentifierArrayKind::HeaderInputDependencySourceFiles), swiftBinDeps->isFramework, swiftBinDeps->isStatic, getIdentifier(swiftBinDeps->moduleCacheKey), getIdentifier(swiftBinDeps->userModuleVersion)); break; } case swift::ModuleDependencyKind::SwiftPlaceholder: { auto swiftPHDeps = dependencyInfo.getAsPlaceholderDependencyModule(); assert(swiftPHDeps); SwiftPlaceholderModuleDetailsLayout::emitRecord( Out, ScratchRecord, AbbrCodes[SwiftPlaceholderModuleDetailsLayout::Code], getIdentifier(swiftPHDeps->compiledModulePath), getIdentifier(swiftPHDeps->moduleDocPath), getIdentifier(swiftPHDeps->sourceInfoPath)); break; } case swift::ModuleDependencyKind::Clang: { auto clangDeps = dependencyInfo.getAsClangModule(); assert(clangDeps); ClangModuleDetailsLayout::emitRecord( Out, ScratchRecord, AbbrCodes[ClangModuleDetailsLayout::Code], getIdentifier(clangDeps->pcmOutputPath), getIdentifier(clangDeps->mappedPCMPath), getIdentifier(clangDeps->moduleMapFile), getIdentifier(clangDeps->contextHash), getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::NonPathCommandLine), getIdentifierArrayID(moduleID, ModuleIdentifierArrayKind::FileDependencies), getIdentifier(clangDeps->CASFileSystemRootID), getIdentifier(clangDeps->CASClangIncludeTreeRootID), getIdentifier(clangDeps->moduleCacheKey), clangDeps->IsSystem); break; } default: llvm_unreachable("Unhandled dependency kind."); } } unsigned ModuleDependenciesCacheSerializer::addIdentifier(const std::string &str) { if (str.empty()) return 0; decltype(IdentifierIDs)::iterator iter; bool isNew; std::tie(iter, isNew) = IdentifierIDs.insert({str, LastIdentifierID + 1}); if (!isNew) return iter->getValue(); ++LastIdentifierID; // Note that we use the string data stored in the StringMap. Identifiers.push_back(iter->getKey()); return iter->getValue(); } unsigned ModuleDependenciesCacheSerializer::getIdentifier(const std::string &str) const { if (str.empty()) return 0; auto iter = IdentifierIDs.find(str); assert(iter != IdentifierIDs.end()); assert(iter->second != 0); return iter->second; } void ModuleDependenciesCacheSerializer::addDependencyIDArray( ModuleDependencyID moduleID, ModuleIdentifierArrayKind arrayKind, const ArrayRef vec) { std::vector encodedDependencyIDs; for (const auto &moduleID : vec) encodedDependencyIDs.push_back(createEncodedModuleKindAndName(moduleID)); addStringArray(moduleID, arrayKind, encodedDependencyIDs); return; } void ModuleDependenciesCacheSerializer::addStringArray( ModuleDependencyID moduleID, ModuleIdentifierArrayKind arrayKind, const std::vector &vec) { if (IdentifierArrayIDsMap.find(moduleID) != IdentifierArrayIDsMap.end()) { // Already have arrays for this module llvm::DenseMap::iterator iter; bool isNew; std::tie(iter, isNew) = IdentifierArrayIDsMap[moduleID].insert( {arrayKind, LastIdentifierArrayID + 1}); if (!isNew) return; } else { // Do not yet have any arrays for this module IdentifierArrayIDsMap[moduleID] = llvm::DenseMap(); IdentifierArrayIDsMap[moduleID].insert( {arrayKind, LastIdentifierArrayID + 1}); } ++LastIdentifierArrayID; // Add in the individual identifiers in the array std::vector identifierIDs; identifierIDs.reserve(vec.size()); for (const auto &id : vec) { identifierIDs.push_back(addIdentifier(id)); } ArraysOfIdentifiers.push_back(identifierIDs); return; } unsigned ModuleDependenciesCacheSerializer::getIdentifierArrayID( ModuleDependencyID moduleID, ModuleIdentifierArrayKind arrayKind) const { auto iter = IdentifierArrayIDsMap.find(moduleID); assert(iter != IdentifierArrayIDsMap.end()); auto &innerMap = iter->second; auto arrayIter = innerMap.find(arrayKind); assert(arrayIter != innerMap.end()); return arrayIter->second; } unsigned ModuleDependenciesCacheSerializer::getLinkLibrariesArrayID( ModuleDependencyID moduleID) const { auto iter = LinkLibraryArrayIDsMap.find(moduleID); if (iter == LinkLibraryArrayIDsMap.end()) return 0; return iter->second; } unsigned ModuleDependenciesCacheSerializer::getMacroDependenciesArrayID( ModuleDependencyID moduleID) const { auto iter = MacroDependenciesArrayIDsMap.find(moduleID); if (iter == MacroDependenciesArrayIDsMap.end()) return 0; return iter->second; } unsigned ModuleDependenciesCacheSerializer::getImportStatementsArrayID( ModuleDependencyID moduleID) const { auto iter = ImportInfosArrayIDsMap.find(moduleID); if (iter == ImportInfosArrayIDsMap.end()) return 0; return iter->second; } unsigned ModuleDependenciesCacheSerializer::getOptionalImportStatementsArrayID( ModuleDependencyID moduleID) const { auto iter = OptionalImportInfosArrayIDsMap.find(moduleID); if (iter == OptionalImportInfosArrayIDsMap.end()) return 0; return iter->second; } void ModuleDependenciesCacheSerializer::collectStringsAndArrays( const ModuleDependenciesCache &cache) { addIdentifier(cache.scannerContextHash); for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { auto modMap = cache.getDependenciesMap(kind); for (const auto &entry : modMap) { ModuleDependencyID moduleID = {entry.getKey().str(), kind}; auto optionalDependencyInfo = cache.findDependency(moduleID); assert(optionalDependencyInfo.has_value() && "Expected dependency info."); auto dependencyInfo = optionalDependencyInfo.value(); // Add the module's name addIdentifier(moduleID.ModuleName); // Map import infos to their respective module identifiers auto importInfoArrayToIdentifier = [](const auto &importInfo) -> std::string { return importInfo.importIdentifier; }; for (const auto &ll : dependencyInfo->getLinkLibraries()) addIdentifier(ll.getName().str()); for (const auto &md : dependencyInfo->getMacroDependencies()) { addIdentifier(md.first); addIdentifier(md.second.LibraryPath); addIdentifier(md.second.ExecutablePath); } // Add the module's imports std::vector importIdentifiers; llvm::transform(dependencyInfo->getModuleImports(), std::back_inserter(importIdentifiers), importInfoArrayToIdentifier); std::vector optionalImportIdentifiers; llvm::transform(dependencyInfo->getOptionalModuleImports(), std::back_inserter(optionalImportIdentifiers), importInfoArrayToIdentifier); addStringArray(moduleID, ModuleIdentifierArrayKind::DependencyImports, importIdentifiers); addStringArray(moduleID, ModuleIdentifierArrayKind::OptionalDependencyImports, optionalImportIdentifiers); addDependencyIDArray( moduleID, ModuleIdentifierArrayKind::ImportedSwiftDependenciesIDs, dependencyInfo->getImportedSwiftDependencies()); addDependencyIDArray( moduleID, ModuleIdentifierArrayKind::ImportedClangDependenciesIDs, dependencyInfo->getImportedClangDependencies()); addDependencyIDArray( moduleID, ModuleIdentifierArrayKind::CrossImportOverlayDependenciesIDs, dependencyInfo->getCrossImportOverlayDependencies()); addDependencyIDArray( moduleID, ModuleIdentifierArrayKind::SwiftOverlayDependenciesIDs, dependencyInfo->getSwiftOverlayDependencies()); addStringArray(moduleID, ModuleIdentifierArrayKind::AuxiliaryFileIDs, dependencyInfo->getAuxiliaryFiles()); std::vector clangHeaderDependencyNames; for (const auto &headerDepID : dependencyInfo->getHeaderClangDependencies()) clangHeaderDependencyNames.push_back(headerDepID.ModuleName); // Add the dependency-kind-specific data switch (dependencyInfo->getKind()) { case swift::ModuleDependencyKind::SwiftInterface: { auto swiftTextDeps = dependencyInfo->getAsSwiftInterfaceModule(); assert(swiftTextDeps); addIdentifier(swiftTextDeps->moduleOutputPath); addIdentifier(swiftTextDeps->swiftInterfaceFile); addStringArray(moduleID, ModuleIdentifierArrayKind::CompiledModuleCandidates, swiftTextDeps->compiledModuleCandidates); addStringArray(moduleID, ModuleIdentifierArrayKind::BuildCommandLine, swiftTextDeps->textualModuleDetails.buildCommandLine); addIdentifier(swiftTextDeps->contextHash); if (swiftTextDeps->textualModuleDetails.bridgingHeaderFile.has_value()) addIdentifier( swiftTextDeps->textualModuleDetails.bridgingHeaderFile.value()); addStringArray(moduleID, ModuleIdentifierArrayKind::SourceFiles, std::vector()); addStringArray(moduleID, ModuleIdentifierArrayKind::BridgingSourceFiles, swiftTextDeps->textualModuleDetails.bridgingSourceFiles); addStringArray(moduleID, ModuleIdentifierArrayKind::BridgingModuleDependencies, clangHeaderDependencyNames); addIdentifier(swiftTextDeps->textualModuleDetails.CASFileSystemRootID); addIdentifier(swiftTextDeps->textualModuleDetails .CASBridgingHeaderIncludeTreeRootID); addIdentifier(swiftTextDeps->moduleCacheKey); addIdentifier(swiftTextDeps->userModuleVersion); break; } case swift::ModuleDependencyKind::SwiftBinary: { auto swiftBinDeps = dependencyInfo->getAsSwiftBinaryModule(); assert(swiftBinDeps); addIdentifier(swiftBinDeps->compiledModulePath); addIdentifier(swiftBinDeps->moduleDocPath); addIdentifier(swiftBinDeps->sourceInfoPath); addIdentifier(swiftBinDeps->moduleCacheKey); addIdentifier(swiftBinDeps->headerImport); addIdentifier(swiftBinDeps->definingModuleInterfacePath); addIdentifier(swiftBinDeps->userModuleVersion); addStringArray(moduleID, ModuleIdentifierArrayKind::HeaderInputModuleDependencies, clangHeaderDependencyNames); addStringArray( moduleID, ModuleIdentifierArrayKind::HeaderInputDependencySourceFiles, swiftBinDeps->headerSourceFiles); break; } case swift::ModuleDependencyKind::SwiftPlaceholder: { auto swiftPHDeps = dependencyInfo->getAsPlaceholderDependencyModule(); assert(swiftPHDeps); addIdentifier(swiftPHDeps->compiledModulePath); addIdentifier(swiftPHDeps->moduleDocPath); addIdentifier(swiftPHDeps->sourceInfoPath); break; } case swift::ModuleDependencyKind::SwiftSource: { auto swiftSourceDeps = dependencyInfo->getAsSwiftSourceModule(); assert(swiftSourceDeps); if (swiftSourceDeps->textualModuleDetails.bridgingHeaderFile .has_value()) addIdentifier( swiftSourceDeps->textualModuleDetails.bridgingHeaderFile.value()); addStringArray(moduleID, ModuleIdentifierArrayKind::SourceFiles, swiftSourceDeps->sourceFiles); addStringArray( moduleID, ModuleIdentifierArrayKind::BridgingSourceFiles, swiftSourceDeps->textualModuleDetails.bridgingSourceFiles); addStringArray(moduleID, ModuleIdentifierArrayKind::BridgingModuleDependencies, clangHeaderDependencyNames); addStringArray(moduleID, ModuleIdentifierArrayKind::BuildCommandLine, swiftSourceDeps->textualModuleDetails.buildCommandLine); addStringArray( moduleID, ModuleIdentifierArrayKind::BridgingHeaderBuildCommandLine, swiftSourceDeps->bridgingHeaderBuildCommandLine); addIdentifier( swiftSourceDeps->textualModuleDetails.CASFileSystemRootID); addIdentifier(swiftSourceDeps->chainedBridgingHeaderPath); addIdentifier(swiftSourceDeps->chainedBridgingHeaderContent); break; } case swift::ModuleDependencyKind::Clang: { auto clangDeps = dependencyInfo->getAsClangModule(); assert(clangDeps); addIdentifier(clangDeps->pcmOutputPath); addIdentifier(clangDeps->mappedPCMPath); addIdentifier(clangDeps->moduleMapFile); addIdentifier(clangDeps->contextHash); addStringArray(moduleID, ModuleIdentifierArrayKind::NonPathCommandLine, clangDeps->buildCommandLine); addStringArray(moduleID, ModuleIdentifierArrayKind::FileDependencies, clangDeps->fileDependencies); addIdentifier(clangDeps->CASFileSystemRootID); addIdentifier(clangDeps->CASClangIncludeTreeRootID); addIdentifier(clangDeps->moduleCacheKey); break; } default: llvm_unreachable("Unhandled dependency kind."); } } } } void ModuleDependenciesCacheSerializer::writeInterModuleDependenciesCache( const ModuleDependenciesCache &cache) { // Write the header writeSignature(); writeBlockInfoBlock(); // Enter the main graph block unsigned blockID = GRAPH_BLOCK_ID; llvm::BCBlockRAII restoreBlock(Out, blockID, 8); using namespace graph_block; registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); registerRecordAbbr(); // Make a pass to collect all unique strings and arrays // of strings collectStringsAndArrays(cache); // Write the version information writeMetadata(cache.scannerContextHash); // The current time-stamp writeSerializationTime(cache.scanInitializationTime); // Write the strings writeIdentifiers(); // Write the arrays writeArraysOfIdentifiers(); // Write all the import statement info writeImportStatementInfos(cache); // Write all the arrays of link library infos for this graph writeLinkLibraries(cache); // Write all the arrays of macro dependency infos for this graph writeMacroDependencies(cache); // Write the core graph for (auto kind = ModuleDependencyKind::FirstKind; kind != ModuleDependencyKind::LastKind; ++kind) { auto modMap = cache.getDependenciesMap(kind); for (const auto &modInfo : modMap) { writeModuleInfo({modInfo.getKey().str(), kind}, modInfo.second); } } return; } void swift::dependencies::module_dependency_cache_serialization:: writeInterModuleDependenciesCache(llvm::BitstreamWriter &Out, const ModuleDependenciesCache &cache) { ModuleDependenciesCacheSerializer serializer{Out}; serializer.writeInterModuleDependenciesCache(cache); } bool swift::dependencies::module_dependency_cache_serialization:: writeInterModuleDependenciesCache(DiagnosticEngine &diags, llvm::vfs::OutputBackend &backend, StringRef path, const ModuleDependenciesCache &cache) { PrettyStackTraceStringAction stackTrace( "saving inter-module dependency graph", path); return withOutputPath(diags, backend, path, [&](llvm::raw_ostream &out) { SmallVector buffer; llvm::BitstreamWriter writer{buffer}; writeInterModuleDependenciesCache(writer, cache); out.write(buffer.data(), buffer.size()); out.flush(); return false; }); }