Path: blob/main/contrib/llvm-project/clang/lib/Serialization/GlobalModuleIndex.cpp
35232 views
//===--- GlobalModuleIndex.cpp - Global Module Index ------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the GlobalModuleIndex class.9//10//===----------------------------------------------------------------------===//1112#include "clang/Serialization/GlobalModuleIndex.h"13#include "ASTReaderInternals.h"14#include "clang/Basic/FileManager.h"15#include "clang/Serialization/ASTBitCodes.h"16#include "clang/Serialization/ModuleFile.h"17#include "clang/Serialization/PCHContainerOperations.h"18#include "llvm/ADT/DenseMap.h"19#include "llvm/ADT/MapVector.h"20#include "llvm/ADT/SmallString.h"21#include "llvm/ADT/StringRef.h"22#include "llvm/Bitstream/BitstreamReader.h"23#include "llvm/Bitstream/BitstreamWriter.h"24#include "llvm/Support/DJB.h"25#include "llvm/Support/FileSystem.h"26#include "llvm/Support/LockFileManager.h"27#include "llvm/Support/MemoryBuffer.h"28#include "llvm/Support/OnDiskHashTable.h"29#include "llvm/Support/Path.h"30#include "llvm/Support/TimeProfiler.h"31#include "llvm/Support/raw_ostream.h"32#include <cstdio>33using namespace clang;34using namespace serialization;3536//----------------------------------------------------------------------------//37// Shared constants38//----------------------------------------------------------------------------//39namespace {40enum {41/// The block containing the index.42GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID43};4445/// Describes the record types in the index.46enum IndexRecordTypes {47/// Contains version information and potentially other metadata,48/// used to determine if we can read this global index file.49INDEX_METADATA,50/// Describes a module, including its file name and dependencies.51MODULE,52/// The index for identifiers.53IDENTIFIER_INDEX54};55}5657/// The name of the global index file.58static const char * const IndexFileName = "modules.idx";5960/// The global index file version.61static const unsigned CurrentVersion = 1;6263//----------------------------------------------------------------------------//64// Global module index reader.65//----------------------------------------------------------------------------//6667namespace {6869/// Trait used to read the identifier index from the on-disk hash70/// table.71class IdentifierIndexReaderTrait {72public:73typedef StringRef external_key_type;74typedef StringRef internal_key_type;75typedef SmallVector<unsigned, 2> data_type;76typedef unsigned hash_value_type;77typedef unsigned offset_type;7879static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {80return a == b;81}8283static hash_value_type ComputeHash(const internal_key_type& a) {84return llvm::djbHash(a);85}8687static std::pair<unsigned, unsigned>88ReadKeyDataLength(const unsigned char*& d) {89using namespace llvm::support;90unsigned KeyLen = endian::readNext<uint16_t, llvm::endianness::little>(d);91unsigned DataLen = endian::readNext<uint16_t, llvm::endianness::little>(d);92return std::make_pair(KeyLen, DataLen);93}9495static const internal_key_type&96GetInternalKey(const external_key_type& x) { return x; }9798static const external_key_type&99GetExternalKey(const internal_key_type& x) { return x; }100101static internal_key_type ReadKey(const unsigned char* d, unsigned n) {102return StringRef((const char *)d, n);103}104105static data_type ReadData(const internal_key_type& k,106const unsigned char* d,107unsigned DataLen) {108using namespace llvm::support;109110data_type Result;111while (DataLen > 0) {112unsigned ID = endian::readNext<uint32_t, llvm::endianness::little>(d);113Result.push_back(ID);114DataLen -= 4;115}116117return Result;118}119};120121typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>122IdentifierIndexTable;123124}125126GlobalModuleIndex::GlobalModuleIndex(127std::unique_ptr<llvm::MemoryBuffer> IndexBuffer,128llvm::BitstreamCursor Cursor)129: Buffer(std::move(IndexBuffer)), IdentifierIndex(), NumIdentifierLookups(),130NumIdentifierLookupHits() {131auto Fail = [&](llvm::Error &&Err) {132report_fatal_error("Module index '" + Buffer->getBufferIdentifier() +133"' failed: " + toString(std::move(Err)));134};135136llvm::TimeTraceScope TimeScope("Module LoadIndex");137// Read the global index.138bool InGlobalIndexBlock = false;139bool Done = false;140while (!Done) {141llvm::BitstreamEntry Entry;142if (Expected<llvm::BitstreamEntry> Res = Cursor.advance())143Entry = Res.get();144else145Fail(Res.takeError());146147switch (Entry.Kind) {148case llvm::BitstreamEntry::Error:149return;150151case llvm::BitstreamEntry::EndBlock:152if (InGlobalIndexBlock) {153InGlobalIndexBlock = false;154Done = true;155continue;156}157return;158159160case llvm::BitstreamEntry::Record:161// Entries in the global index block are handled below.162if (InGlobalIndexBlock)163break;164165return;166167case llvm::BitstreamEntry::SubBlock:168if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {169if (llvm::Error Err = Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))170Fail(std::move(Err));171InGlobalIndexBlock = true;172} else if (llvm::Error Err = Cursor.SkipBlock())173Fail(std::move(Err));174continue;175}176177SmallVector<uint64_t, 64> Record;178StringRef Blob;179Expected<unsigned> MaybeIndexRecord =180Cursor.readRecord(Entry.ID, Record, &Blob);181if (!MaybeIndexRecord)182Fail(MaybeIndexRecord.takeError());183IndexRecordTypes IndexRecord =184static_cast<IndexRecordTypes>(MaybeIndexRecord.get());185switch (IndexRecord) {186case INDEX_METADATA:187// Make sure that the version matches.188if (Record.size() < 1 || Record[0] != CurrentVersion)189return;190break;191192case MODULE: {193unsigned Idx = 0;194unsigned ID = Record[Idx++];195196// Make room for this module's information.197if (ID == Modules.size())198Modules.push_back(ModuleInfo());199else200Modules.resize(ID + 1);201202// Size/modification time for this module file at the time the203// global index was built.204Modules[ID].Size = Record[Idx++];205Modules[ID].ModTime = Record[Idx++];206207// File name.208unsigned NameLen = Record[Idx++];209Modules[ID].FileName.assign(Record.begin() + Idx,210Record.begin() + Idx + NameLen);211Idx += NameLen;212213// Dependencies214unsigned NumDeps = Record[Idx++];215Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),216Record.begin() + Idx,217Record.begin() + Idx + NumDeps);218Idx += NumDeps;219220// Make sure we're at the end of the record.221assert(Idx == Record.size() && "More module info?");222223// Record this module as an unresolved module.224// FIXME: this doesn't work correctly for module names containing path225// separators.226StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName);227// Remove the -<hash of ModuleMapPath>228ModuleName = ModuleName.rsplit('-').first;229UnresolvedModules[ModuleName] = ID;230break;231}232233case IDENTIFIER_INDEX:234// Wire up the identifier index.235if (Record[0]) {236IdentifierIndex = IdentifierIndexTable::Create(237(const unsigned char *)Blob.data() + Record[0],238(const unsigned char *)Blob.data() + sizeof(uint32_t),239(const unsigned char *)Blob.data(), IdentifierIndexReaderTrait());240}241break;242}243}244}245246GlobalModuleIndex::~GlobalModuleIndex() {247delete static_cast<IdentifierIndexTable *>(IdentifierIndex);248}249250std::pair<GlobalModuleIndex *, llvm::Error>251GlobalModuleIndex::readIndex(StringRef Path) {252// Load the index file, if it's there.253llvm::SmallString<128> IndexPath;254IndexPath += Path;255llvm::sys::path::append(IndexPath, IndexFileName);256257llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr =258llvm::MemoryBuffer::getFile(IndexPath.c_str());259if (!BufferOrErr)260return std::make_pair(nullptr,261llvm::errorCodeToError(BufferOrErr.getError()));262std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get());263264/// The main bitstream cursor for the main block.265llvm::BitstreamCursor Cursor(*Buffer);266267// Sniff for the signature.268for (unsigned char C : {'B', 'C', 'G', 'I'}) {269if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Cursor.Read(8)) {270if (Res.get() != C)271return std::make_pair(272nullptr, llvm::createStringError(std::errc::illegal_byte_sequence,273"expected signature BCGI"));274} else275return std::make_pair(nullptr, Res.takeError());276}277278return std::make_pair(new GlobalModuleIndex(std::move(Buffer), std::move(Cursor)),279llvm::Error::success());280}281282void GlobalModuleIndex::getModuleDependencies(283ModuleFile *File,284SmallVectorImpl<ModuleFile *> &Dependencies) {285// Look for information about this module file.286llvm::DenseMap<ModuleFile *, unsigned>::iterator Known287= ModulesByFile.find(File);288if (Known == ModulesByFile.end())289return;290291// Record dependencies.292Dependencies.clear();293ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies;294for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) {295if (ModuleFile *MF = Modules[I].File)296Dependencies.push_back(MF);297}298}299300bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) {301Hits.clear();302303// If there's no identifier index, there is nothing we can do.304if (!IdentifierIndex)305return false;306307// Look into the identifier index.308++NumIdentifierLookups;309IdentifierIndexTable &Table310= *static_cast<IdentifierIndexTable *>(IdentifierIndex);311IdentifierIndexTable::iterator Known = Table.find(Name);312if (Known == Table.end()) {313return false;314}315316SmallVector<unsigned, 2> ModuleIDs = *Known;317for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) {318if (ModuleFile *MF = Modules[ModuleIDs[I]].File)319Hits.insert(MF);320}321322++NumIdentifierLookupHits;323return true;324}325326bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) {327// Look for the module in the global module index based on the module name.328StringRef Name = File->ModuleName;329llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name);330if (Known == UnresolvedModules.end()) {331return true;332}333334// Rectify this module with the global module index.335ModuleInfo &Info = Modules[Known->second];336337// If the size and modification time match what we expected, record this338// module file.339bool Failed = true;340if (File->File.getSize() == Info.Size &&341File->File.getModificationTime() == Info.ModTime) {342Info.File = File;343ModulesByFile[File] = Known->second;344345Failed = false;346}347348// One way or another, we have resolved this module file.349UnresolvedModules.erase(Known);350return Failed;351}352353void GlobalModuleIndex::printStats() {354std::fprintf(stderr, "*** Global Module Index Statistics:\n");355if (NumIdentifierLookups) {356fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n",357NumIdentifierLookupHits, NumIdentifierLookups,358(double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);359}360std::fprintf(stderr, "\n");361}362363LLVM_DUMP_METHOD void GlobalModuleIndex::dump() {364llvm::errs() << "*** Global Module Index Dump:\n";365llvm::errs() << "Module files:\n";366for (auto &MI : Modules) {367llvm::errs() << "** " << MI.FileName << "\n";368if (MI.File)369MI.File->dump();370else371llvm::errs() << "\n";372}373llvm::errs() << "\n";374}375376//----------------------------------------------------------------------------//377// Global module index writer.378//----------------------------------------------------------------------------//379380namespace {381/// Provides information about a specific module file.382struct ModuleFileInfo {383/// The numberic ID for this module file.384unsigned ID;385386/// The set of modules on which this module depends. Each entry is387/// a module ID.388SmallVector<unsigned, 4> Dependencies;389ASTFileSignature Signature;390};391392struct ImportedModuleFileInfo {393off_t StoredSize;394time_t StoredModTime;395ASTFileSignature StoredSignature;396ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig)397: StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {}398};399400/// Builder that generates the global module index file.401class GlobalModuleIndexBuilder {402FileManager &FileMgr;403const PCHContainerReader &PCHContainerRdr;404405/// Mapping from files to module file information.406using ModuleFilesMap = llvm::MapVector<FileEntryRef, ModuleFileInfo>;407408/// Information about each of the known module files.409ModuleFilesMap ModuleFiles;410411/// Mapping from the imported module file to the imported412/// information.413using ImportedModuleFilesMap =414std::multimap<FileEntryRef, ImportedModuleFileInfo>;415416/// Information about each importing of a module file.417ImportedModuleFilesMap ImportedModuleFiles;418419/// Mapping from identifiers to the list of module file IDs that420/// consider this identifier to be interesting.421typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;422423/// A mapping from all interesting identifiers to the set of module424/// files in which those identifiers are considered interesting.425InterestingIdentifierMap InterestingIdentifiers;426427/// Write the block-info block for the global module index file.428void emitBlockInfoBlock(llvm::BitstreamWriter &Stream);429430/// Retrieve the module file information for the given file.431ModuleFileInfo &getModuleFileInfo(FileEntryRef File) {432auto Known = ModuleFiles.find(File);433if (Known != ModuleFiles.end())434return Known->second;435436unsigned NewID = ModuleFiles.size();437ModuleFileInfo &Info = ModuleFiles[File];438Info.ID = NewID;439return Info;440}441442public:443explicit GlobalModuleIndexBuilder(444FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr)445: FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr) {}446447/// Load the contents of the given module file into the builder.448llvm::Error loadModuleFile(FileEntryRef File);449450/// Write the index to the given bitstream.451/// \returns true if an error occurred, false otherwise.452bool writeIndex(llvm::BitstreamWriter &Stream);453};454}455456static void emitBlockID(unsigned ID, const char *Name,457llvm::BitstreamWriter &Stream,458SmallVectorImpl<uint64_t> &Record) {459Record.clear();460Record.push_back(ID);461Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);462463// Emit the block name if present.464if (!Name || Name[0] == 0) return;465Record.clear();466while (*Name)467Record.push_back(*Name++);468Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);469}470471static void emitRecordID(unsigned ID, const char *Name,472llvm::BitstreamWriter &Stream,473SmallVectorImpl<uint64_t> &Record) {474Record.clear();475Record.push_back(ID);476while (*Name)477Record.push_back(*Name++);478Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);479}480481void482GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) {483SmallVector<uint64_t, 64> Record;484Stream.EnterBlockInfoBlock();485486#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)487#define RECORD(X) emitRecordID(X, #X, Stream, Record)488BLOCK(GLOBAL_INDEX_BLOCK);489RECORD(INDEX_METADATA);490RECORD(MODULE);491RECORD(IDENTIFIER_INDEX);492#undef RECORD493#undef BLOCK494495Stream.ExitBlock();496}497498namespace {499class InterestingASTIdentifierLookupTrait500: public serialization::reader::ASTIdentifierLookupTraitBase {501502public:503/// The identifier and whether it is "interesting".504typedef std::pair<StringRef, bool> data_type;505506data_type ReadData(const internal_key_type& k,507const unsigned char* d,508unsigned DataLen) {509// The first bit indicates whether this identifier is interesting.510// That's all we care about.511using namespace llvm::support;512IdentifierID RawID =513endian::readNext<IdentifierID, llvm::endianness::little>(d);514bool IsInteresting = RawID & 0x01;515return std::make_pair(k, IsInteresting);516}517};518}519520llvm::Error GlobalModuleIndexBuilder::loadModuleFile(FileEntryRef File) {521// Open the module file.522523auto Buffer = FileMgr.getBufferForFile(File, /*isVolatile=*/true);524if (!Buffer)525return llvm::createStringError(Buffer.getError(),526"failed getting buffer for module file");527528// Initialize the input stream529llvm::BitstreamCursor InStream(PCHContainerRdr.ExtractPCH(**Buffer));530531// Sniff for the signature.532for (unsigned char C : {'C', 'P', 'C', 'H'})533if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = InStream.Read(8)) {534if (Res.get() != C)535return llvm::createStringError(std::errc::illegal_byte_sequence,536"expected signature CPCH");537} else538return Res.takeError();539540// Record this module file and assign it a unique ID (if it doesn't have541// one already).542unsigned ID = getModuleFileInfo(File).ID;543544// Search for the blocks and records we care about.545enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other;546bool Done = false;547while (!Done) {548Expected<llvm::BitstreamEntry> MaybeEntry = InStream.advance();549if (!MaybeEntry)550return MaybeEntry.takeError();551llvm::BitstreamEntry Entry = MaybeEntry.get();552553switch (Entry.Kind) {554case llvm::BitstreamEntry::Error:555Done = true;556continue;557558case llvm::BitstreamEntry::Record:559// In the 'other' state, just skip the record. We don't care.560if (State == Other) {561if (llvm::Expected<unsigned> Skipped = InStream.skipRecord(Entry.ID))562continue;563else564return Skipped.takeError();565}566567// Handle potentially-interesting records below.568break;569570case llvm::BitstreamEntry::SubBlock:571if (Entry.ID == CONTROL_BLOCK_ID) {572if (llvm::Error Err = InStream.EnterSubBlock(CONTROL_BLOCK_ID))573return Err;574575// Found the control block.576State = ControlBlock;577continue;578}579580if (Entry.ID == AST_BLOCK_ID) {581if (llvm::Error Err = InStream.EnterSubBlock(AST_BLOCK_ID))582return Err;583584// Found the AST block.585State = ASTBlock;586continue;587}588589if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) {590if (llvm::Error Err = InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID))591return Err;592593// Found the Diagnostic Options block.594State = DiagnosticOptionsBlock;595continue;596}597598if (llvm::Error Err = InStream.SkipBlock())599return Err;600601continue;602603case llvm::BitstreamEntry::EndBlock:604State = Other;605continue;606}607608// Read the given record.609SmallVector<uint64_t, 64> Record;610StringRef Blob;611Expected<unsigned> MaybeCode = InStream.readRecord(Entry.ID, Record, &Blob);612if (!MaybeCode)613return MaybeCode.takeError();614unsigned Code = MaybeCode.get();615616// Handle module dependencies.617if (State == ControlBlock && Code == IMPORTS) {618// Load each of the imported PCH files.619unsigned Idx = 0, N = Record.size();620while (Idx < N) {621// Read information about the AST file.622623// Skip the imported kind624++Idx;625626// Skip if it is standard C++ module627++Idx;628629// Skip the import location630++Idx;631632// Load stored size/modification time.633off_t StoredSize = (off_t)Record[Idx++];634time_t StoredModTime = (time_t)Record[Idx++];635636// Skip the stored signature.637// FIXME: we could read the signature out of the import and validate it.638auto FirstSignatureByte = Record.begin() + Idx;639ASTFileSignature StoredSignature = ASTFileSignature::create(640FirstSignatureByte, FirstSignatureByte + ASTFileSignature::size);641Idx += ASTFileSignature::size;642643// Skip the module name (currently this is only used for prebuilt644// modules while here we are only dealing with cached).645Idx += Record[Idx] + 1;646647// Retrieve the imported file name.648unsigned Length = Record[Idx++];649SmallString<128> ImportedFile(Record.begin() + Idx,650Record.begin() + Idx + Length);651Idx += Length;652653// Find the imported module file.654auto DependsOnFile =655FileMgr.getOptionalFileRef(ImportedFile, /*OpenFile=*/false,656/*CacheFailure=*/false);657658if (!DependsOnFile)659return llvm::createStringError(std::errc::bad_file_descriptor,660"imported file \"%s\" not found",661ImportedFile.c_str());662663// Save the information in ImportedModuleFileInfo so we can verify after664// loading all pcms.665ImportedModuleFiles.insert(std::make_pair(666*DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,667StoredSignature)));668669// Record the dependency.670unsigned DependsOnID = getModuleFileInfo(*DependsOnFile).ID;671getModuleFileInfo(File).Dependencies.push_back(DependsOnID);672}673674continue;675}676677// Handle the identifier table678if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {679typedef llvm::OnDiskIterableChainedHashTable<680InterestingASTIdentifierLookupTrait> InterestingIdentifierTable;681std::unique_ptr<InterestingIdentifierTable> Table(682InterestingIdentifierTable::Create(683(const unsigned char *)Blob.data() + Record[0],684(const unsigned char *)Blob.data() + sizeof(uint32_t),685(const unsigned char *)Blob.data()));686for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),687DEnd = Table->data_end();688D != DEnd; ++D) {689std::pair<StringRef, bool> Ident = *D;690if (Ident.second)691InterestingIdentifiers[Ident.first].push_back(ID);692else693(void)InterestingIdentifiers[Ident.first];694}695}696697// Get Signature.698if (State == DiagnosticOptionsBlock && Code == SIGNATURE) {699auto Signature = ASTFileSignature::create(Blob.begin(), Blob.end());700assert(Signature != ASTFileSignature::createDummy() &&701"Dummy AST file signature not backpatched in ASTWriter.");702getModuleFileInfo(File).Signature = Signature;703}704705// We don't care about this record.706}707708return llvm::Error::success();709}710711namespace {712713/// Trait used to generate the identifier index as an on-disk hash714/// table.715class IdentifierIndexWriterTrait {716public:717typedef StringRef key_type;718typedef StringRef key_type_ref;719typedef SmallVector<unsigned, 2> data_type;720typedef const SmallVector<unsigned, 2> &data_type_ref;721typedef unsigned hash_value_type;722typedef unsigned offset_type;723724static hash_value_type ComputeHash(key_type_ref Key) {725return llvm::djbHash(Key);726}727728std::pair<unsigned,unsigned>729EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) {730using namespace llvm::support;731endian::Writer LE(Out, llvm::endianness::little);732unsigned KeyLen = Key.size();733unsigned DataLen = Data.size() * 4;734LE.write<uint16_t>(KeyLen);735LE.write<uint16_t>(DataLen);736return std::make_pair(KeyLen, DataLen);737}738739void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {740Out.write(Key.data(), KeyLen);741}742743void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,744unsigned DataLen) {745using namespace llvm::support;746for (unsigned I = 0, N = Data.size(); I != N; ++I)747endian::write<uint32_t>(Out, Data[I], llvm::endianness::little);748}749};750751}752753bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {754for (auto MapEntry : ImportedModuleFiles) {755auto File = MapEntry.first;756ImportedModuleFileInfo &Info = MapEntry.second;757if (getModuleFileInfo(File).Signature) {758if (getModuleFileInfo(File).Signature != Info.StoredSignature)759// Verify Signature.760return true;761} else if (Info.StoredSize != File.getSize() ||762Info.StoredModTime != File.getModificationTime())763// Verify Size and ModTime.764return true;765}766767using namespace llvm;768llvm::TimeTraceScope TimeScope("Module WriteIndex");769770// Emit the file header.771Stream.Emit((unsigned)'B', 8);772Stream.Emit((unsigned)'C', 8);773Stream.Emit((unsigned)'G', 8);774Stream.Emit((unsigned)'I', 8);775776// Write the block-info block, which describes the records in this bitcode777// file.778emitBlockInfoBlock(Stream);779780Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);781782// Write the metadata.783SmallVector<uint64_t, 2> Record;784Record.push_back(CurrentVersion);785Stream.EmitRecord(INDEX_METADATA, Record);786787// Write the set of known module files.788for (ModuleFilesMap::iterator M = ModuleFiles.begin(),789MEnd = ModuleFiles.end();790M != MEnd; ++M) {791Record.clear();792Record.push_back(M->second.ID);793Record.push_back(M->first.getSize());794Record.push_back(M->first.getModificationTime());795796// File name797StringRef Name(M->first.getName());798Record.push_back(Name.size());799Record.append(Name.begin(), Name.end());800801// Dependencies802Record.push_back(M->second.Dependencies.size());803Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());804Stream.EmitRecord(MODULE, Record);805}806807// Write the identifier -> module file mapping.808{809llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;810IdentifierIndexWriterTrait Trait;811812// Populate the hash table.813for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),814IEnd = InterestingIdentifiers.end();815I != IEnd; ++I) {816Generator.insert(I->first(), I->second, Trait);817}818819// Create the on-disk hash table in a buffer.820SmallString<4096> IdentifierTable;821uint32_t BucketOffset;822{823using namespace llvm::support;824llvm::raw_svector_ostream Out(IdentifierTable);825// Make sure that no bucket is at offset 0826endian::write<uint32_t>(Out, 0, llvm::endianness::little);827BucketOffset = Generator.Emit(Out, Trait);828}829830// Create a blob abbreviation831auto Abbrev = std::make_shared<BitCodeAbbrev>();832Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX));833Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));834Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));835unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev));836837// Write the identifier table838uint64_t Record[] = {IDENTIFIER_INDEX, BucketOffset};839Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable);840}841842Stream.ExitBlock();843return false;844}845846llvm::Error847GlobalModuleIndex::writeIndex(FileManager &FileMgr,848const PCHContainerReader &PCHContainerRdr,849StringRef Path) {850llvm::SmallString<128> IndexPath;851IndexPath += Path;852llvm::sys::path::append(IndexPath, IndexFileName);853854// Coordinate building the global index file with other processes that might855// try to do the same.856llvm::LockFileManager Locked(IndexPath);857switch (Locked) {858case llvm::LockFileManager::LFS_Error:859return llvm::createStringError(std::errc::io_error, "LFS error");860861case llvm::LockFileManager::LFS_Owned:862// We're responsible for building the index ourselves. Do so below.863break;864865case llvm::LockFileManager::LFS_Shared:866// Someone else is responsible for building the index. We don't care867// when they finish, so we're done.868return llvm::createStringError(std::errc::device_or_resource_busy,869"someone else is building the index");870}871872// The module index builder.873GlobalModuleIndexBuilder Builder(FileMgr, PCHContainerRdr);874875// Load each of the module files.876std::error_code EC;877for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;878D != DEnd && !EC;879D.increment(EC)) {880// If this isn't a module file, we don't care.881if (llvm::sys::path::extension(D->path()) != ".pcm") {882// ... unless it's a .pcm.lock file, which indicates that someone is883// in the process of rebuilding a module. They'll rebuild the index884// at the end of that translation unit, so we don't have to.885if (llvm::sys::path::extension(D->path()) == ".pcm.lock")886return llvm::createStringError(std::errc::device_or_resource_busy,887"someone else is building the index");888889continue;890}891892// If we can't find the module file, skip it.893auto ModuleFile = FileMgr.getOptionalFileRef(D->path());894if (!ModuleFile)895continue;896897// Load this module file.898if (llvm::Error Err = Builder.loadModuleFile(*ModuleFile))899return Err;900}901902// The output buffer, into which the global index will be written.903SmallString<16> OutputBuffer;904{905llvm::BitstreamWriter OutputStream(OutputBuffer);906if (Builder.writeIndex(OutputStream))907return llvm::createStringError(std::errc::io_error,908"failed writing index");909}910911return llvm::writeToOutput(IndexPath, [&OutputBuffer](llvm::raw_ostream &OS) {912OS << OutputBuffer;913return llvm::Error::success();914});915}916917namespace {918class GlobalIndexIdentifierIterator : public IdentifierIterator {919/// The current position within the identifier lookup table.920IdentifierIndexTable::key_iterator Current;921922/// The end position within the identifier lookup table.923IdentifierIndexTable::key_iterator End;924925public:926explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) {927Current = Idx.key_begin();928End = Idx.key_end();929}930931StringRef Next() override {932if (Current == End)933return StringRef();934935StringRef Result = *Current;936++Current;937return Result;938}939};940}941942IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const {943IdentifierIndexTable &Table =944*static_cast<IdentifierIndexTable *>(IdentifierIndex);945return new GlobalIndexIdentifierIterator(Table);946}947948949