10b57cec5SDimitry Andric //===--- GlobalModuleIndex.cpp - Global Module Index ------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the GlobalModuleIndex class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 13480093f4SDimitry Andric #include "clang/Serialization/GlobalModuleIndex.h" 140b57cec5SDimitry Andric #include "ASTReaderInternals.h" 150b57cec5SDimitry Andric #include "clang/Basic/FileManager.h" 160b57cec5SDimitry Andric #include "clang/Serialization/ASTBitCodes.h" 17480093f4SDimitry Andric #include "clang/Serialization/ModuleFile.h" 180b57cec5SDimitry Andric #include "clang/Serialization/PCHContainerOperations.h" 190b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 200b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h" 210b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 22a7dea167SDimitry Andric #include "llvm/ADT/StringRef.h" 230b57cec5SDimitry Andric #include "llvm/Bitstream/BitstreamReader.h" 240b57cec5SDimitry Andric #include "llvm/Bitstream/BitstreamWriter.h" 250b57cec5SDimitry Andric #include "llvm/Support/DJB.h" 260b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 270b57cec5SDimitry Andric #include "llvm/Support/LockFileManager.h" 280b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 290b57cec5SDimitry Andric #include "llvm/Support/OnDiskHashTable.h" 300b57cec5SDimitry Andric #include "llvm/Support/Path.h" 310b57cec5SDimitry Andric #include "llvm/Support/TimeProfiler.h" 3206c3fb27SDimitry Andric #include "llvm/Support/raw_ostream.h" 330b57cec5SDimitry Andric #include <cstdio> 340b57cec5SDimitry Andric using namespace clang; 350b57cec5SDimitry Andric using namespace serialization; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric //----------------------------------------------------------------------------// 380b57cec5SDimitry Andric // Shared constants 390b57cec5SDimitry Andric //----------------------------------------------------------------------------// 400b57cec5SDimitry Andric namespace { 410b57cec5SDimitry Andric enum { 420b57cec5SDimitry Andric /// The block containing the index. 430b57cec5SDimitry Andric GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID 440b57cec5SDimitry Andric }; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric /// Describes the record types in the index. 470b57cec5SDimitry Andric enum IndexRecordTypes { 480b57cec5SDimitry Andric /// Contains version information and potentially other metadata, 490b57cec5SDimitry Andric /// used to determine if we can read this global index file. 500b57cec5SDimitry Andric INDEX_METADATA, 510b57cec5SDimitry Andric /// Describes a module, including its file name and dependencies. 520b57cec5SDimitry Andric MODULE, 530b57cec5SDimitry Andric /// The index for identifiers. 540b57cec5SDimitry Andric IDENTIFIER_INDEX 550b57cec5SDimitry Andric }; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric /// The name of the global index file. 590b57cec5SDimitry Andric static const char * const IndexFileName = "modules.idx"; 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric /// The global index file version. 620b57cec5SDimitry Andric static const unsigned CurrentVersion = 1; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric //----------------------------------------------------------------------------// 650b57cec5SDimitry Andric // Global module index reader. 660b57cec5SDimitry Andric //----------------------------------------------------------------------------// 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric namespace { 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric /// Trait used to read the identifier index from the on-disk hash 710b57cec5SDimitry Andric /// table. 720b57cec5SDimitry Andric class IdentifierIndexReaderTrait { 730b57cec5SDimitry Andric public: 740b57cec5SDimitry Andric typedef StringRef external_key_type; 750b57cec5SDimitry Andric typedef StringRef internal_key_type; 760b57cec5SDimitry Andric typedef SmallVector<unsigned, 2> data_type; 770b57cec5SDimitry Andric typedef unsigned hash_value_type; 780b57cec5SDimitry Andric typedef unsigned offset_type; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { 810b57cec5SDimitry Andric return a == b; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric static hash_value_type ComputeHash(const internal_key_type& a) { 850b57cec5SDimitry Andric return llvm::djbHash(a); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric static std::pair<unsigned, unsigned> 890b57cec5SDimitry Andric ReadKeyDataLength(const unsigned char*& d) { 900b57cec5SDimitry Andric using namespace llvm::support; 91*0fca6ea1SDimitry Andric unsigned KeyLen = endian::readNext<uint16_t, llvm::endianness::little>(d); 92*0fca6ea1SDimitry Andric unsigned DataLen = endian::readNext<uint16_t, llvm::endianness::little>(d); 930b57cec5SDimitry Andric return std::make_pair(KeyLen, DataLen); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric static const internal_key_type& 970b57cec5SDimitry Andric GetInternalKey(const external_key_type& x) { return x; } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric static const external_key_type& 1000b57cec5SDimitry Andric GetExternalKey(const internal_key_type& x) { return x; } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric static internal_key_type ReadKey(const unsigned char* d, unsigned n) { 1030b57cec5SDimitry Andric return StringRef((const char *)d, n); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric static data_type ReadData(const internal_key_type& k, 1070b57cec5SDimitry Andric const unsigned char* d, 1080b57cec5SDimitry Andric unsigned DataLen) { 1090b57cec5SDimitry Andric using namespace llvm::support; 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric data_type Result; 1120b57cec5SDimitry Andric while (DataLen > 0) { 113*0fca6ea1SDimitry Andric unsigned ID = endian::readNext<uint32_t, llvm::endianness::little>(d); 1140b57cec5SDimitry Andric Result.push_back(ID); 1150b57cec5SDimitry Andric DataLen -= 4; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric return Result; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric }; 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait> 1230b57cec5SDimitry Andric IdentifierIndexTable; 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 127480093f4SDimitry Andric GlobalModuleIndex::GlobalModuleIndex( 128480093f4SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> IndexBuffer, 1290b57cec5SDimitry Andric llvm::BitstreamCursor Cursor) 130480093f4SDimitry Andric : Buffer(std::move(IndexBuffer)), IdentifierIndex(), NumIdentifierLookups(), 1310b57cec5SDimitry Andric NumIdentifierLookupHits() { 132480093f4SDimitry Andric auto Fail = [&](llvm::Error &&Err) { 1330b57cec5SDimitry Andric report_fatal_error("Module index '" + Buffer->getBufferIdentifier() + 1340b57cec5SDimitry Andric "' failed: " + toString(std::move(Err))); 1350b57cec5SDimitry Andric }; 1360b57cec5SDimitry Andric 137480093f4SDimitry Andric llvm::TimeTraceScope TimeScope("Module LoadIndex"); 1380b57cec5SDimitry Andric // Read the global index. 1390b57cec5SDimitry Andric bool InGlobalIndexBlock = false; 1400b57cec5SDimitry Andric bool Done = false; 1410b57cec5SDimitry Andric while (!Done) { 1420b57cec5SDimitry Andric llvm::BitstreamEntry Entry; 1430b57cec5SDimitry Andric if (Expected<llvm::BitstreamEntry> Res = Cursor.advance()) 1440b57cec5SDimitry Andric Entry = Res.get(); 1450b57cec5SDimitry Andric else 1460b57cec5SDimitry Andric Fail(Res.takeError()); 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric switch (Entry.Kind) { 1490b57cec5SDimitry Andric case llvm::BitstreamEntry::Error: 1500b57cec5SDimitry Andric return; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric case llvm::BitstreamEntry::EndBlock: 1530b57cec5SDimitry Andric if (InGlobalIndexBlock) { 1540b57cec5SDimitry Andric InGlobalIndexBlock = false; 1550b57cec5SDimitry Andric Done = true; 1560b57cec5SDimitry Andric continue; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric return; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric case llvm::BitstreamEntry::Record: 1620b57cec5SDimitry Andric // Entries in the global index block are handled below. 1630b57cec5SDimitry Andric if (InGlobalIndexBlock) 1640b57cec5SDimitry Andric break; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric return; 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric case llvm::BitstreamEntry::SubBlock: 1690b57cec5SDimitry Andric if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { 1700b57cec5SDimitry Andric if (llvm::Error Err = Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) 1710b57cec5SDimitry Andric Fail(std::move(Err)); 1720b57cec5SDimitry Andric InGlobalIndexBlock = true; 1730b57cec5SDimitry Andric } else if (llvm::Error Err = Cursor.SkipBlock()) 1740b57cec5SDimitry Andric Fail(std::move(Err)); 1750b57cec5SDimitry Andric continue; 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric SmallVector<uint64_t, 64> Record; 1790b57cec5SDimitry Andric StringRef Blob; 1800b57cec5SDimitry Andric Expected<unsigned> MaybeIndexRecord = 1810b57cec5SDimitry Andric Cursor.readRecord(Entry.ID, Record, &Blob); 1820b57cec5SDimitry Andric if (!MaybeIndexRecord) 1830b57cec5SDimitry Andric Fail(MaybeIndexRecord.takeError()); 1840b57cec5SDimitry Andric IndexRecordTypes IndexRecord = 1850b57cec5SDimitry Andric static_cast<IndexRecordTypes>(MaybeIndexRecord.get()); 1860b57cec5SDimitry Andric switch (IndexRecord) { 1870b57cec5SDimitry Andric case INDEX_METADATA: 1880b57cec5SDimitry Andric // Make sure that the version matches. 1890b57cec5SDimitry Andric if (Record.size() < 1 || Record[0] != CurrentVersion) 1900b57cec5SDimitry Andric return; 1910b57cec5SDimitry Andric break; 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric case MODULE: { 1940b57cec5SDimitry Andric unsigned Idx = 0; 1950b57cec5SDimitry Andric unsigned ID = Record[Idx++]; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // Make room for this module's information. 1980b57cec5SDimitry Andric if (ID == Modules.size()) 1990b57cec5SDimitry Andric Modules.push_back(ModuleInfo()); 2000b57cec5SDimitry Andric else 2010b57cec5SDimitry Andric Modules.resize(ID + 1); 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric // Size/modification time for this module file at the time the 2040b57cec5SDimitry Andric // global index was built. 2050b57cec5SDimitry Andric Modules[ID].Size = Record[Idx++]; 2060b57cec5SDimitry Andric Modules[ID].ModTime = Record[Idx++]; 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric // File name. 2090b57cec5SDimitry Andric unsigned NameLen = Record[Idx++]; 2100b57cec5SDimitry Andric Modules[ID].FileName.assign(Record.begin() + Idx, 2110b57cec5SDimitry Andric Record.begin() + Idx + NameLen); 2120b57cec5SDimitry Andric Idx += NameLen; 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric // Dependencies 2150b57cec5SDimitry Andric unsigned NumDeps = Record[Idx++]; 2160b57cec5SDimitry Andric Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(), 2170b57cec5SDimitry Andric Record.begin() + Idx, 2180b57cec5SDimitry Andric Record.begin() + Idx + NumDeps); 2190b57cec5SDimitry Andric Idx += NumDeps; 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric // Make sure we're at the end of the record. 2220b57cec5SDimitry Andric assert(Idx == Record.size() && "More module info?"); 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric // Record this module as an unresolved module. 2250b57cec5SDimitry Andric // FIXME: this doesn't work correctly for module names containing path 2260b57cec5SDimitry Andric // separators. 2270b57cec5SDimitry Andric StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName); 2280b57cec5SDimitry Andric // Remove the -<hash of ModuleMapPath> 2290b57cec5SDimitry Andric ModuleName = ModuleName.rsplit('-').first; 2300b57cec5SDimitry Andric UnresolvedModules[ModuleName] = ID; 2310b57cec5SDimitry Andric break; 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric case IDENTIFIER_INDEX: 2350b57cec5SDimitry Andric // Wire up the identifier index. 2360b57cec5SDimitry Andric if (Record[0]) { 2370b57cec5SDimitry Andric IdentifierIndex = IdentifierIndexTable::Create( 2380b57cec5SDimitry Andric (const unsigned char *)Blob.data() + Record[0], 2390b57cec5SDimitry Andric (const unsigned char *)Blob.data() + sizeof(uint32_t), 2400b57cec5SDimitry Andric (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait()); 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric break; 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric GlobalModuleIndex::~GlobalModuleIndex() { 2480b57cec5SDimitry Andric delete static_cast<IdentifierIndexTable *>(IdentifierIndex); 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric std::pair<GlobalModuleIndex *, llvm::Error> 2520b57cec5SDimitry Andric GlobalModuleIndex::readIndex(StringRef Path) { 2530b57cec5SDimitry Andric // Load the index file, if it's there. 2540b57cec5SDimitry Andric llvm::SmallString<128> IndexPath; 2550b57cec5SDimitry Andric IndexPath += Path; 2560b57cec5SDimitry Andric llvm::sys::path::append(IndexPath, IndexFileName); 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr = 2590b57cec5SDimitry Andric llvm::MemoryBuffer::getFile(IndexPath.c_str()); 2600b57cec5SDimitry Andric if (!BufferOrErr) 2610b57cec5SDimitry Andric return std::make_pair(nullptr, 2620b57cec5SDimitry Andric llvm::errorCodeToError(BufferOrErr.getError())); 2630b57cec5SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get()); 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric /// The main bitstream cursor for the main block. 2660b57cec5SDimitry Andric llvm::BitstreamCursor Cursor(*Buffer); 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric // Sniff for the signature. 2690b57cec5SDimitry Andric for (unsigned char C : {'B', 'C', 'G', 'I'}) { 2700b57cec5SDimitry Andric if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Cursor.Read(8)) { 2710b57cec5SDimitry Andric if (Res.get() != C) 2720b57cec5SDimitry Andric return std::make_pair( 2730b57cec5SDimitry Andric nullptr, llvm::createStringError(std::errc::illegal_byte_sequence, 2740b57cec5SDimitry Andric "expected signature BCGI")); 2750b57cec5SDimitry Andric } else 2760b57cec5SDimitry Andric return std::make_pair(nullptr, Res.takeError()); 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 27981ad6265SDimitry Andric return std::make_pair(new GlobalModuleIndex(std::move(Buffer), std::move(Cursor)), 2800b57cec5SDimitry Andric llvm::Error::success()); 2810b57cec5SDimitry Andric } 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric void GlobalModuleIndex::getModuleDependencies( 2840b57cec5SDimitry Andric ModuleFile *File, 2850b57cec5SDimitry Andric SmallVectorImpl<ModuleFile *> &Dependencies) { 2860b57cec5SDimitry Andric // Look for information about this module file. 2870b57cec5SDimitry Andric llvm::DenseMap<ModuleFile *, unsigned>::iterator Known 2880b57cec5SDimitry Andric = ModulesByFile.find(File); 2890b57cec5SDimitry Andric if (Known == ModulesByFile.end()) 2900b57cec5SDimitry Andric return; 2910b57cec5SDimitry Andric 2920b57cec5SDimitry Andric // Record dependencies. 2930b57cec5SDimitry Andric Dependencies.clear(); 2940b57cec5SDimitry Andric ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies; 2950b57cec5SDimitry Andric for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) { 2960b57cec5SDimitry Andric if (ModuleFile *MF = Modules[I].File) 2970b57cec5SDimitry Andric Dependencies.push_back(MF); 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) { 3020b57cec5SDimitry Andric Hits.clear(); 3030b57cec5SDimitry Andric 3040b57cec5SDimitry Andric // If there's no identifier index, there is nothing we can do. 3050b57cec5SDimitry Andric if (!IdentifierIndex) 3060b57cec5SDimitry Andric return false; 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric // Look into the identifier index. 3090b57cec5SDimitry Andric ++NumIdentifierLookups; 3100b57cec5SDimitry Andric IdentifierIndexTable &Table 3110b57cec5SDimitry Andric = *static_cast<IdentifierIndexTable *>(IdentifierIndex); 3120b57cec5SDimitry Andric IdentifierIndexTable::iterator Known = Table.find(Name); 3130b57cec5SDimitry Andric if (Known == Table.end()) { 3145ffd83dbSDimitry Andric return false; 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric SmallVector<unsigned, 2> ModuleIDs = *Known; 3180b57cec5SDimitry Andric for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) { 3190b57cec5SDimitry Andric if (ModuleFile *MF = Modules[ModuleIDs[I]].File) 3200b57cec5SDimitry Andric Hits.insert(MF); 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric ++NumIdentifierLookupHits; 3240b57cec5SDimitry Andric return true; 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) { 3280b57cec5SDimitry Andric // Look for the module in the global module index based on the module name. 3290b57cec5SDimitry Andric StringRef Name = File->ModuleName; 3300b57cec5SDimitry Andric llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name); 3310b57cec5SDimitry Andric if (Known == UnresolvedModules.end()) { 3320b57cec5SDimitry Andric return true; 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric // Rectify this module with the global module index. 3360b57cec5SDimitry Andric ModuleInfo &Info = Modules[Known->second]; 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric // If the size and modification time match what we expected, record this 3390b57cec5SDimitry Andric // module file. 3400b57cec5SDimitry Andric bool Failed = true; 3415f757f3fSDimitry Andric if (File->File.getSize() == Info.Size && 3425f757f3fSDimitry Andric File->File.getModificationTime() == Info.ModTime) { 3430b57cec5SDimitry Andric Info.File = File; 3440b57cec5SDimitry Andric ModulesByFile[File] = Known->second; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric Failed = false; 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric // One way or another, we have resolved this module file. 3500b57cec5SDimitry Andric UnresolvedModules.erase(Known); 3510b57cec5SDimitry Andric return Failed; 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric void GlobalModuleIndex::printStats() { 3550b57cec5SDimitry Andric std::fprintf(stderr, "*** Global Module Index Statistics:\n"); 3560b57cec5SDimitry Andric if (NumIdentifierLookups) { 3570b57cec5SDimitry Andric fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n", 3580b57cec5SDimitry Andric NumIdentifierLookupHits, NumIdentifierLookups, 3590b57cec5SDimitry Andric (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups); 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric std::fprintf(stderr, "\n"); 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric LLVM_DUMP_METHOD void GlobalModuleIndex::dump() { 3650b57cec5SDimitry Andric llvm::errs() << "*** Global Module Index Dump:\n"; 3660b57cec5SDimitry Andric llvm::errs() << "Module files:\n"; 3670b57cec5SDimitry Andric for (auto &MI : Modules) { 3680b57cec5SDimitry Andric llvm::errs() << "** " << MI.FileName << "\n"; 3690b57cec5SDimitry Andric if (MI.File) 3700b57cec5SDimitry Andric MI.File->dump(); 3710b57cec5SDimitry Andric else 3720b57cec5SDimitry Andric llvm::errs() << "\n"; 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric llvm::errs() << "\n"; 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric //----------------------------------------------------------------------------// 3780b57cec5SDimitry Andric // Global module index writer. 3790b57cec5SDimitry Andric //----------------------------------------------------------------------------// 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric namespace { 3820b57cec5SDimitry Andric /// Provides information about a specific module file. 3830b57cec5SDimitry Andric struct ModuleFileInfo { 3840b57cec5SDimitry Andric /// The numberic ID for this module file. 3850b57cec5SDimitry Andric unsigned ID; 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric /// The set of modules on which this module depends. Each entry is 3880b57cec5SDimitry Andric /// a module ID. 3890b57cec5SDimitry Andric SmallVector<unsigned, 4> Dependencies; 3900b57cec5SDimitry Andric ASTFileSignature Signature; 3910b57cec5SDimitry Andric }; 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric struct ImportedModuleFileInfo { 3940b57cec5SDimitry Andric off_t StoredSize; 3950b57cec5SDimitry Andric time_t StoredModTime; 3960b57cec5SDimitry Andric ASTFileSignature StoredSignature; 3970b57cec5SDimitry Andric ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig) 3980b57cec5SDimitry Andric : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {} 3990b57cec5SDimitry Andric }; 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andric /// Builder that generates the global module index file. 4020b57cec5SDimitry Andric class GlobalModuleIndexBuilder { 4030b57cec5SDimitry Andric FileManager &FileMgr; 4040b57cec5SDimitry Andric const PCHContainerReader &PCHContainerRdr; 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric /// Mapping from files to module file information. 4075f757f3fSDimitry Andric using ModuleFilesMap = llvm::MapVector<FileEntryRef, ModuleFileInfo>; 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric /// Information about each of the known module files. 4100b57cec5SDimitry Andric ModuleFilesMap ModuleFiles; 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric /// Mapping from the imported module file to the imported 4130b57cec5SDimitry Andric /// information. 4145f757f3fSDimitry Andric using ImportedModuleFilesMap = 4155f757f3fSDimitry Andric std::multimap<FileEntryRef, ImportedModuleFileInfo>; 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric /// Information about each importing of a module file. 4180b57cec5SDimitry Andric ImportedModuleFilesMap ImportedModuleFiles; 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric /// Mapping from identifiers to the list of module file IDs that 4210b57cec5SDimitry Andric /// consider this identifier to be interesting. 4220b57cec5SDimitry Andric typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap; 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric /// A mapping from all interesting identifiers to the set of module 4250b57cec5SDimitry Andric /// files in which those identifiers are considered interesting. 4260b57cec5SDimitry Andric InterestingIdentifierMap InterestingIdentifiers; 4270b57cec5SDimitry Andric 4280b57cec5SDimitry Andric /// Write the block-info block for the global module index file. 4290b57cec5SDimitry Andric void emitBlockInfoBlock(llvm::BitstreamWriter &Stream); 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric /// Retrieve the module file information for the given file. 4325f757f3fSDimitry Andric ModuleFileInfo &getModuleFileInfo(FileEntryRef File) { 4335f757f3fSDimitry Andric auto Known = ModuleFiles.find(File); 4340b57cec5SDimitry Andric if (Known != ModuleFiles.end()) 4350b57cec5SDimitry Andric return Known->second; 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric unsigned NewID = ModuleFiles.size(); 4380b57cec5SDimitry Andric ModuleFileInfo &Info = ModuleFiles[File]; 4390b57cec5SDimitry Andric Info.ID = NewID; 4400b57cec5SDimitry Andric return Info; 4410b57cec5SDimitry Andric } 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric public: 4440b57cec5SDimitry Andric explicit GlobalModuleIndexBuilder( 4450b57cec5SDimitry Andric FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr) 4460b57cec5SDimitry Andric : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr) {} 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric /// Load the contents of the given module file into the builder. 4495f757f3fSDimitry Andric llvm::Error loadModuleFile(FileEntryRef File); 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric /// Write the index to the given bitstream. 4520b57cec5SDimitry Andric /// \returns true if an error occurred, false otherwise. 4530b57cec5SDimitry Andric bool writeIndex(llvm::BitstreamWriter &Stream); 4540b57cec5SDimitry Andric }; 4550b57cec5SDimitry Andric } 4560b57cec5SDimitry Andric 4570b57cec5SDimitry Andric static void emitBlockID(unsigned ID, const char *Name, 4580b57cec5SDimitry Andric llvm::BitstreamWriter &Stream, 4590b57cec5SDimitry Andric SmallVectorImpl<uint64_t> &Record) { 4600b57cec5SDimitry Andric Record.clear(); 4610b57cec5SDimitry Andric Record.push_back(ID); 4620b57cec5SDimitry Andric Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric // Emit the block name if present. 4650b57cec5SDimitry Andric if (!Name || Name[0] == 0) return; 4660b57cec5SDimitry Andric Record.clear(); 4670b57cec5SDimitry Andric while (*Name) 4680b57cec5SDimitry Andric Record.push_back(*Name++); 4690b57cec5SDimitry Andric Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric static void emitRecordID(unsigned ID, const char *Name, 4730b57cec5SDimitry Andric llvm::BitstreamWriter &Stream, 4740b57cec5SDimitry Andric SmallVectorImpl<uint64_t> &Record) { 4750b57cec5SDimitry Andric Record.clear(); 4760b57cec5SDimitry Andric Record.push_back(ID); 4770b57cec5SDimitry Andric while (*Name) 4780b57cec5SDimitry Andric Record.push_back(*Name++); 4790b57cec5SDimitry Andric Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric void 4830b57cec5SDimitry Andric GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) { 4840b57cec5SDimitry Andric SmallVector<uint64_t, 64> Record; 4850b57cec5SDimitry Andric Stream.EnterBlockInfoBlock(); 4860b57cec5SDimitry Andric 4870b57cec5SDimitry Andric #define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record) 4880b57cec5SDimitry Andric #define RECORD(X) emitRecordID(X, #X, Stream, Record) 4890b57cec5SDimitry Andric BLOCK(GLOBAL_INDEX_BLOCK); 4900b57cec5SDimitry Andric RECORD(INDEX_METADATA); 4910b57cec5SDimitry Andric RECORD(MODULE); 4920b57cec5SDimitry Andric RECORD(IDENTIFIER_INDEX); 4930b57cec5SDimitry Andric #undef RECORD 4940b57cec5SDimitry Andric #undef BLOCK 4950b57cec5SDimitry Andric 4960b57cec5SDimitry Andric Stream.ExitBlock(); 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric namespace { 5000b57cec5SDimitry Andric class InterestingASTIdentifierLookupTrait 5010b57cec5SDimitry Andric : public serialization::reader::ASTIdentifierLookupTraitBase { 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric public: 5040b57cec5SDimitry Andric /// The identifier and whether it is "interesting". 5050b57cec5SDimitry Andric typedef std::pair<StringRef, bool> data_type; 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric data_type ReadData(const internal_key_type& k, 5080b57cec5SDimitry Andric const unsigned char* d, 5090b57cec5SDimitry Andric unsigned DataLen) { 5100b57cec5SDimitry Andric // The first bit indicates whether this identifier is interesting. 5110b57cec5SDimitry Andric // That's all we care about. 5120b57cec5SDimitry Andric using namespace llvm::support; 513*0fca6ea1SDimitry Andric IdentifierID RawID = 514*0fca6ea1SDimitry Andric endian::readNext<IdentifierID, llvm::endianness::little>(d); 5150b57cec5SDimitry Andric bool IsInteresting = RawID & 0x01; 5160b57cec5SDimitry Andric return std::make_pair(k, IsInteresting); 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric }; 5190b57cec5SDimitry Andric } 5200b57cec5SDimitry Andric 5215f757f3fSDimitry Andric llvm::Error GlobalModuleIndexBuilder::loadModuleFile(FileEntryRef File) { 5220b57cec5SDimitry Andric // Open the module file. 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric auto Buffer = FileMgr.getBufferForFile(File, /*isVolatile=*/true); 5250b57cec5SDimitry Andric if (!Buffer) 5260b57cec5SDimitry Andric return llvm::createStringError(Buffer.getError(), 5270b57cec5SDimitry Andric "failed getting buffer for module file"); 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric // Initialize the input stream 5300b57cec5SDimitry Andric llvm::BitstreamCursor InStream(PCHContainerRdr.ExtractPCH(**Buffer)); 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric // Sniff for the signature. 5330b57cec5SDimitry Andric for (unsigned char C : {'C', 'P', 'C', 'H'}) 5340b57cec5SDimitry Andric if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = InStream.Read(8)) { 5350b57cec5SDimitry Andric if (Res.get() != C) 5360b57cec5SDimitry Andric return llvm::createStringError(std::errc::illegal_byte_sequence, 5370b57cec5SDimitry Andric "expected signature CPCH"); 5380b57cec5SDimitry Andric } else 5390b57cec5SDimitry Andric return Res.takeError(); 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric // Record this module file and assign it a unique ID (if it doesn't have 5420b57cec5SDimitry Andric // one already). 5430b57cec5SDimitry Andric unsigned ID = getModuleFileInfo(File).ID; 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric // Search for the blocks and records we care about. 5460b57cec5SDimitry Andric enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other; 5470b57cec5SDimitry Andric bool Done = false; 5480b57cec5SDimitry Andric while (!Done) { 5490b57cec5SDimitry Andric Expected<llvm::BitstreamEntry> MaybeEntry = InStream.advance(); 5500b57cec5SDimitry Andric if (!MaybeEntry) 5510b57cec5SDimitry Andric return MaybeEntry.takeError(); 5520b57cec5SDimitry Andric llvm::BitstreamEntry Entry = MaybeEntry.get(); 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric switch (Entry.Kind) { 5550b57cec5SDimitry Andric case llvm::BitstreamEntry::Error: 5560b57cec5SDimitry Andric Done = true; 5570b57cec5SDimitry Andric continue; 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric case llvm::BitstreamEntry::Record: 5600b57cec5SDimitry Andric // In the 'other' state, just skip the record. We don't care. 5610b57cec5SDimitry Andric if (State == Other) { 5620b57cec5SDimitry Andric if (llvm::Expected<unsigned> Skipped = InStream.skipRecord(Entry.ID)) 5630b57cec5SDimitry Andric continue; 5640b57cec5SDimitry Andric else 5650b57cec5SDimitry Andric return Skipped.takeError(); 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric // Handle potentially-interesting records below. 5690b57cec5SDimitry Andric break; 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric case llvm::BitstreamEntry::SubBlock: 5720b57cec5SDimitry Andric if (Entry.ID == CONTROL_BLOCK_ID) { 5730b57cec5SDimitry Andric if (llvm::Error Err = InStream.EnterSubBlock(CONTROL_BLOCK_ID)) 5740b57cec5SDimitry Andric return Err; 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric // Found the control block. 5770b57cec5SDimitry Andric State = ControlBlock; 5780b57cec5SDimitry Andric continue; 5790b57cec5SDimitry Andric } 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric if (Entry.ID == AST_BLOCK_ID) { 5820b57cec5SDimitry Andric if (llvm::Error Err = InStream.EnterSubBlock(AST_BLOCK_ID)) 5830b57cec5SDimitry Andric return Err; 5840b57cec5SDimitry Andric 5850b57cec5SDimitry Andric // Found the AST block. 5860b57cec5SDimitry Andric State = ASTBlock; 5870b57cec5SDimitry Andric continue; 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) { 5910b57cec5SDimitry Andric if (llvm::Error Err = InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID)) 5920b57cec5SDimitry Andric return Err; 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric // Found the Diagnostic Options block. 5950b57cec5SDimitry Andric State = DiagnosticOptionsBlock; 5960b57cec5SDimitry Andric continue; 5970b57cec5SDimitry Andric } 5980b57cec5SDimitry Andric 5990b57cec5SDimitry Andric if (llvm::Error Err = InStream.SkipBlock()) 6000b57cec5SDimitry Andric return Err; 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric continue; 6030b57cec5SDimitry Andric 6040b57cec5SDimitry Andric case llvm::BitstreamEntry::EndBlock: 6050b57cec5SDimitry Andric State = Other; 6060b57cec5SDimitry Andric continue; 6070b57cec5SDimitry Andric } 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric // Read the given record. 6100b57cec5SDimitry Andric SmallVector<uint64_t, 64> Record; 6110b57cec5SDimitry Andric StringRef Blob; 6120b57cec5SDimitry Andric Expected<unsigned> MaybeCode = InStream.readRecord(Entry.ID, Record, &Blob); 6130b57cec5SDimitry Andric if (!MaybeCode) 6140b57cec5SDimitry Andric return MaybeCode.takeError(); 6150b57cec5SDimitry Andric unsigned Code = MaybeCode.get(); 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric // Handle module dependencies. 6180b57cec5SDimitry Andric if (State == ControlBlock && Code == IMPORTS) { 6190b57cec5SDimitry Andric // Load each of the imported PCH files. 6200b57cec5SDimitry Andric unsigned Idx = 0, N = Record.size(); 6210b57cec5SDimitry Andric while (Idx < N) { 6220b57cec5SDimitry Andric // Read information about the AST file. 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric // Skip the imported kind 6250b57cec5SDimitry Andric ++Idx; 6260b57cec5SDimitry Andric 62706c3fb27SDimitry Andric // Skip if it is standard C++ module 62806c3fb27SDimitry Andric ++Idx; 62906c3fb27SDimitry Andric 6300b57cec5SDimitry Andric // Skip the import location 6310b57cec5SDimitry Andric ++Idx; 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric // Load stored size/modification time. 6340b57cec5SDimitry Andric off_t StoredSize = (off_t)Record[Idx++]; 6350b57cec5SDimitry Andric time_t StoredModTime = (time_t)Record[Idx++]; 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric // Skip the stored signature. 6380b57cec5SDimitry Andric // FIXME: we could read the signature out of the import and validate it. 6395ffd83dbSDimitry Andric auto FirstSignatureByte = Record.begin() + Idx; 6405ffd83dbSDimitry Andric ASTFileSignature StoredSignature = ASTFileSignature::create( 6415ffd83dbSDimitry Andric FirstSignatureByte, FirstSignatureByte + ASTFileSignature::size); 6425ffd83dbSDimitry Andric Idx += ASTFileSignature::size; 6430b57cec5SDimitry Andric 6440b57cec5SDimitry Andric // Skip the module name (currently this is only used for prebuilt 6450b57cec5SDimitry Andric // modules while here we are only dealing with cached). 6460b57cec5SDimitry Andric Idx += Record[Idx] + 1; 6470b57cec5SDimitry Andric 6480b57cec5SDimitry Andric // Retrieve the imported file name. 6490b57cec5SDimitry Andric unsigned Length = Record[Idx++]; 6500b57cec5SDimitry Andric SmallString<128> ImportedFile(Record.begin() + Idx, 6510b57cec5SDimitry Andric Record.begin() + Idx + Length); 6520b57cec5SDimitry Andric Idx += Length; 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric // Find the imported module file. 6555f757f3fSDimitry Andric auto DependsOnFile = 6565f757f3fSDimitry Andric FileMgr.getOptionalFileRef(ImportedFile, /*OpenFile=*/false, 6570b57cec5SDimitry Andric /*CacheFailure=*/false); 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric if (!DependsOnFile) 6600b57cec5SDimitry Andric return llvm::createStringError(std::errc::bad_file_descriptor, 6610b57cec5SDimitry Andric "imported file \"%s\" not found", 6620b57cec5SDimitry Andric ImportedFile.c_str()); 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric // Save the information in ImportedModuleFileInfo so we can verify after 6650b57cec5SDimitry Andric // loading all pcms. 6660b57cec5SDimitry Andric ImportedModuleFiles.insert(std::make_pair( 667a7dea167SDimitry Andric *DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime, 6680b57cec5SDimitry Andric StoredSignature))); 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric // Record the dependency. 671a7dea167SDimitry Andric unsigned DependsOnID = getModuleFileInfo(*DependsOnFile).ID; 6720b57cec5SDimitry Andric getModuleFileInfo(File).Dependencies.push_back(DependsOnID); 6730b57cec5SDimitry Andric } 6740b57cec5SDimitry Andric 6750b57cec5SDimitry Andric continue; 6760b57cec5SDimitry Andric } 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric // Handle the identifier table 6790b57cec5SDimitry Andric if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) { 6800b57cec5SDimitry Andric typedef llvm::OnDiskIterableChainedHashTable< 6810b57cec5SDimitry Andric InterestingASTIdentifierLookupTrait> InterestingIdentifierTable; 6820b57cec5SDimitry Andric std::unique_ptr<InterestingIdentifierTable> Table( 6830b57cec5SDimitry Andric InterestingIdentifierTable::Create( 6840b57cec5SDimitry Andric (const unsigned char *)Blob.data() + Record[0], 6850b57cec5SDimitry Andric (const unsigned char *)Blob.data() + sizeof(uint32_t), 6860b57cec5SDimitry Andric (const unsigned char *)Blob.data())); 6870b57cec5SDimitry Andric for (InterestingIdentifierTable::data_iterator D = Table->data_begin(), 6880b57cec5SDimitry Andric DEnd = Table->data_end(); 6890b57cec5SDimitry Andric D != DEnd; ++D) { 6900b57cec5SDimitry Andric std::pair<StringRef, bool> Ident = *D; 6910b57cec5SDimitry Andric if (Ident.second) 6920b57cec5SDimitry Andric InterestingIdentifiers[Ident.first].push_back(ID); 6930b57cec5SDimitry Andric else 6940b57cec5SDimitry Andric (void)InterestingIdentifiers[Ident.first]; 6950b57cec5SDimitry Andric } 6960b57cec5SDimitry Andric } 6970b57cec5SDimitry Andric 6980b57cec5SDimitry Andric // Get Signature. 6995f757f3fSDimitry Andric if (State == DiagnosticOptionsBlock && Code == SIGNATURE) { 7005f757f3fSDimitry Andric auto Signature = ASTFileSignature::create(Blob.begin(), Blob.end()); 7015f757f3fSDimitry Andric assert(Signature != ASTFileSignature::createDummy() && 7025f757f3fSDimitry Andric "Dummy AST file signature not backpatched in ASTWriter."); 7035f757f3fSDimitry Andric getModuleFileInfo(File).Signature = Signature; 7045f757f3fSDimitry Andric } 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric // We don't care about this record. 7070b57cec5SDimitry Andric } 7080b57cec5SDimitry Andric 7090b57cec5SDimitry Andric return llvm::Error::success(); 7100b57cec5SDimitry Andric } 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric namespace { 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric /// Trait used to generate the identifier index as an on-disk hash 7150b57cec5SDimitry Andric /// table. 7160b57cec5SDimitry Andric class IdentifierIndexWriterTrait { 7170b57cec5SDimitry Andric public: 7180b57cec5SDimitry Andric typedef StringRef key_type; 7190b57cec5SDimitry Andric typedef StringRef key_type_ref; 7200b57cec5SDimitry Andric typedef SmallVector<unsigned, 2> data_type; 7210b57cec5SDimitry Andric typedef const SmallVector<unsigned, 2> &data_type_ref; 7220b57cec5SDimitry Andric typedef unsigned hash_value_type; 7230b57cec5SDimitry Andric typedef unsigned offset_type; 7240b57cec5SDimitry Andric 7250b57cec5SDimitry Andric static hash_value_type ComputeHash(key_type_ref Key) { 7260b57cec5SDimitry Andric return llvm::djbHash(Key); 7270b57cec5SDimitry Andric } 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric std::pair<unsigned,unsigned> 7300b57cec5SDimitry Andric EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) { 7310b57cec5SDimitry Andric using namespace llvm::support; 7325f757f3fSDimitry Andric endian::Writer LE(Out, llvm::endianness::little); 7330b57cec5SDimitry Andric unsigned KeyLen = Key.size(); 7340b57cec5SDimitry Andric unsigned DataLen = Data.size() * 4; 7350b57cec5SDimitry Andric LE.write<uint16_t>(KeyLen); 7360b57cec5SDimitry Andric LE.write<uint16_t>(DataLen); 7370b57cec5SDimitry Andric return std::make_pair(KeyLen, DataLen); 7380b57cec5SDimitry Andric } 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) { 7410b57cec5SDimitry Andric Out.write(Key.data(), KeyLen); 7420b57cec5SDimitry Andric } 7430b57cec5SDimitry Andric 7440b57cec5SDimitry Andric void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data, 7450b57cec5SDimitry Andric unsigned DataLen) { 7460b57cec5SDimitry Andric using namespace llvm::support; 7470b57cec5SDimitry Andric for (unsigned I = 0, N = Data.size(); I != N; ++I) 7485f757f3fSDimitry Andric endian::write<uint32_t>(Out, Data[I], llvm::endianness::little); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric }; 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric } 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { 7550b57cec5SDimitry Andric for (auto MapEntry : ImportedModuleFiles) { 7565f757f3fSDimitry Andric auto File = MapEntry.first; 7570b57cec5SDimitry Andric ImportedModuleFileInfo &Info = MapEntry.second; 7580b57cec5SDimitry Andric if (getModuleFileInfo(File).Signature) { 7590b57cec5SDimitry Andric if (getModuleFileInfo(File).Signature != Info.StoredSignature) 7600b57cec5SDimitry Andric // Verify Signature. 7610b57cec5SDimitry Andric return true; 7625f757f3fSDimitry Andric } else if (Info.StoredSize != File.getSize() || 7635f757f3fSDimitry Andric Info.StoredModTime != File.getModificationTime()) 7640b57cec5SDimitry Andric // Verify Size and ModTime. 7650b57cec5SDimitry Andric return true; 7660b57cec5SDimitry Andric } 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric using namespace llvm; 769480093f4SDimitry Andric llvm::TimeTraceScope TimeScope("Module WriteIndex"); 7700b57cec5SDimitry Andric 7710b57cec5SDimitry Andric // Emit the file header. 7720b57cec5SDimitry Andric Stream.Emit((unsigned)'B', 8); 7730b57cec5SDimitry Andric Stream.Emit((unsigned)'C', 8); 7740b57cec5SDimitry Andric Stream.Emit((unsigned)'G', 8); 7750b57cec5SDimitry Andric Stream.Emit((unsigned)'I', 8); 7760b57cec5SDimitry Andric 7770b57cec5SDimitry Andric // Write the block-info block, which describes the records in this bitcode 7780b57cec5SDimitry Andric // file. 7790b57cec5SDimitry Andric emitBlockInfoBlock(Stream); 7800b57cec5SDimitry Andric 7810b57cec5SDimitry Andric Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3); 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric // Write the metadata. 7840b57cec5SDimitry Andric SmallVector<uint64_t, 2> Record; 7850b57cec5SDimitry Andric Record.push_back(CurrentVersion); 7860b57cec5SDimitry Andric Stream.EmitRecord(INDEX_METADATA, Record); 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric // Write the set of known module files. 7890b57cec5SDimitry Andric for (ModuleFilesMap::iterator M = ModuleFiles.begin(), 7900b57cec5SDimitry Andric MEnd = ModuleFiles.end(); 7910b57cec5SDimitry Andric M != MEnd; ++M) { 7920b57cec5SDimitry Andric Record.clear(); 7930b57cec5SDimitry Andric Record.push_back(M->second.ID); 7945f757f3fSDimitry Andric Record.push_back(M->first.getSize()); 7955f757f3fSDimitry Andric Record.push_back(M->first.getModificationTime()); 7960b57cec5SDimitry Andric 7970b57cec5SDimitry Andric // File name 7985f757f3fSDimitry Andric StringRef Name(M->first.getName()); 7990b57cec5SDimitry Andric Record.push_back(Name.size()); 8000b57cec5SDimitry Andric Record.append(Name.begin(), Name.end()); 8010b57cec5SDimitry Andric 8020b57cec5SDimitry Andric // Dependencies 8030b57cec5SDimitry Andric Record.push_back(M->second.Dependencies.size()); 8040b57cec5SDimitry Andric Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end()); 8050b57cec5SDimitry Andric Stream.EmitRecord(MODULE, Record); 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric // Write the identifier -> module file mapping. 8090b57cec5SDimitry Andric { 8100b57cec5SDimitry Andric llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator; 8110b57cec5SDimitry Andric IdentifierIndexWriterTrait Trait; 8120b57cec5SDimitry Andric 8130b57cec5SDimitry Andric // Populate the hash table. 8140b57cec5SDimitry Andric for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(), 8150b57cec5SDimitry Andric IEnd = InterestingIdentifiers.end(); 8160b57cec5SDimitry Andric I != IEnd; ++I) { 8170b57cec5SDimitry Andric Generator.insert(I->first(), I->second, Trait); 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric // Create the on-disk hash table in a buffer. 8210b57cec5SDimitry Andric SmallString<4096> IdentifierTable; 8220b57cec5SDimitry Andric uint32_t BucketOffset; 8230b57cec5SDimitry Andric { 8240b57cec5SDimitry Andric using namespace llvm::support; 8250b57cec5SDimitry Andric llvm::raw_svector_ostream Out(IdentifierTable); 8260b57cec5SDimitry Andric // Make sure that no bucket is at offset 0 8275f757f3fSDimitry Andric endian::write<uint32_t>(Out, 0, llvm::endianness::little); 8280b57cec5SDimitry Andric BucketOffset = Generator.Emit(Out, Trait); 8290b57cec5SDimitry Andric } 8300b57cec5SDimitry Andric 8310b57cec5SDimitry Andric // Create a blob abbreviation 8320b57cec5SDimitry Andric auto Abbrev = std::make_shared<BitCodeAbbrev>(); 8330b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX)); 8340b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); 8350b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); 8360b57cec5SDimitry Andric unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); 8370b57cec5SDimitry Andric 8380b57cec5SDimitry Andric // Write the identifier table 8390b57cec5SDimitry Andric uint64_t Record[] = {IDENTIFIER_INDEX, BucketOffset}; 8400b57cec5SDimitry Andric Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable); 8410b57cec5SDimitry Andric } 8420b57cec5SDimitry Andric 8430b57cec5SDimitry Andric Stream.ExitBlock(); 8440b57cec5SDimitry Andric return false; 8450b57cec5SDimitry Andric } 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric llvm::Error 8480b57cec5SDimitry Andric GlobalModuleIndex::writeIndex(FileManager &FileMgr, 8490b57cec5SDimitry Andric const PCHContainerReader &PCHContainerRdr, 8500b57cec5SDimitry Andric StringRef Path) { 8510b57cec5SDimitry Andric llvm::SmallString<128> IndexPath; 8520b57cec5SDimitry Andric IndexPath += Path; 8530b57cec5SDimitry Andric llvm::sys::path::append(IndexPath, IndexFileName); 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric // Coordinate building the global index file with other processes that might 8560b57cec5SDimitry Andric // try to do the same. 8570b57cec5SDimitry Andric llvm::LockFileManager Locked(IndexPath); 8580b57cec5SDimitry Andric switch (Locked) { 8590b57cec5SDimitry Andric case llvm::LockFileManager::LFS_Error: 8600b57cec5SDimitry Andric return llvm::createStringError(std::errc::io_error, "LFS error"); 8610b57cec5SDimitry Andric 8620b57cec5SDimitry Andric case llvm::LockFileManager::LFS_Owned: 8630b57cec5SDimitry Andric // We're responsible for building the index ourselves. Do so below. 8640b57cec5SDimitry Andric break; 8650b57cec5SDimitry Andric 8660b57cec5SDimitry Andric case llvm::LockFileManager::LFS_Shared: 8670b57cec5SDimitry Andric // Someone else is responsible for building the index. We don't care 8680b57cec5SDimitry Andric // when they finish, so we're done. 8690b57cec5SDimitry Andric return llvm::createStringError(std::errc::device_or_resource_busy, 8700b57cec5SDimitry Andric "someone else is building the index"); 8710b57cec5SDimitry Andric } 8720b57cec5SDimitry Andric 8730b57cec5SDimitry Andric // The module index builder. 8740b57cec5SDimitry Andric GlobalModuleIndexBuilder Builder(FileMgr, PCHContainerRdr); 8750b57cec5SDimitry Andric 8760b57cec5SDimitry Andric // Load each of the module files. 8770b57cec5SDimitry Andric std::error_code EC; 8780b57cec5SDimitry Andric for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd; 8790b57cec5SDimitry Andric D != DEnd && !EC; 8800b57cec5SDimitry Andric D.increment(EC)) { 8810b57cec5SDimitry Andric // If this isn't a module file, we don't care. 8820b57cec5SDimitry Andric if (llvm::sys::path::extension(D->path()) != ".pcm") { 8830b57cec5SDimitry Andric // ... unless it's a .pcm.lock file, which indicates that someone is 8840b57cec5SDimitry Andric // in the process of rebuilding a module. They'll rebuild the index 8850b57cec5SDimitry Andric // at the end of that translation unit, so we don't have to. 8860b57cec5SDimitry Andric if (llvm::sys::path::extension(D->path()) == ".pcm.lock") 8870b57cec5SDimitry Andric return llvm::createStringError(std::errc::device_or_resource_busy, 8880b57cec5SDimitry Andric "someone else is building the index"); 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric continue; 8910b57cec5SDimitry Andric } 8920b57cec5SDimitry Andric 8930b57cec5SDimitry Andric // If we can't find the module file, skip it. 8945f757f3fSDimitry Andric auto ModuleFile = FileMgr.getOptionalFileRef(D->path()); 8950b57cec5SDimitry Andric if (!ModuleFile) 8960b57cec5SDimitry Andric continue; 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric // Load this module file. 899a7dea167SDimitry Andric if (llvm::Error Err = Builder.loadModuleFile(*ModuleFile)) 9000b57cec5SDimitry Andric return Err; 9010b57cec5SDimitry Andric } 9020b57cec5SDimitry Andric 9030b57cec5SDimitry Andric // The output buffer, into which the global index will be written. 904e8d8bef9SDimitry Andric SmallString<16> OutputBuffer; 9050b57cec5SDimitry Andric { 9060b57cec5SDimitry Andric llvm::BitstreamWriter OutputStream(OutputBuffer); 9070b57cec5SDimitry Andric if (Builder.writeIndex(OutputStream)) 9080b57cec5SDimitry Andric return llvm::createStringError(std::errc::io_error, 9090b57cec5SDimitry Andric "failed writing index"); 9100b57cec5SDimitry Andric } 9110b57cec5SDimitry Andric 91206c3fb27SDimitry Andric return llvm::writeToOutput(IndexPath, [&OutputBuffer](llvm::raw_ostream &OS) { 91306c3fb27SDimitry Andric OS << OutputBuffer; 91406c3fb27SDimitry Andric return llvm::Error::success(); 91506c3fb27SDimitry Andric }); 9160b57cec5SDimitry Andric } 9170b57cec5SDimitry Andric 9180b57cec5SDimitry Andric namespace { 9190b57cec5SDimitry Andric class GlobalIndexIdentifierIterator : public IdentifierIterator { 9200b57cec5SDimitry Andric /// The current position within the identifier lookup table. 9210b57cec5SDimitry Andric IdentifierIndexTable::key_iterator Current; 9220b57cec5SDimitry Andric 9230b57cec5SDimitry Andric /// The end position within the identifier lookup table. 9240b57cec5SDimitry Andric IdentifierIndexTable::key_iterator End; 9250b57cec5SDimitry Andric 9260b57cec5SDimitry Andric public: 9270b57cec5SDimitry Andric explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) { 9280b57cec5SDimitry Andric Current = Idx.key_begin(); 9290b57cec5SDimitry Andric End = Idx.key_end(); 9300b57cec5SDimitry Andric } 9310b57cec5SDimitry Andric 9320b57cec5SDimitry Andric StringRef Next() override { 9330b57cec5SDimitry Andric if (Current == End) 9340b57cec5SDimitry Andric return StringRef(); 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric StringRef Result = *Current; 9370b57cec5SDimitry Andric ++Current; 9380b57cec5SDimitry Andric return Result; 9390b57cec5SDimitry Andric } 9400b57cec5SDimitry Andric }; 9410b57cec5SDimitry Andric } 9420b57cec5SDimitry Andric 9430b57cec5SDimitry Andric IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const { 9440b57cec5SDimitry Andric IdentifierIndexTable &Table = 9450b57cec5SDimitry Andric *static_cast<IdentifierIndexTable *>(IdentifierIndex); 9460b57cec5SDimitry Andric return new GlobalIndexIdentifierIterator(Table); 9470b57cec5SDimitry Andric } 948