15e306b12SDouglas Gregor //===--- GlobalModuleIndex.cpp - Global Module Index ------------*- C++ -*-===// 25e306b12SDouglas Gregor // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65e306b12SDouglas Gregor // 75e306b12SDouglas Gregor //===----------------------------------------------------------------------===// 85e306b12SDouglas Gregor // 95e306b12SDouglas Gregor // This file implements the GlobalModuleIndex class. 105e306b12SDouglas Gregor // 115e306b12SDouglas Gregor //===----------------------------------------------------------------------===// 125e306b12SDouglas Gregor 13d880de2dSAnton Afanasyev 145e306b12SDouglas Gregor #include "ASTReaderInternals.h" 155e306b12SDouglas Gregor #include "clang/Basic/FileManager.h" 16beee15e7SBen Langmuir #include "clang/Lex/HeaderSearch.h" 175e306b12SDouglas Gregor #include "clang/Serialization/ASTBitCodes.h" 185e306b12SDouglas Gregor #include "clang/Serialization/GlobalModuleIndex.h" 19603cd869SDouglas Gregor #include "clang/Serialization/Module.h" 20f3b0046bSRichard Trieu #include "clang/Serialization/PCHContainerOperations.h" 215e306b12SDouglas Gregor #include "llvm/ADT/DenseMap.h" 225e306b12SDouglas Gregor #include "llvm/ADT/MapVector.h" 235e306b12SDouglas Gregor #include "llvm/ADT/SmallString.h" 245e306b12SDouglas Gregor #include "llvm/Bitcode/BitstreamReader.h" 255e306b12SDouglas Gregor #include "llvm/Bitcode/BitstreamWriter.h" 26560ce2c7SJonas Devlieghere #include "llvm/Support/DJB.h" 278ec343ccSDouglas Gregor #include "llvm/Support/FileSystem.h" 285e306b12SDouglas Gregor #include "llvm/Support/LockFileManager.h" 295e306b12SDouglas Gregor #include "llvm/Support/MemoryBuffer.h" 30bb094f06SJustin Bogner #include "llvm/Support/OnDiskHashTable.h" 31552c169eSRafael Espindola #include "llvm/Support/Path.h" 32d880de2dSAnton Afanasyev #include "llvm/Support/TimeProfiler.h" 33f0add23aSNAKAMURA Takumi #include <cstdio> 345e306b12SDouglas Gregor using namespace clang; 355e306b12SDouglas Gregor using namespace serialization; 365e306b12SDouglas Gregor 375e306b12SDouglas Gregor //----------------------------------------------------------------------------// 385e306b12SDouglas Gregor // Shared constants 395e306b12SDouglas Gregor //----------------------------------------------------------------------------// 405e306b12SDouglas Gregor namespace { 415e306b12SDouglas Gregor enum { 429fc8faf9SAdrian Prantl /// The block containing the index. 435e306b12SDouglas Gregor GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID 445e306b12SDouglas Gregor }; 455e306b12SDouglas Gregor 469fc8faf9SAdrian Prantl /// Describes the record types in the index. 475e306b12SDouglas Gregor enum IndexRecordTypes { 489fc8faf9SAdrian Prantl /// Contains version information and potentially other metadata, 495e306b12SDouglas Gregor /// used to determine if we can read this global index file. 50e060e57bSDouglas Gregor INDEX_METADATA, 519fc8faf9SAdrian Prantl /// Describes a module, including its file name and dependencies. 525e306b12SDouglas Gregor MODULE, 539fc8faf9SAdrian Prantl /// The index for identifiers. 545e306b12SDouglas Gregor IDENTIFIER_INDEX 555e306b12SDouglas Gregor }; 56ab9db510SAlexander Kornienko } 575e306b12SDouglas Gregor 589fc8faf9SAdrian Prantl /// The name of the global index file. 595e306b12SDouglas Gregor static const char * const IndexFileName = "modules.idx"; 605e306b12SDouglas Gregor 619fc8faf9SAdrian Prantl /// The global index file version. 625e306b12SDouglas Gregor static const unsigned CurrentVersion = 1; 635e306b12SDouglas Gregor 645e306b12SDouglas Gregor //----------------------------------------------------------------------------// 65e060e57bSDouglas Gregor // Global module index reader. 66e060e57bSDouglas Gregor //----------------------------------------------------------------------------// 67e060e57bSDouglas Gregor 68e060e57bSDouglas Gregor namespace { 69e060e57bSDouglas Gregor 709fc8faf9SAdrian Prantl /// Trait used to read the identifier index from the on-disk hash 71e060e57bSDouglas Gregor /// table. 72e060e57bSDouglas Gregor class IdentifierIndexReaderTrait { 73e060e57bSDouglas Gregor public: 74e060e57bSDouglas Gregor typedef StringRef external_key_type; 75e060e57bSDouglas Gregor typedef StringRef internal_key_type; 76e060e57bSDouglas Gregor typedef SmallVector<unsigned, 2> data_type; 7725463f15SJustin Bogner typedef unsigned hash_value_type; 7825463f15SJustin Bogner typedef unsigned offset_type; 79e060e57bSDouglas Gregor 80e060e57bSDouglas Gregor static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { 81e060e57bSDouglas Gregor return a == b; 82e060e57bSDouglas Gregor } 83e060e57bSDouglas Gregor 8425463f15SJustin Bogner static hash_value_type ComputeHash(const internal_key_type& a) { 85560ce2c7SJonas Devlieghere return llvm::djbHash(a); 86e060e57bSDouglas Gregor } 87e060e57bSDouglas Gregor 88e060e57bSDouglas Gregor static std::pair<unsigned, unsigned> 89e060e57bSDouglas Gregor ReadKeyDataLength(const unsigned char*& d) { 9057ba0b22SJustin Bogner using namespace llvm::support; 9157ba0b22SJustin Bogner unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d); 9257ba0b22SJustin Bogner unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d); 93e060e57bSDouglas Gregor return std::make_pair(KeyLen, DataLen); 94e060e57bSDouglas Gregor } 95e060e57bSDouglas Gregor 96e060e57bSDouglas Gregor static const internal_key_type& 97e060e57bSDouglas Gregor GetInternalKey(const external_key_type& x) { return x; } 98e060e57bSDouglas Gregor 99e060e57bSDouglas Gregor static const external_key_type& 100e060e57bSDouglas Gregor GetExternalKey(const internal_key_type& x) { return x; } 101e060e57bSDouglas Gregor 102e060e57bSDouglas Gregor static internal_key_type ReadKey(const unsigned char* d, unsigned n) { 103e060e57bSDouglas Gregor return StringRef((const char *)d, n); 104e060e57bSDouglas Gregor } 105e060e57bSDouglas Gregor 106e060e57bSDouglas Gregor static data_type ReadData(const internal_key_type& k, 107e060e57bSDouglas Gregor const unsigned char* d, 108e060e57bSDouglas Gregor unsigned DataLen) { 10957ba0b22SJustin Bogner using namespace llvm::support; 110e060e57bSDouglas Gregor 111e060e57bSDouglas Gregor data_type Result; 112e060e57bSDouglas Gregor while (DataLen > 0) { 11357ba0b22SJustin Bogner unsigned ID = endian::readNext<uint32_t, little, unaligned>(d); 114e060e57bSDouglas Gregor Result.push_back(ID); 115e060e57bSDouglas Gregor DataLen -= 4; 116e060e57bSDouglas Gregor } 117e060e57bSDouglas Gregor 118e060e57bSDouglas Gregor return Result; 119e060e57bSDouglas Gregor } 120e060e57bSDouglas Gregor }; 121e060e57bSDouglas Gregor 122bb094f06SJustin Bogner typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait> 123da4e650eSJustin Bogner IdentifierIndexTable; 124e060e57bSDouglas Gregor 125ab9db510SAlexander Kornienko } 126e060e57bSDouglas Gregor 127afa10d3eSDavid Blaikie GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer, 128e060e57bSDouglas Gregor llvm::BitstreamCursor Cursor) 129afa10d3eSDavid Blaikie : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(), 130afa10d3eSDavid Blaikie NumIdentifierLookupHits() { 131*0e828958SJF Bastien auto Fail = [&Buffer](llvm::Error &&Err) { 132*0e828958SJF Bastien report_fatal_error("Module index '" + Buffer->getBufferIdentifier() + 133*0e828958SJF Bastien "' failed: " + toString(std::move(Err))); 134*0e828958SJF Bastien }; 135*0e828958SJF Bastien 136d880de2dSAnton Afanasyev llvm::TimeTraceScope TimeScope("Module LoadIndex", StringRef("")); 137e060e57bSDouglas Gregor // Read the global index. 138e060e57bSDouglas Gregor bool InGlobalIndexBlock = false; 139e060e57bSDouglas Gregor bool Done = false; 140e060e57bSDouglas Gregor while (!Done) { 141*0e828958SJF Bastien llvm::BitstreamEntry Entry; 142*0e828958SJF Bastien if (Expected<llvm::BitstreamEntry> Res = Cursor.advance()) 143*0e828958SJF Bastien Entry = Res.get(); 144*0e828958SJF Bastien else 145*0e828958SJF Bastien Fail(Res.takeError()); 146e060e57bSDouglas Gregor 147e060e57bSDouglas Gregor switch (Entry.Kind) { 148e060e57bSDouglas Gregor case llvm::BitstreamEntry::Error: 149e060e57bSDouglas Gregor return; 150e060e57bSDouglas Gregor 151e060e57bSDouglas Gregor case llvm::BitstreamEntry::EndBlock: 152e060e57bSDouglas Gregor if (InGlobalIndexBlock) { 153e060e57bSDouglas Gregor InGlobalIndexBlock = false; 154e060e57bSDouglas Gregor Done = true; 155e060e57bSDouglas Gregor continue; 156e060e57bSDouglas Gregor } 157e060e57bSDouglas Gregor return; 158e060e57bSDouglas Gregor 159e060e57bSDouglas Gregor 160e060e57bSDouglas Gregor case llvm::BitstreamEntry::Record: 161e060e57bSDouglas Gregor // Entries in the global index block are handled below. 162e060e57bSDouglas Gregor if (InGlobalIndexBlock) 163e060e57bSDouglas Gregor break; 164e060e57bSDouglas Gregor 165e060e57bSDouglas Gregor return; 166e060e57bSDouglas Gregor 167e060e57bSDouglas Gregor case llvm::BitstreamEntry::SubBlock: 168e060e57bSDouglas Gregor if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { 169*0e828958SJF Bastien if (llvm::Error Err = Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) 170*0e828958SJF Bastien Fail(std::move(Err)); 171e060e57bSDouglas Gregor InGlobalIndexBlock = true; 172*0e828958SJF Bastien } else if (llvm::Error Err = Cursor.SkipBlock()) 173*0e828958SJF Bastien Fail(std::move(Err)); 174e060e57bSDouglas Gregor continue; 175e060e57bSDouglas Gregor } 176e060e57bSDouglas Gregor 177e060e57bSDouglas Gregor SmallVector<uint64_t, 64> Record; 178e060e57bSDouglas Gregor StringRef Blob; 179*0e828958SJF Bastien Expected<unsigned> MaybeIndexRecord = 180*0e828958SJF Bastien Cursor.readRecord(Entry.ID, Record, &Blob); 181*0e828958SJF Bastien if (!MaybeIndexRecord) 182*0e828958SJF Bastien Fail(MaybeIndexRecord.takeError()); 183*0e828958SJF Bastien IndexRecordTypes IndexRecord = 184*0e828958SJF Bastien static_cast<IndexRecordTypes>(MaybeIndexRecord.get()); 185*0e828958SJF Bastien switch (IndexRecord) { 186e060e57bSDouglas Gregor case INDEX_METADATA: 187e060e57bSDouglas Gregor // Make sure that the version matches. 188e060e57bSDouglas Gregor if (Record.size() < 1 || Record[0] != CurrentVersion) 189e060e57bSDouglas Gregor return; 190e060e57bSDouglas Gregor break; 191e060e57bSDouglas Gregor 192e060e57bSDouglas Gregor case MODULE: { 193e060e57bSDouglas Gregor unsigned Idx = 0; 194e060e57bSDouglas Gregor unsigned ID = Record[Idx++]; 195e060e57bSDouglas Gregor 1967029ce1aSDouglas Gregor // Make room for this module's information. 1977029ce1aSDouglas Gregor if (ID == Modules.size()) 1987029ce1aSDouglas Gregor Modules.push_back(ModuleInfo()); 1997029ce1aSDouglas Gregor else 2007029ce1aSDouglas Gregor Modules.resize(ID + 1); 2017029ce1aSDouglas Gregor 2027029ce1aSDouglas Gregor // Size/modification time for this module file at the time the 2037029ce1aSDouglas Gregor // global index was built. 2047029ce1aSDouglas Gregor Modules[ID].Size = Record[Idx++]; 2057029ce1aSDouglas Gregor Modules[ID].ModTime = Record[Idx++]; 206e060e57bSDouglas Gregor 207e060e57bSDouglas Gregor // File name. 208e060e57bSDouglas Gregor unsigned NameLen = Record[Idx++]; 2097029ce1aSDouglas Gregor Modules[ID].FileName.assign(Record.begin() + Idx, 210e060e57bSDouglas Gregor Record.begin() + Idx + NameLen); 211e060e57bSDouglas Gregor Idx += NameLen; 212e060e57bSDouglas Gregor 213e060e57bSDouglas Gregor // Dependencies 214e060e57bSDouglas Gregor unsigned NumDeps = Record[Idx++]; 2157029ce1aSDouglas Gregor Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(), 2167029ce1aSDouglas Gregor Record.begin() + Idx, 2177029ce1aSDouglas Gregor Record.begin() + Idx + NumDeps); 2187029ce1aSDouglas Gregor Idx += NumDeps; 219e060e57bSDouglas Gregor 2207029ce1aSDouglas Gregor // Make sure we're at the end of the record. 2217029ce1aSDouglas Gregor assert(Idx == Record.size() && "More module info?"); 222603cd869SDouglas Gregor 223603cd869SDouglas Gregor // Record this module as an unresolved module. 224beee15e7SBen Langmuir // FIXME: this doesn't work correctly for module names containing path 225beee15e7SBen Langmuir // separators. 226beee15e7SBen Langmuir StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName); 227beee15e7SBen Langmuir // Remove the -<hash of ModuleMapPath> 228beee15e7SBen Langmuir ModuleName = ModuleName.rsplit('-').first; 229beee15e7SBen Langmuir UnresolvedModules[ModuleName] = ID; 230e060e57bSDouglas Gregor break; 231e060e57bSDouglas Gregor } 232e060e57bSDouglas Gregor 233e060e57bSDouglas Gregor case IDENTIFIER_INDEX: 234e060e57bSDouglas Gregor // Wire up the identifier index. 235e060e57bSDouglas Gregor if (Record[0]) { 236e060e57bSDouglas Gregor IdentifierIndex = IdentifierIndexTable::Create( 237e060e57bSDouglas Gregor (const unsigned char *)Blob.data() + Record[0], 238da4e650eSJustin Bogner (const unsigned char *)Blob.data() + sizeof(uint32_t), 239da4e650eSJustin Bogner (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait()); 240e060e57bSDouglas Gregor } 241e060e57bSDouglas Gregor break; 242e060e57bSDouglas Gregor } 243e060e57bSDouglas Gregor } 244e060e57bSDouglas Gregor } 245e060e57bSDouglas Gregor 246e68b847fSNico Weber GlobalModuleIndex::~GlobalModuleIndex() { 247e68b847fSNico Weber delete static_cast<IdentifierIndexTable *>(IdentifierIndex); 248e68b847fSNico Weber } 249e060e57bSDouglas Gregor 250*0e828958SJF Bastien std::pair<GlobalModuleIndex *, llvm::Error> 2517029ce1aSDouglas Gregor GlobalModuleIndex::readIndex(StringRef Path) { 252e060e57bSDouglas Gregor // Load the index file, if it's there. 253e060e57bSDouglas Gregor llvm::SmallString<128> IndexPath; 254e060e57bSDouglas Gregor IndexPath += Path; 255e060e57bSDouglas Gregor llvm::sys::path::append(IndexPath, IndexFileName); 256e060e57bSDouglas Gregor 2572d2b420aSRafael Espindola llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr = 2582d2b420aSRafael Espindola llvm::MemoryBuffer::getFile(IndexPath.c_str()); 2592d2b420aSRafael Espindola if (!BufferOrErr) 260*0e828958SJF Bastien return std::make_pair(nullptr, 261*0e828958SJF Bastien llvm::errorCodeToError(BufferOrErr.getError())); 2622d2b420aSRafael Espindola std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get()); 263e060e57bSDouglas Gregor 2649fc8faf9SAdrian Prantl /// The main bitstream cursor for the main block. 26577c89b69SPeter Collingbourne llvm::BitstreamCursor Cursor(*Buffer); 266e060e57bSDouglas Gregor 267e060e57bSDouglas Gregor // Sniff for the signature. 268*0e828958SJF Bastien for (unsigned char C : {'B', 'C', 'G', 'I'}) { 269*0e828958SJF Bastien if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Cursor.Read(8)) { 270*0e828958SJF Bastien if (Res.get() != C) 271*0e828958SJF Bastien return std::make_pair( 272*0e828958SJF Bastien nullptr, llvm::createStringError(std::errc::illegal_byte_sequence, 273*0e828958SJF Bastien "expected signature BCGI")); 274*0e828958SJF Bastien } else 275*0e828958SJF Bastien return std::make_pair(nullptr, Res.takeError()); 276e060e57bSDouglas Gregor } 277e060e57bSDouglas Gregor 278afa10d3eSDavid Blaikie return std::make_pair(new GlobalModuleIndex(std::move(Buffer), Cursor), 279*0e828958SJF Bastien llvm::Error::success()); 280e060e57bSDouglas Gregor } 281e060e57bSDouglas Gregor 2827029ce1aSDouglas Gregor void 2837029ce1aSDouglas Gregor GlobalModuleIndex::getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles) { 284e060e57bSDouglas Gregor ModuleFiles.clear(); 285e060e57bSDouglas Gregor for (unsigned I = 0, N = Modules.size(); I != N; ++I) { 286603cd869SDouglas Gregor if (ModuleFile *MF = Modules[I].File) 287603cd869SDouglas Gregor ModuleFiles.push_back(MF); 288e060e57bSDouglas Gregor } 289e060e57bSDouglas Gregor } 290e060e57bSDouglas Gregor 291e060e57bSDouglas Gregor void GlobalModuleIndex::getModuleDependencies( 2927029ce1aSDouglas Gregor ModuleFile *File, 2937029ce1aSDouglas Gregor SmallVectorImpl<ModuleFile *> &Dependencies) { 294e060e57bSDouglas Gregor // Look for information about this module file. 2957029ce1aSDouglas Gregor llvm::DenseMap<ModuleFile *, unsigned>::iterator Known 2967029ce1aSDouglas Gregor = ModulesByFile.find(File); 297e060e57bSDouglas Gregor if (Known == ModulesByFile.end()) 298e060e57bSDouglas Gregor return; 299e060e57bSDouglas Gregor 300e060e57bSDouglas Gregor // Record dependencies. 3017029ce1aSDouglas Gregor Dependencies.clear(); 3027029ce1aSDouglas Gregor ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies; 3037029ce1aSDouglas Gregor for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) { 304603cd869SDouglas Gregor if (ModuleFile *MF = Modules[I].File) 3057029ce1aSDouglas Gregor Dependencies.push_back(MF); 3067029ce1aSDouglas Gregor } 307e060e57bSDouglas Gregor } 308e060e57bSDouglas Gregor 3097211ac15SDouglas Gregor bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) { 3107211ac15SDouglas Gregor Hits.clear(); 311e060e57bSDouglas Gregor 312e060e57bSDouglas Gregor // If there's no identifier index, there is nothing we can do. 313e060e57bSDouglas Gregor if (!IdentifierIndex) 314e060e57bSDouglas Gregor return false; 315e060e57bSDouglas Gregor 316e060e57bSDouglas Gregor // Look into the identifier index. 317e060e57bSDouglas Gregor ++NumIdentifierLookups; 318e060e57bSDouglas Gregor IdentifierIndexTable &Table 319e060e57bSDouglas Gregor = *static_cast<IdentifierIndexTable *>(IdentifierIndex); 320e060e57bSDouglas Gregor IdentifierIndexTable::iterator Known = Table.find(Name); 321e060e57bSDouglas Gregor if (Known == Table.end()) { 322e060e57bSDouglas Gregor return true; 323e060e57bSDouglas Gregor } 324e060e57bSDouglas Gregor 325e060e57bSDouglas Gregor SmallVector<unsigned, 2> ModuleIDs = *Known; 326e060e57bSDouglas Gregor for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) { 327603cd869SDouglas Gregor if (ModuleFile *MF = Modules[ModuleIDs[I]].File) 328603cd869SDouglas Gregor Hits.insert(MF); 329e060e57bSDouglas Gregor } 330e060e57bSDouglas Gregor 331e060e57bSDouglas Gregor ++NumIdentifierLookupHits; 332e060e57bSDouglas Gregor return true; 333e060e57bSDouglas Gregor } 334e060e57bSDouglas Gregor 335603cd869SDouglas Gregor bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) { 336603cd869SDouglas Gregor // Look for the module in the global module index based on the module name. 337beee15e7SBen Langmuir StringRef Name = File->ModuleName; 338603cd869SDouglas Gregor llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name); 339603cd869SDouglas Gregor if (Known == UnresolvedModules.end()) { 340603cd869SDouglas Gregor return true; 3417029ce1aSDouglas Gregor } 3427029ce1aSDouglas Gregor 343603cd869SDouglas Gregor // Rectify this module with the global module index. 344603cd869SDouglas Gregor ModuleInfo &Info = Modules[Known->second]; 345603cd869SDouglas Gregor 346603cd869SDouglas Gregor // If the size and modification time match what we expected, record this 347603cd869SDouglas Gregor // module file. 348603cd869SDouglas Gregor bool Failed = true; 349603cd869SDouglas Gregor if (File->File->getSize() == Info.Size && 350603cd869SDouglas Gregor File->File->getModificationTime() == Info.ModTime) { 351603cd869SDouglas Gregor Info.File = File; 352603cd869SDouglas Gregor ModulesByFile[File] = Known->second; 353603cd869SDouglas Gregor 354603cd869SDouglas Gregor Failed = false; 3557029ce1aSDouglas Gregor } 3567029ce1aSDouglas Gregor 357603cd869SDouglas Gregor // One way or another, we have resolved this module file. 358603cd869SDouglas Gregor UnresolvedModules.erase(Known); 359603cd869SDouglas Gregor return Failed; 3607029ce1aSDouglas Gregor } 3617029ce1aSDouglas Gregor 362e060e57bSDouglas Gregor void GlobalModuleIndex::printStats() { 363e060e57bSDouglas Gregor std::fprintf(stderr, "*** Global Module Index Statistics:\n"); 364e060e57bSDouglas Gregor if (NumIdentifierLookups) { 365e060e57bSDouglas Gregor fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n", 366e060e57bSDouglas Gregor NumIdentifierLookupHits, NumIdentifierLookups, 367e060e57bSDouglas Gregor (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups); 368e060e57bSDouglas Gregor } 369e060e57bSDouglas Gregor std::fprintf(stderr, "\n"); 370e060e57bSDouglas Gregor } 371e060e57bSDouglas Gregor 372cdae941eSYaron Keren LLVM_DUMP_METHOD void GlobalModuleIndex::dump() { 373a39baf1aSJohn Thompson llvm::errs() << "*** Global Module Index Dump:\n"; 374a39baf1aSJohn Thompson llvm::errs() << "Module files:\n"; 3754f52d44dSJohn Thompson for (auto &MI : Modules) { 376a39baf1aSJohn Thompson llvm::errs() << "** " << MI.FileName << "\n"; 377a39baf1aSJohn Thompson if (MI.File) 378a39baf1aSJohn Thompson MI.File->dump(); 379bcdcc92eSJohn Thompson else 380a39baf1aSJohn Thompson llvm::errs() << "\n"; 381bcdcc92eSJohn Thompson } 382a39baf1aSJohn Thompson llvm::errs() << "\n"; 383bcdcc92eSJohn Thompson } 384bcdcc92eSJohn Thompson 385e060e57bSDouglas Gregor //----------------------------------------------------------------------------// 3865e306b12SDouglas Gregor // Global module index writer. 3875e306b12SDouglas Gregor //----------------------------------------------------------------------------// 3885e306b12SDouglas Gregor 3895e306b12SDouglas Gregor namespace { 3909fc8faf9SAdrian Prantl /// Provides information about a specific module file. 3915e306b12SDouglas Gregor struct ModuleFileInfo { 3929fc8faf9SAdrian Prantl /// The numberic ID for this module file. 3935e306b12SDouglas Gregor unsigned ID; 3945e306b12SDouglas Gregor 3959fc8faf9SAdrian Prantl /// The set of modules on which this module depends. Each entry is 3965e306b12SDouglas Gregor /// a module ID. 3975e306b12SDouglas Gregor SmallVector<unsigned, 4> Dependencies; 39860fa2888SDuncan P. N. Exon Smith ASTFileSignature Signature; 39960fa2888SDuncan P. N. Exon Smith }; 40060fa2888SDuncan P. N. Exon Smith 40160fa2888SDuncan P. N. Exon Smith struct ImportedModuleFileInfo { 40260fa2888SDuncan P. N. Exon Smith off_t StoredSize; 40360fa2888SDuncan P. N. Exon Smith time_t StoredModTime; 40460fa2888SDuncan P. N. Exon Smith ASTFileSignature StoredSignature; 40560fa2888SDuncan P. N. Exon Smith ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig) 40660fa2888SDuncan P. N. Exon Smith : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {} 4075e306b12SDouglas Gregor }; 4085e306b12SDouglas Gregor 4099fc8faf9SAdrian Prantl /// Builder that generates the global module index file. 4105e306b12SDouglas Gregor class GlobalModuleIndexBuilder { 4115e306b12SDouglas Gregor FileManager &FileMgr; 412fb2398d0SAdrian Prantl const PCHContainerReader &PCHContainerRdr; 4135e306b12SDouglas Gregor 41460fa2888SDuncan P. N. Exon Smith /// Mapping from files to module file information. 4155e306b12SDouglas Gregor typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap; 4165e306b12SDouglas Gregor 41760fa2888SDuncan P. N. Exon Smith /// Information about each of the known module files. 4185e306b12SDouglas Gregor ModuleFilesMap ModuleFiles; 4195e306b12SDouglas Gregor 4209fc8faf9SAdrian Prantl /// Mapping from the imported module file to the imported 42160fa2888SDuncan P. N. Exon Smith /// information. 42260fa2888SDuncan P. N. Exon Smith typedef std::multimap<const FileEntry *, ImportedModuleFileInfo> 42360fa2888SDuncan P. N. Exon Smith ImportedModuleFilesMap; 42460fa2888SDuncan P. N. Exon Smith 4259fc8faf9SAdrian Prantl /// Information about each importing of a module file. 42660fa2888SDuncan P. N. Exon Smith ImportedModuleFilesMap ImportedModuleFiles; 42760fa2888SDuncan P. N. Exon Smith 4289fc8faf9SAdrian Prantl /// Mapping from identifiers to the list of module file IDs that 4295e306b12SDouglas Gregor /// consider this identifier to be interesting. 4305e306b12SDouglas Gregor typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap; 4315e306b12SDouglas Gregor 4329fc8faf9SAdrian Prantl /// A mapping from all interesting identifiers to the set of module 4335e306b12SDouglas Gregor /// files in which those identifiers are considered interesting. 4345e306b12SDouglas Gregor InterestingIdentifierMap InterestingIdentifiers; 4355e306b12SDouglas Gregor 4369fc8faf9SAdrian Prantl /// Write the block-info block for the global module index file. 4375e306b12SDouglas Gregor void emitBlockInfoBlock(llvm::BitstreamWriter &Stream); 4385e306b12SDouglas Gregor 4399fc8faf9SAdrian Prantl /// Retrieve the module file information for the given file. 4405e306b12SDouglas Gregor ModuleFileInfo &getModuleFileInfo(const FileEntry *File) { 4415e306b12SDouglas Gregor llvm::MapVector<const FileEntry *, ModuleFileInfo>::iterator Known 4425e306b12SDouglas Gregor = ModuleFiles.find(File); 4435e306b12SDouglas Gregor if (Known != ModuleFiles.end()) 4445e306b12SDouglas Gregor return Known->second; 4455e306b12SDouglas Gregor 4465e306b12SDouglas Gregor unsigned NewID = ModuleFiles.size(); 4475e306b12SDouglas Gregor ModuleFileInfo &Info = ModuleFiles[File]; 4485e306b12SDouglas Gregor Info.ID = NewID; 4495e306b12SDouglas Gregor return Info; 4505e306b12SDouglas Gregor } 4515e306b12SDouglas Gregor 4525e306b12SDouglas Gregor public: 453bb165fb0SAdrian Prantl explicit GlobalModuleIndexBuilder( 454fb2398d0SAdrian Prantl FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr) 455fb2398d0SAdrian Prantl : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr) {} 4565e306b12SDouglas Gregor 4579fc8faf9SAdrian Prantl /// Load the contents of the given module file into the builder. 458*0e828958SJF Bastien llvm::Error loadModuleFile(const FileEntry *File); 4595e306b12SDouglas Gregor 4609fc8faf9SAdrian Prantl /// Write the index to the given bitstream. 46160fa2888SDuncan P. N. Exon Smith /// \returns true if an error occurred, false otherwise. 46260fa2888SDuncan P. N. Exon Smith bool writeIndex(llvm::BitstreamWriter &Stream); 4635e306b12SDouglas Gregor }; 464ab9db510SAlexander Kornienko } 4655e306b12SDouglas Gregor 4665e306b12SDouglas Gregor static void emitBlockID(unsigned ID, const char *Name, 4675e306b12SDouglas Gregor llvm::BitstreamWriter &Stream, 4685e306b12SDouglas Gregor SmallVectorImpl<uint64_t> &Record) { 4695e306b12SDouglas Gregor Record.clear(); 4705e306b12SDouglas Gregor Record.push_back(ID); 4715e306b12SDouglas Gregor Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); 4725e306b12SDouglas Gregor 4735e306b12SDouglas Gregor // Emit the block name if present. 474a13603a2SCraig Topper if (!Name || Name[0] == 0) return; 4755e306b12SDouglas Gregor Record.clear(); 4765e306b12SDouglas Gregor while (*Name) 4775e306b12SDouglas Gregor Record.push_back(*Name++); 4785e306b12SDouglas Gregor Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); 4795e306b12SDouglas Gregor } 4805e306b12SDouglas Gregor 4815e306b12SDouglas Gregor static void emitRecordID(unsigned ID, const char *Name, 4825e306b12SDouglas Gregor llvm::BitstreamWriter &Stream, 4835e306b12SDouglas Gregor SmallVectorImpl<uint64_t> &Record) { 4845e306b12SDouglas Gregor Record.clear(); 4855e306b12SDouglas Gregor Record.push_back(ID); 4865e306b12SDouglas Gregor while (*Name) 4875e306b12SDouglas Gregor Record.push_back(*Name++); 4885e306b12SDouglas Gregor Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); 4895e306b12SDouglas Gregor } 4905e306b12SDouglas Gregor 4915e306b12SDouglas Gregor void 4925e306b12SDouglas Gregor GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) { 4935e306b12SDouglas Gregor SmallVector<uint64_t, 64> Record; 494d3a6c70bSPeter Collingbourne Stream.EnterBlockInfoBlock(); 4955e306b12SDouglas Gregor 4965e306b12SDouglas Gregor #define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record) 4975e306b12SDouglas Gregor #define RECORD(X) emitRecordID(X, #X, Stream, Record) 4985e306b12SDouglas Gregor BLOCK(GLOBAL_INDEX_BLOCK); 499e060e57bSDouglas Gregor RECORD(INDEX_METADATA); 5005e306b12SDouglas Gregor RECORD(MODULE); 5015e306b12SDouglas Gregor RECORD(IDENTIFIER_INDEX); 5025e306b12SDouglas Gregor #undef RECORD 5035e306b12SDouglas Gregor #undef BLOCK 5045e306b12SDouglas Gregor 5055e306b12SDouglas Gregor Stream.ExitBlock(); 5065e306b12SDouglas Gregor } 5075e306b12SDouglas Gregor 508e060e57bSDouglas Gregor namespace { 5095e306b12SDouglas Gregor class InterestingASTIdentifierLookupTrait 5105e306b12SDouglas Gregor : public serialization::reader::ASTIdentifierLookupTraitBase { 5115e306b12SDouglas Gregor 5125e306b12SDouglas Gregor public: 5139fc8faf9SAdrian Prantl /// The identifier and whether it is "interesting". 5145e306b12SDouglas Gregor typedef std::pair<StringRef, bool> data_type; 5155e306b12SDouglas Gregor 5165e306b12SDouglas Gregor data_type ReadData(const internal_key_type& k, 5175e306b12SDouglas Gregor const unsigned char* d, 5185e306b12SDouglas Gregor unsigned DataLen) { 5195e306b12SDouglas Gregor // The first bit indicates whether this identifier is interesting. 5205e306b12SDouglas Gregor // That's all we care about. 52157ba0b22SJustin Bogner using namespace llvm::support; 52257ba0b22SJustin Bogner unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d); 5235e306b12SDouglas Gregor bool IsInteresting = RawID & 0x01; 5245e306b12SDouglas Gregor return std::make_pair(k, IsInteresting); 5255e306b12SDouglas Gregor } 5265e306b12SDouglas Gregor }; 527ab9db510SAlexander Kornienko } 5285e306b12SDouglas Gregor 529*0e828958SJF Bastien llvm::Error GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { 5305e306b12SDouglas Gregor // Open the module file. 5316406f7b8SRafael Espindola 532a885796dSBenjamin Kramer auto Buffer = FileMgr.getBufferForFile(File, /*isVolatile=*/true); 533*0e828958SJF Bastien if (!Buffer) 534*0e828958SJF Bastien return llvm::createStringError(Buffer.getError(), 535*0e828958SJF Bastien "failed getting buffer for module file"); 5365e306b12SDouglas Gregor 5375e306b12SDouglas Gregor // Initialize the input stream 53877c89b69SPeter Collingbourne llvm::BitstreamCursor InStream(PCHContainerRdr.ExtractPCH(**Buffer)); 5395e306b12SDouglas Gregor 5405e306b12SDouglas Gregor // Sniff for the signature. 541*0e828958SJF Bastien for (unsigned char C : {'C', 'P', 'C', 'H'}) 542*0e828958SJF Bastien if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = InStream.Read(8)) { 543*0e828958SJF Bastien if (Res.get() != C) 544*0e828958SJF Bastien return llvm::createStringError(std::errc::illegal_byte_sequence, 545*0e828958SJF Bastien "expected signature CPCH"); 546*0e828958SJF Bastien } else 547*0e828958SJF Bastien return Res.takeError(); 5485e306b12SDouglas Gregor 5495e306b12SDouglas Gregor // Record this module file and assign it a unique ID (if it doesn't have 5505e306b12SDouglas Gregor // one already). 5515e306b12SDouglas Gregor unsigned ID = getModuleFileInfo(File).ID; 5525e306b12SDouglas Gregor 5535e306b12SDouglas Gregor // Search for the blocks and records we care about. 55460fa2888SDuncan P. N. Exon Smith enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other; 5555e306b12SDouglas Gregor bool Done = false; 5565e306b12SDouglas Gregor while (!Done) { 557*0e828958SJF Bastien Expected<llvm::BitstreamEntry> MaybeEntry = InStream.advance(); 558*0e828958SJF Bastien if (!MaybeEntry) 559*0e828958SJF Bastien return MaybeEntry.takeError(); 560*0e828958SJF Bastien llvm::BitstreamEntry Entry = MaybeEntry.get(); 561*0e828958SJF Bastien 5625e306b12SDouglas Gregor switch (Entry.Kind) { 5635e306b12SDouglas Gregor case llvm::BitstreamEntry::Error: 564e060e57bSDouglas Gregor Done = true; 565e060e57bSDouglas Gregor continue; 5665e306b12SDouglas Gregor 5675e306b12SDouglas Gregor case llvm::BitstreamEntry::Record: 568e060e57bSDouglas Gregor // In the 'other' state, just skip the record. We don't care. 569e060e57bSDouglas Gregor if (State == Other) { 570*0e828958SJF Bastien if (llvm::Expected<unsigned> Skipped = InStream.skipRecord(Entry.ID)) 5715e306b12SDouglas Gregor continue; 572*0e828958SJF Bastien else 573*0e828958SJF Bastien return Skipped.takeError(); 5745e306b12SDouglas Gregor } 5755e306b12SDouglas Gregor 5765e306b12SDouglas Gregor // Handle potentially-interesting records below. 5775e306b12SDouglas Gregor break; 5785e306b12SDouglas Gregor 5795e306b12SDouglas Gregor case llvm::BitstreamEntry::SubBlock: 580e060e57bSDouglas Gregor if (Entry.ID == CONTROL_BLOCK_ID) { 581*0e828958SJF Bastien if (llvm::Error Err = InStream.EnterSubBlock(CONTROL_BLOCK_ID)) 582*0e828958SJF Bastien return Err; 5835e306b12SDouglas Gregor 5845e306b12SDouglas Gregor // Found the control block. 5855e306b12SDouglas Gregor State = ControlBlock; 5865e306b12SDouglas Gregor continue; 5875e306b12SDouglas Gregor } 5885e306b12SDouglas Gregor 589e060e57bSDouglas Gregor if (Entry.ID == AST_BLOCK_ID) { 590*0e828958SJF Bastien if (llvm::Error Err = InStream.EnterSubBlock(AST_BLOCK_ID)) 591*0e828958SJF Bastien return Err; 5925e306b12SDouglas Gregor 5935e306b12SDouglas Gregor // Found the AST block. 5945e306b12SDouglas Gregor State = ASTBlock; 5955e306b12SDouglas Gregor continue; 5965e306b12SDouglas Gregor } 5975e306b12SDouglas Gregor 59860fa2888SDuncan P. N. Exon Smith if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) { 599*0e828958SJF Bastien if (llvm::Error Err = InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID)) 600*0e828958SJF Bastien return Err; 60160fa2888SDuncan P. N. Exon Smith 60260fa2888SDuncan P. N. Exon Smith // Found the Diagnostic Options block. 60360fa2888SDuncan P. N. Exon Smith State = DiagnosticOptionsBlock; 60460fa2888SDuncan P. N. Exon Smith continue; 60560fa2888SDuncan P. N. Exon Smith } 60660fa2888SDuncan P. N. Exon Smith 607*0e828958SJF Bastien if (llvm::Error Err = InStream.SkipBlock()) 608*0e828958SJF Bastien return Err; 6095e306b12SDouglas Gregor 6105e306b12SDouglas Gregor continue; 6115e306b12SDouglas Gregor 6125e306b12SDouglas Gregor case llvm::BitstreamEntry::EndBlock: 613e060e57bSDouglas Gregor State = Other; 6145e306b12SDouglas Gregor continue; 6155e306b12SDouglas Gregor } 6165e306b12SDouglas Gregor 6175e306b12SDouglas Gregor // Read the given record. 6185e306b12SDouglas Gregor SmallVector<uint64_t, 64> Record; 6195e306b12SDouglas Gregor StringRef Blob; 620*0e828958SJF Bastien Expected<unsigned> MaybeCode = InStream.readRecord(Entry.ID, Record, &Blob); 621*0e828958SJF Bastien if (!MaybeCode) 622*0e828958SJF Bastien return MaybeCode.takeError(); 623*0e828958SJF Bastien unsigned Code = MaybeCode.get(); 6245e306b12SDouglas Gregor 6255e306b12SDouglas Gregor // Handle module dependencies. 6265e306b12SDouglas Gregor if (State == ControlBlock && Code == IMPORTS) { 6275e306b12SDouglas Gregor // Load each of the imported PCH files. 6285e306b12SDouglas Gregor unsigned Idx = 0, N = Record.size(); 6295e306b12SDouglas Gregor while (Idx < N) { 6305e306b12SDouglas Gregor // Read information about the AST file. 6315e306b12SDouglas Gregor 6325e306b12SDouglas Gregor // Skip the imported kind 6335e306b12SDouglas Gregor ++Idx; 6345e306b12SDouglas Gregor 6355e306b12SDouglas Gregor // Skip the import location 6365e306b12SDouglas Gregor ++Idx; 6375e306b12SDouglas Gregor 6387029ce1aSDouglas Gregor // Load stored size/modification time. 6397029ce1aSDouglas Gregor off_t StoredSize = (off_t)Record[Idx++]; 6407029ce1aSDouglas Gregor time_t StoredModTime = (time_t)Record[Idx++]; 6417029ce1aSDouglas Gregor 642487ea14aSBen Langmuir // Skip the stored signature. 643487ea14aSBen Langmuir // FIXME: we could read the signature out of the import and validate it. 64460fa2888SDuncan P. N. Exon Smith ASTFileSignature StoredSignature = { 64560fa2888SDuncan P. N. Exon Smith {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++], 64660fa2888SDuncan P. N. Exon Smith (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], 64760fa2888SDuncan P. N. Exon Smith (uint32_t)Record[Idx++]}}}; 648487ea14aSBen Langmuir 649d30446fdSBoris Kolpackov // Skip the module name (currently this is only used for prebuilt 650d30446fdSBoris Kolpackov // modules while here we are only dealing with cached). 651d30446fdSBoris Kolpackov Idx += Record[Idx] + 1; 652d30446fdSBoris Kolpackov 6535e306b12SDouglas Gregor // Retrieve the imported file name. 6545e306b12SDouglas Gregor unsigned Length = Record[Idx++]; 6555e306b12SDouglas Gregor SmallString<128> ImportedFile(Record.begin() + Idx, 6565e306b12SDouglas Gregor Record.begin() + Idx + Length); 6575e306b12SDouglas Gregor Idx += Length; 6585e306b12SDouglas Gregor 6595e306b12SDouglas Gregor // Find the imported module file. 660dadd85dcSDouglas Gregor const FileEntry *DependsOnFile 661dadd85dcSDouglas Gregor = FileMgr.getFile(ImportedFile, /*openFile=*/false, 662dadd85dcSDouglas Gregor /*cacheFailure=*/false); 66360fa2888SDuncan P. N. Exon Smith 66460fa2888SDuncan P. N. Exon Smith if (!DependsOnFile) 665*0e828958SJF Bastien return llvm::createStringError(std::errc::bad_file_descriptor, 666*0e828958SJF Bastien "imported file \"%s\" not found", 667*0e828958SJF Bastien ImportedFile.c_str()); 6685e306b12SDouglas Gregor 66960fa2888SDuncan P. N. Exon Smith // Save the information in ImportedModuleFileInfo so we can verify after 67060fa2888SDuncan P. N. Exon Smith // loading all pcms. 67160fa2888SDuncan P. N. Exon Smith ImportedModuleFiles.insert(std::make_pair( 67260fa2888SDuncan P. N. Exon Smith DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime, 67360fa2888SDuncan P. N. Exon Smith StoredSignature))); 67460fa2888SDuncan P. N. Exon Smith 6755e306b12SDouglas Gregor // Record the dependency. 6765e306b12SDouglas Gregor unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID; 6775e306b12SDouglas Gregor getModuleFileInfo(File).Dependencies.push_back(DependsOnID); 6785e306b12SDouglas Gregor } 6795e306b12SDouglas Gregor 6805e306b12SDouglas Gregor continue; 6815e306b12SDouglas Gregor } 6825e306b12SDouglas Gregor 6835e306b12SDouglas Gregor // Handle the identifier table 6845e306b12SDouglas Gregor if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) { 685bb094f06SJustin Bogner typedef llvm::OnDiskIterableChainedHashTable< 686bb094f06SJustin Bogner InterestingASTIdentifierLookupTrait> InterestingIdentifierTable; 687b8984329SAhmed Charles std::unique_ptr<InterestingIdentifierTable> Table( 688b8984329SAhmed Charles InterestingIdentifierTable::Create( 6895e306b12SDouglas Gregor (const unsigned char *)Blob.data() + Record[0], 690da4e650eSJustin Bogner (const unsigned char *)Blob.data() + sizeof(uint32_t), 6915e306b12SDouglas Gregor (const unsigned char *)Blob.data())); 6925e306b12SDouglas Gregor for (InterestingIdentifierTable::data_iterator D = Table->data_begin(), 6935e306b12SDouglas Gregor DEnd = Table->data_end(); 6945e306b12SDouglas Gregor D != DEnd; ++D) { 6955e306b12SDouglas Gregor std::pair<StringRef, bool> Ident = *D; 6965e306b12SDouglas Gregor if (Ident.second) 6975e306b12SDouglas Gregor InterestingIdentifiers[Ident.first].push_back(ID); 698e060e57bSDouglas Gregor else 699e060e57bSDouglas Gregor (void)InterestingIdentifiers[Ident.first]; 7005e306b12SDouglas Gregor } 7015e306b12SDouglas Gregor } 7025e306b12SDouglas Gregor 70360fa2888SDuncan P. N. Exon Smith // Get Signature. 70460fa2888SDuncan P. N. Exon Smith if (State == DiagnosticOptionsBlock && Code == SIGNATURE) 70560fa2888SDuncan P. N. Exon Smith getModuleFileInfo(File).Signature = { 70660fa2888SDuncan P. N. Exon Smith {{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2], 70760fa2888SDuncan P. N. Exon Smith (uint32_t)Record[3], (uint32_t)Record[4]}}}; 70860fa2888SDuncan P. N. Exon Smith 7095e306b12SDouglas Gregor // We don't care about this record. 7105e306b12SDouglas Gregor } 7115e306b12SDouglas Gregor 712*0e828958SJF Bastien return llvm::Error::success(); 7135e306b12SDouglas Gregor } 7145e306b12SDouglas Gregor 7155e306b12SDouglas Gregor namespace { 7165e306b12SDouglas Gregor 7179fc8faf9SAdrian Prantl /// Trait used to generate the identifier index as an on-disk hash 7185e306b12SDouglas Gregor /// table. 7195e306b12SDouglas Gregor class IdentifierIndexWriterTrait { 7205e306b12SDouglas Gregor public: 7215e306b12SDouglas Gregor typedef StringRef key_type; 7225e306b12SDouglas Gregor typedef StringRef key_type_ref; 7235e306b12SDouglas Gregor typedef SmallVector<unsigned, 2> data_type; 7245e306b12SDouglas Gregor typedef const SmallVector<unsigned, 2> &data_type_ref; 72525463f15SJustin Bogner typedef unsigned hash_value_type; 72625463f15SJustin Bogner typedef unsigned offset_type; 7275e306b12SDouglas Gregor 72825463f15SJustin Bogner static hash_value_type ComputeHash(key_type_ref Key) { 729560ce2c7SJonas Devlieghere return llvm::djbHash(Key); 7305e306b12SDouglas Gregor } 7315e306b12SDouglas Gregor 7325e306b12SDouglas Gregor std::pair<unsigned,unsigned> 7335e306b12SDouglas Gregor EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) { 734e1c147c3SJustin Bogner using namespace llvm::support; 735e3f65297SPeter Collingbourne endian::Writer LE(Out, little); 7365e306b12SDouglas Gregor unsigned KeyLen = Key.size(); 7375e306b12SDouglas Gregor unsigned DataLen = Data.size() * 4; 738e1c147c3SJustin Bogner LE.write<uint16_t>(KeyLen); 739e1c147c3SJustin Bogner LE.write<uint16_t>(DataLen); 7405e306b12SDouglas Gregor return std::make_pair(KeyLen, DataLen); 7415e306b12SDouglas Gregor } 7425e306b12SDouglas Gregor 7435e306b12SDouglas Gregor void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) { 7445e306b12SDouglas Gregor Out.write(Key.data(), KeyLen); 7455e306b12SDouglas Gregor } 7465e306b12SDouglas Gregor 7475e306b12SDouglas Gregor void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data, 7485e306b12SDouglas Gregor unsigned DataLen) { 749e1c147c3SJustin Bogner using namespace llvm::support; 7505e306b12SDouglas Gregor for (unsigned I = 0, N = Data.size(); I != N; ++I) 751e3f65297SPeter Collingbourne endian::write<uint32_t>(Out, Data[I], little); 7525e306b12SDouglas Gregor } 7535e306b12SDouglas Gregor }; 7545e306b12SDouglas Gregor 755ab9db510SAlexander Kornienko } 7565e306b12SDouglas Gregor 75760fa2888SDuncan P. N. Exon Smith bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { 75860fa2888SDuncan P. N. Exon Smith for (auto MapEntry : ImportedModuleFiles) { 75960fa2888SDuncan P. N. Exon Smith auto *File = MapEntry.first; 76060fa2888SDuncan P. N. Exon Smith ImportedModuleFileInfo &Info = MapEntry.second; 76160fa2888SDuncan P. N. Exon Smith if (getModuleFileInfo(File).Signature) { 76260fa2888SDuncan P. N. Exon Smith if (getModuleFileInfo(File).Signature != Info.StoredSignature) 76360fa2888SDuncan P. N. Exon Smith // Verify Signature. 76460fa2888SDuncan P. N. Exon Smith return true; 76560fa2888SDuncan P. N. Exon Smith } else if (Info.StoredSize != File->getSize() || 76660fa2888SDuncan P. N. Exon Smith Info.StoredModTime != File->getModificationTime()) 76760fa2888SDuncan P. N. Exon Smith // Verify Size and ModTime. 76860fa2888SDuncan P. N. Exon Smith return true; 76960fa2888SDuncan P. N. Exon Smith } 77060fa2888SDuncan P. N. Exon Smith 7715e306b12SDouglas Gregor using namespace llvm; 772d880de2dSAnton Afanasyev llvm::TimeTraceScope TimeScope("Module WriteIndex", StringRef("")); 7735e306b12SDouglas Gregor 7745e306b12SDouglas Gregor // Emit the file header. 7755e306b12SDouglas Gregor Stream.Emit((unsigned)'B', 8); 7765e306b12SDouglas Gregor Stream.Emit((unsigned)'C', 8); 7775e306b12SDouglas Gregor Stream.Emit((unsigned)'G', 8); 7785e306b12SDouglas Gregor Stream.Emit((unsigned)'I', 8); 7795e306b12SDouglas Gregor 7805e306b12SDouglas Gregor // Write the block-info block, which describes the records in this bitcode 7815e306b12SDouglas Gregor // file. 7825e306b12SDouglas Gregor emitBlockInfoBlock(Stream); 7835e306b12SDouglas Gregor 7845e306b12SDouglas Gregor Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3); 7855e306b12SDouglas Gregor 7865e306b12SDouglas Gregor // Write the metadata. 7875e306b12SDouglas Gregor SmallVector<uint64_t, 2> Record; 7885e306b12SDouglas Gregor Record.push_back(CurrentVersion); 789e060e57bSDouglas Gregor Stream.EmitRecord(INDEX_METADATA, Record); 7905e306b12SDouglas Gregor 7915e306b12SDouglas Gregor // Write the set of known module files. 7925e306b12SDouglas Gregor for (ModuleFilesMap::iterator M = ModuleFiles.begin(), 7935e306b12SDouglas Gregor MEnd = ModuleFiles.end(); 7945e306b12SDouglas Gregor M != MEnd; ++M) { 7955e306b12SDouglas Gregor Record.clear(); 7965e306b12SDouglas Gregor Record.push_back(M->second.ID); 7975e306b12SDouglas Gregor Record.push_back(M->first->getSize()); 7985e306b12SDouglas Gregor Record.push_back(M->first->getModificationTime()); 7995e306b12SDouglas Gregor 8005e306b12SDouglas Gregor // File name 8015e306b12SDouglas Gregor StringRef Name(M->first->getName()); 8025e306b12SDouglas Gregor Record.push_back(Name.size()); 8035e306b12SDouglas Gregor Record.append(Name.begin(), Name.end()); 8045e306b12SDouglas Gregor 8055e306b12SDouglas Gregor // Dependencies 8065e306b12SDouglas Gregor Record.push_back(M->second.Dependencies.size()); 8075e306b12SDouglas Gregor Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end()); 8085e306b12SDouglas Gregor Stream.EmitRecord(MODULE, Record); 8095e306b12SDouglas Gregor } 8105e306b12SDouglas Gregor 8115e306b12SDouglas Gregor // Write the identifier -> module file mapping. 8125e306b12SDouglas Gregor { 813bb094f06SJustin Bogner llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator; 8145e306b12SDouglas Gregor IdentifierIndexWriterTrait Trait; 8155e306b12SDouglas Gregor 8165e306b12SDouglas Gregor // Populate the hash table. 8175e306b12SDouglas Gregor for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(), 8185e306b12SDouglas Gregor IEnd = InterestingIdentifiers.end(); 8195e306b12SDouglas Gregor I != IEnd; ++I) { 8205e306b12SDouglas Gregor Generator.insert(I->first(), I->second, Trait); 8215e306b12SDouglas Gregor } 8225e306b12SDouglas Gregor 8235e306b12SDouglas Gregor // Create the on-disk hash table in a buffer. 8245e306b12SDouglas Gregor SmallString<4096> IdentifierTable; 8255e306b12SDouglas Gregor uint32_t BucketOffset; 8265e306b12SDouglas Gregor { 827e1c147c3SJustin Bogner using namespace llvm::support; 8285e306b12SDouglas Gregor llvm::raw_svector_ostream Out(IdentifierTable); 8295e306b12SDouglas Gregor // Make sure that no bucket is at offset 0 830e3f65297SPeter Collingbourne endian::write<uint32_t>(Out, 0, little); 8315e306b12SDouglas Gregor BucketOffset = Generator.Emit(Out, Trait); 8325e306b12SDouglas Gregor } 8335e306b12SDouglas Gregor 8345e306b12SDouglas Gregor // Create a blob abbreviation 835b44f0bfbSDavid Blaikie auto Abbrev = std::make_shared<BitCodeAbbrev>(); 8365e306b12SDouglas Gregor Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX)); 8375e306b12SDouglas Gregor Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); 8385e306b12SDouglas Gregor Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); 839b44f0bfbSDavid Blaikie unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); 8405e306b12SDouglas Gregor 8415e306b12SDouglas Gregor // Write the identifier table 84257a41913SMehdi Amini uint64_t Record[] = {IDENTIFIER_INDEX, BucketOffset}; 84392e1b62dSYaron Keren Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable); 8445e306b12SDouglas Gregor } 8455e306b12SDouglas Gregor 8465e306b12SDouglas Gregor Stream.ExitBlock(); 84760fa2888SDuncan P. N. Exon Smith return false; 8485e306b12SDouglas Gregor } 8495e306b12SDouglas Gregor 850*0e828958SJF Bastien llvm::Error 851bb165fb0SAdrian Prantl GlobalModuleIndex::writeIndex(FileManager &FileMgr, 852fb2398d0SAdrian Prantl const PCHContainerReader &PCHContainerRdr, 853bb165fb0SAdrian Prantl StringRef Path) { 8545e306b12SDouglas Gregor llvm::SmallString<128> IndexPath; 8555e306b12SDouglas Gregor IndexPath += Path; 8565e306b12SDouglas Gregor llvm::sys::path::append(IndexPath, IndexFileName); 8575e306b12SDouglas Gregor 8585e306b12SDouglas Gregor // Coordinate building the global index file with other processes that might 8595e306b12SDouglas Gregor // try to do the same. 8605e306b12SDouglas Gregor llvm::LockFileManager Locked(IndexPath); 8615e306b12SDouglas Gregor switch (Locked) { 8625e306b12SDouglas Gregor case llvm::LockFileManager::LFS_Error: 863*0e828958SJF Bastien return llvm::createStringError(std::errc::io_error, "LFS error"); 8645e306b12SDouglas Gregor 8655e306b12SDouglas Gregor case llvm::LockFileManager::LFS_Owned: 8665e306b12SDouglas Gregor // We're responsible for building the index ourselves. Do so below. 8675e306b12SDouglas Gregor break; 8685e306b12SDouglas Gregor 8695e306b12SDouglas Gregor case llvm::LockFileManager::LFS_Shared: 8705e306b12SDouglas Gregor // Someone else is responsible for building the index. We don't care 8715e306b12SDouglas Gregor // when they finish, so we're done. 872*0e828958SJF Bastien return llvm::createStringError(std::errc::device_or_resource_busy, 873*0e828958SJF Bastien "someone else is building the index"); 8745e306b12SDouglas Gregor } 8755e306b12SDouglas Gregor 8765e306b12SDouglas Gregor // The module index builder. 877fb2398d0SAdrian Prantl GlobalModuleIndexBuilder Builder(FileMgr, PCHContainerRdr); 8785e306b12SDouglas Gregor 8795e306b12SDouglas Gregor // Load each of the module files. 880c080917eSRafael Espindola std::error_code EC; 8815e306b12SDouglas Gregor for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd; 8825e306b12SDouglas Gregor D != DEnd && !EC; 8835e306b12SDouglas Gregor D.increment(EC)) { 8845e306b12SDouglas Gregor // If this isn't a module file, we don't care. 8855e306b12SDouglas Gregor if (llvm::sys::path::extension(D->path()) != ".pcm") { 8865e306b12SDouglas Gregor // ... unless it's a .pcm.lock file, which indicates that someone is 8875e306b12SDouglas Gregor // in the process of rebuilding a module. They'll rebuild the index 8885e306b12SDouglas Gregor // at the end of that translation unit, so we don't have to. 8895e306b12SDouglas Gregor if (llvm::sys::path::extension(D->path()) == ".pcm.lock") 890*0e828958SJF Bastien return llvm::createStringError(std::errc::device_or_resource_busy, 891*0e828958SJF Bastien "someone else is building the index"); 8925e306b12SDouglas Gregor 8935e306b12SDouglas Gregor continue; 8945e306b12SDouglas Gregor } 8955e306b12SDouglas Gregor 8965e306b12SDouglas Gregor // If we can't find the module file, skip it. 8975e306b12SDouglas Gregor const FileEntry *ModuleFile = FileMgr.getFile(D->path()); 8985e306b12SDouglas Gregor if (!ModuleFile) 8995e306b12SDouglas Gregor continue; 9005e306b12SDouglas Gregor 9015e306b12SDouglas Gregor // Load this module file. 902*0e828958SJF Bastien if (llvm::Error Err = Builder.loadModuleFile(ModuleFile)) 903*0e828958SJF Bastien return Err; 9045e306b12SDouglas Gregor } 9055e306b12SDouglas Gregor 9065e306b12SDouglas Gregor // The output buffer, into which the global index will be written. 9075e306b12SDouglas Gregor SmallVector<char, 16> OutputBuffer; 9085e306b12SDouglas Gregor { 9095e306b12SDouglas Gregor llvm::BitstreamWriter OutputStream(OutputBuffer); 91060fa2888SDuncan P. N. Exon Smith if (Builder.writeIndex(OutputStream)) 911*0e828958SJF Bastien return llvm::createStringError(std::errc::io_error, 912*0e828958SJF Bastien "failed writing index"); 9135e306b12SDouglas Gregor } 9145e306b12SDouglas Gregor 9155e306b12SDouglas Gregor // Write the global index file to a temporary file. 9165e306b12SDouglas Gregor llvm::SmallString<128> IndexTmpPath; 9175e306b12SDouglas Gregor int TmpFD; 91818627115SRafael Espindola if (llvm::sys::fs::createUniqueFile(IndexPath + "-%%%%%%%%", TmpFD, 91918627115SRafael Espindola IndexTmpPath)) 920*0e828958SJF Bastien return llvm::createStringError(std::errc::io_error, 921*0e828958SJF Bastien "failed creating unique file"); 9225e306b12SDouglas Gregor 9235e306b12SDouglas Gregor // Open the temporary global index file for output. 924e00c9868SNAKAMURA Takumi llvm::raw_fd_ostream Out(TmpFD, true); 9255e306b12SDouglas Gregor if (Out.has_error()) 926*0e828958SJF Bastien return llvm::createStringError(Out.error(), "failed outputting to stream"); 9275e306b12SDouglas Gregor 9285e306b12SDouglas Gregor // Write the index. 9295e306b12SDouglas Gregor Out.write(OutputBuffer.data(), OutputBuffer.size()); 9305e306b12SDouglas Gregor Out.close(); 9315e306b12SDouglas Gregor if (Out.has_error()) 932*0e828958SJF Bastien return llvm::createStringError(Out.error(), "failed writing to stream"); 9335e306b12SDouglas Gregor 9345e306b12SDouglas Gregor // Remove the old index file. It isn't relevant any more. 93592e1b62dSYaron Keren llvm::sys::fs::remove(IndexPath); 9365e306b12SDouglas Gregor 9375e306b12SDouglas Gregor // Rename the newly-written index file to the proper name. 938*0e828958SJF Bastien if (std::error_code Err = llvm::sys::fs::rename(IndexTmpPath, IndexPath)) { 939*0e828958SJF Bastien // Remove the file on failure, don't check whether removal succeeded. 94092e1b62dSYaron Keren llvm::sys::fs::remove(IndexTmpPath); 941*0e828958SJF Bastien return llvm::createStringError(Err, "failed renaming file \"%s\" to \"%s\"", 942*0e828958SJF Bastien IndexTmpPath.c_str(), IndexPath.c_str()); 9435e306b12SDouglas Gregor } 9445e306b12SDouglas Gregor 945*0e828958SJF Bastien return llvm::Error::success(); 9465e306b12SDouglas Gregor } 9479aca3c61SArgyrios Kyrtzidis 9489aca3c61SArgyrios Kyrtzidis namespace { 9499aca3c61SArgyrios Kyrtzidis class GlobalIndexIdentifierIterator : public IdentifierIterator { 9509fc8faf9SAdrian Prantl /// The current position within the identifier lookup table. 9519aca3c61SArgyrios Kyrtzidis IdentifierIndexTable::key_iterator Current; 9529aca3c61SArgyrios Kyrtzidis 9539fc8faf9SAdrian Prantl /// The end position within the identifier lookup table. 9549aca3c61SArgyrios Kyrtzidis IdentifierIndexTable::key_iterator End; 9559aca3c61SArgyrios Kyrtzidis 9569aca3c61SArgyrios Kyrtzidis public: 9579aca3c61SArgyrios Kyrtzidis explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) { 9589aca3c61SArgyrios Kyrtzidis Current = Idx.key_begin(); 9599aca3c61SArgyrios Kyrtzidis End = Idx.key_end(); 9609aca3c61SArgyrios Kyrtzidis } 9619aca3c61SArgyrios Kyrtzidis 9623e89dfeeSCraig Topper StringRef Next() override { 9639aca3c61SArgyrios Kyrtzidis if (Current == End) 9649aca3c61SArgyrios Kyrtzidis return StringRef(); 9659aca3c61SArgyrios Kyrtzidis 9669aca3c61SArgyrios Kyrtzidis StringRef Result = *Current; 9679aca3c61SArgyrios Kyrtzidis ++Current; 9689aca3c61SArgyrios Kyrtzidis return Result; 9699aca3c61SArgyrios Kyrtzidis } 9709aca3c61SArgyrios Kyrtzidis }; 971ab9db510SAlexander Kornienko } 9729aca3c61SArgyrios Kyrtzidis 9739aca3c61SArgyrios Kyrtzidis IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const { 9749aca3c61SArgyrios Kyrtzidis IdentifierIndexTable &Table = 9759aca3c61SArgyrios Kyrtzidis *static_cast<IdentifierIndexTable *>(IdentifierIndex); 9769aca3c61SArgyrios Kyrtzidis return new GlobalIndexIdentifierIterator(Table); 9779aca3c61SArgyrios Kyrtzidis } 978