xref: /src/contrib/llvm-project/clang/lib/Serialization/GlobalModuleIndex.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1809500fcSDimitry Andric //===--- GlobalModuleIndex.cpp - Global Module Index ------------*- C++ -*-===//
2809500fcSDimitry Andric //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6809500fcSDimitry Andric //
7809500fcSDimitry Andric //===----------------------------------------------------------------------===//
8809500fcSDimitry Andric //
9809500fcSDimitry Andric // This file implements the GlobalModuleIndex class.
10809500fcSDimitry Andric //
11809500fcSDimitry Andric //===----------------------------------------------------------------------===//
12809500fcSDimitry Andric 
13706b4fc4SDimitry Andric #include "clang/Serialization/GlobalModuleIndex.h"
14809500fcSDimitry Andric #include "ASTReaderInternals.h"
15809500fcSDimitry Andric #include "clang/Basic/FileManager.h"
16809500fcSDimitry Andric #include "clang/Serialization/ASTBitCodes.h"
17706b4fc4SDimitry Andric #include "clang/Serialization/ModuleFile.h"
18676fbe81SDimitry Andric #include "clang/Serialization/PCHContainerOperations.h"
19809500fcSDimitry Andric #include "llvm/ADT/DenseMap.h"
20809500fcSDimitry Andric #include "llvm/ADT/MapVector.h"
21809500fcSDimitry Andric #include "llvm/ADT/SmallString.h"
22519fc96cSDimitry Andric #include "llvm/ADT/StringRef.h"
2322989816SDimitry Andric #include "llvm/Bitstream/BitstreamReader.h"
2422989816SDimitry Andric #include "llvm/Bitstream/BitstreamWriter.h"
2548675466SDimitry Andric #include "llvm/Support/DJB.h"
26809500fcSDimitry Andric #include "llvm/Support/FileSystem.h"
27809500fcSDimitry Andric #include "llvm/Support/LockFileManager.h"
28809500fcSDimitry Andric #include "llvm/Support/MemoryBuffer.h"
299f4dbff6SDimitry Andric #include "llvm/Support/OnDiskHashTable.h"
30bfef3995SDimitry Andric #include "llvm/Support/Path.h"
3122989816SDimitry Andric #include "llvm/Support/TimeProfiler.h"
327fa27ce4SDimitry Andric #include "llvm/Support/raw_ostream.h"
33809500fcSDimitry Andric #include <cstdio>
34809500fcSDimitry Andric using namespace clang;
35809500fcSDimitry Andric using namespace serialization;
36809500fcSDimitry Andric 
37809500fcSDimitry Andric //----------------------------------------------------------------------------//
38809500fcSDimitry Andric // Shared constants
39809500fcSDimitry Andric //----------------------------------------------------------------------------//
40809500fcSDimitry Andric namespace {
41809500fcSDimitry Andric   enum {
4248675466SDimitry Andric     /// The block containing the index.
43809500fcSDimitry Andric     GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID
44809500fcSDimitry Andric   };
45809500fcSDimitry Andric 
4648675466SDimitry Andric   /// Describes the record types in the index.
47809500fcSDimitry Andric   enum IndexRecordTypes {
4848675466SDimitry Andric     /// Contains version information and potentially other metadata,
49809500fcSDimitry Andric     /// used to determine if we can read this global index file.
50809500fcSDimitry Andric     INDEX_METADATA,
5148675466SDimitry Andric     /// Describes a module, including its file name and dependencies.
52809500fcSDimitry Andric     MODULE,
5348675466SDimitry Andric     /// The index for identifiers.
54809500fcSDimitry Andric     IDENTIFIER_INDEX
55809500fcSDimitry Andric   };
56809500fcSDimitry Andric }
57809500fcSDimitry Andric 
5848675466SDimitry Andric /// The name of the global index file.
59809500fcSDimitry Andric static const char * const IndexFileName = "modules.idx";
60809500fcSDimitry Andric 
6148675466SDimitry Andric /// The global index file version.
62809500fcSDimitry Andric static const unsigned CurrentVersion = 1;
63809500fcSDimitry Andric 
64809500fcSDimitry Andric //----------------------------------------------------------------------------//
65809500fcSDimitry Andric // Global module index reader.
66809500fcSDimitry Andric //----------------------------------------------------------------------------//
67809500fcSDimitry Andric 
68809500fcSDimitry Andric namespace {
69809500fcSDimitry Andric 
7048675466SDimitry Andric /// Trait used to read the identifier index from the on-disk hash
71809500fcSDimitry Andric /// table.
72809500fcSDimitry Andric class IdentifierIndexReaderTrait {
73809500fcSDimitry Andric public:
74809500fcSDimitry Andric   typedef StringRef external_key_type;
75809500fcSDimitry Andric   typedef StringRef internal_key_type;
76809500fcSDimitry Andric   typedef SmallVector<unsigned, 2> data_type;
779f4dbff6SDimitry Andric   typedef unsigned hash_value_type;
789f4dbff6SDimitry Andric   typedef unsigned offset_type;
79809500fcSDimitry Andric 
EqualKey(const internal_key_type & a,const internal_key_type & b)80809500fcSDimitry Andric   static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
81809500fcSDimitry Andric     return a == b;
82809500fcSDimitry Andric   }
83809500fcSDimitry Andric 
ComputeHash(const internal_key_type & a)849f4dbff6SDimitry Andric   static hash_value_type ComputeHash(const internal_key_type& a) {
8548675466SDimitry Andric     return llvm::djbHash(a);
86809500fcSDimitry Andric   }
87809500fcSDimitry Andric 
88809500fcSDimitry Andric   static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char * & d)89809500fcSDimitry Andric   ReadKeyDataLength(const unsigned char*& d) {
909f4dbff6SDimitry Andric     using namespace llvm::support;
91ac9a064cSDimitry Andric     unsigned KeyLen = endian::readNext<uint16_t, llvm::endianness::little>(d);
92ac9a064cSDimitry Andric     unsigned DataLen = endian::readNext<uint16_t, llvm::endianness::little>(d);
93809500fcSDimitry Andric     return std::make_pair(KeyLen, DataLen);
94809500fcSDimitry Andric   }
95809500fcSDimitry Andric 
96809500fcSDimitry Andric   static const internal_key_type&
GetInternalKey(const external_key_type & x)97809500fcSDimitry Andric   GetInternalKey(const external_key_type& x) { return x; }
98809500fcSDimitry Andric 
99809500fcSDimitry Andric   static const external_key_type&
GetExternalKey(const internal_key_type & x)100809500fcSDimitry Andric   GetExternalKey(const internal_key_type& x) { return x; }
101809500fcSDimitry Andric 
ReadKey(const unsigned char * d,unsigned n)102809500fcSDimitry Andric   static internal_key_type ReadKey(const unsigned char* d, unsigned n) {
103809500fcSDimitry Andric     return StringRef((const char *)d, n);
104809500fcSDimitry Andric   }
105809500fcSDimitry Andric 
ReadData(const internal_key_type & k,const unsigned char * d,unsigned DataLen)106809500fcSDimitry Andric   static data_type ReadData(const internal_key_type& k,
107809500fcSDimitry Andric                             const unsigned char* d,
108809500fcSDimitry Andric                             unsigned DataLen) {
1099f4dbff6SDimitry Andric     using namespace llvm::support;
110809500fcSDimitry Andric 
111809500fcSDimitry Andric     data_type Result;
112809500fcSDimitry Andric     while (DataLen > 0) {
113ac9a064cSDimitry Andric       unsigned ID = endian::readNext<uint32_t, llvm::endianness::little>(d);
114809500fcSDimitry Andric       Result.push_back(ID);
115809500fcSDimitry Andric       DataLen -= 4;
116809500fcSDimitry Andric     }
117809500fcSDimitry Andric 
118809500fcSDimitry Andric     return Result;
119809500fcSDimitry Andric   }
120809500fcSDimitry Andric };
121809500fcSDimitry Andric 
1229f4dbff6SDimitry Andric typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>
1239f4dbff6SDimitry Andric     IdentifierIndexTable;
124809500fcSDimitry Andric 
125809500fcSDimitry Andric }
126809500fcSDimitry Andric 
GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> IndexBuffer,llvm::BitstreamCursor Cursor)127706b4fc4SDimitry Andric GlobalModuleIndex::GlobalModuleIndex(
128706b4fc4SDimitry Andric     std::unique_ptr<llvm::MemoryBuffer> IndexBuffer,
129809500fcSDimitry Andric     llvm::BitstreamCursor Cursor)
130706b4fc4SDimitry Andric     : Buffer(std::move(IndexBuffer)), IdentifierIndex(), NumIdentifierLookups(),
13106d4ba38SDimitry Andric       NumIdentifierLookupHits() {
132706b4fc4SDimitry Andric   auto Fail = [&](llvm::Error &&Err) {
13322989816SDimitry Andric     report_fatal_error("Module index '" + Buffer->getBufferIdentifier() +
13422989816SDimitry Andric                        "' failed: " + toString(std::move(Err)));
13522989816SDimitry Andric   };
13622989816SDimitry Andric 
137706b4fc4SDimitry Andric   llvm::TimeTraceScope TimeScope("Module LoadIndex");
138809500fcSDimitry Andric   // Read the global index.
139809500fcSDimitry Andric   bool InGlobalIndexBlock = false;
140809500fcSDimitry Andric   bool Done = false;
141809500fcSDimitry Andric   while (!Done) {
14222989816SDimitry Andric     llvm::BitstreamEntry Entry;
14322989816SDimitry Andric     if (Expected<llvm::BitstreamEntry> Res = Cursor.advance())
14422989816SDimitry Andric       Entry = Res.get();
14522989816SDimitry Andric     else
14622989816SDimitry Andric       Fail(Res.takeError());
147809500fcSDimitry Andric 
148809500fcSDimitry Andric     switch (Entry.Kind) {
149809500fcSDimitry Andric     case llvm::BitstreamEntry::Error:
150809500fcSDimitry Andric       return;
151809500fcSDimitry Andric 
152809500fcSDimitry Andric     case llvm::BitstreamEntry::EndBlock:
153809500fcSDimitry Andric       if (InGlobalIndexBlock) {
154809500fcSDimitry Andric         InGlobalIndexBlock = false;
155809500fcSDimitry Andric         Done = true;
156809500fcSDimitry Andric         continue;
157809500fcSDimitry Andric       }
158809500fcSDimitry Andric       return;
159809500fcSDimitry Andric 
160809500fcSDimitry Andric 
161809500fcSDimitry Andric     case llvm::BitstreamEntry::Record:
162809500fcSDimitry Andric       // Entries in the global index block are handled below.
163809500fcSDimitry Andric       if (InGlobalIndexBlock)
164809500fcSDimitry Andric         break;
165809500fcSDimitry Andric 
166809500fcSDimitry Andric       return;
167809500fcSDimitry Andric 
168809500fcSDimitry Andric     case llvm::BitstreamEntry::SubBlock:
169809500fcSDimitry Andric       if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {
17022989816SDimitry Andric         if (llvm::Error Err = Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))
17122989816SDimitry Andric           Fail(std::move(Err));
172809500fcSDimitry Andric         InGlobalIndexBlock = true;
17322989816SDimitry Andric       } else if (llvm::Error Err = Cursor.SkipBlock())
17422989816SDimitry Andric         Fail(std::move(Err));
175809500fcSDimitry Andric       continue;
176809500fcSDimitry Andric     }
177809500fcSDimitry Andric 
178809500fcSDimitry Andric     SmallVector<uint64_t, 64> Record;
179809500fcSDimitry Andric     StringRef Blob;
18022989816SDimitry Andric     Expected<unsigned> MaybeIndexRecord =
18122989816SDimitry Andric         Cursor.readRecord(Entry.ID, Record, &Blob);
18222989816SDimitry Andric     if (!MaybeIndexRecord)
18322989816SDimitry Andric       Fail(MaybeIndexRecord.takeError());
18422989816SDimitry Andric     IndexRecordTypes IndexRecord =
18522989816SDimitry Andric         static_cast<IndexRecordTypes>(MaybeIndexRecord.get());
18622989816SDimitry Andric     switch (IndexRecord) {
187809500fcSDimitry Andric     case INDEX_METADATA:
188809500fcSDimitry Andric       // Make sure that the version matches.
189809500fcSDimitry Andric       if (Record.size() < 1 || Record[0] != CurrentVersion)
190809500fcSDimitry Andric         return;
191809500fcSDimitry Andric       break;
192809500fcSDimitry Andric 
193809500fcSDimitry Andric     case MODULE: {
194809500fcSDimitry Andric       unsigned Idx = 0;
195809500fcSDimitry Andric       unsigned ID = Record[Idx++];
196809500fcSDimitry Andric 
197809500fcSDimitry Andric       // Make room for this module's information.
198809500fcSDimitry Andric       if (ID == Modules.size())
199809500fcSDimitry Andric         Modules.push_back(ModuleInfo());
200809500fcSDimitry Andric       else
201809500fcSDimitry Andric         Modules.resize(ID + 1);
202809500fcSDimitry Andric 
203809500fcSDimitry Andric       // Size/modification time for this module file at the time the
204809500fcSDimitry Andric       // global index was built.
205809500fcSDimitry Andric       Modules[ID].Size = Record[Idx++];
206809500fcSDimitry Andric       Modules[ID].ModTime = Record[Idx++];
207809500fcSDimitry Andric 
208809500fcSDimitry Andric       // File name.
209809500fcSDimitry Andric       unsigned NameLen = Record[Idx++];
210809500fcSDimitry Andric       Modules[ID].FileName.assign(Record.begin() + Idx,
211809500fcSDimitry Andric                                   Record.begin() + Idx + NameLen);
212809500fcSDimitry Andric       Idx += NameLen;
213809500fcSDimitry Andric 
214809500fcSDimitry Andric       // Dependencies
215809500fcSDimitry Andric       unsigned NumDeps = Record[Idx++];
216809500fcSDimitry Andric       Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),
217809500fcSDimitry Andric                                       Record.begin() + Idx,
218809500fcSDimitry Andric                                       Record.begin() + Idx + NumDeps);
219809500fcSDimitry Andric       Idx += NumDeps;
220809500fcSDimitry Andric 
221809500fcSDimitry Andric       // Make sure we're at the end of the record.
222809500fcSDimitry Andric       assert(Idx == Record.size() && "More module info?");
223809500fcSDimitry Andric 
224809500fcSDimitry Andric       // Record this module as an unresolved module.
2259f4dbff6SDimitry Andric       // FIXME: this doesn't work correctly for module names containing path
2269f4dbff6SDimitry Andric       // separators.
2279f4dbff6SDimitry Andric       StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName);
2289f4dbff6SDimitry Andric       // Remove the -<hash of ModuleMapPath>
2299f4dbff6SDimitry Andric       ModuleName = ModuleName.rsplit('-').first;
2309f4dbff6SDimitry Andric       UnresolvedModules[ModuleName] = ID;
231809500fcSDimitry Andric       break;
232809500fcSDimitry Andric     }
233809500fcSDimitry Andric 
234809500fcSDimitry Andric     case IDENTIFIER_INDEX:
235809500fcSDimitry Andric       // Wire up the identifier index.
236809500fcSDimitry Andric       if (Record[0]) {
237809500fcSDimitry Andric         IdentifierIndex = IdentifierIndexTable::Create(
238809500fcSDimitry Andric             (const unsigned char *)Blob.data() + Record[0],
2399f4dbff6SDimitry Andric             (const unsigned char *)Blob.data() + sizeof(uint32_t),
2409f4dbff6SDimitry Andric             (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait());
241809500fcSDimitry Andric       }
242809500fcSDimitry Andric       break;
243809500fcSDimitry Andric     }
244809500fcSDimitry Andric   }
245809500fcSDimitry Andric }
246809500fcSDimitry Andric 
~GlobalModuleIndex()2479f4dbff6SDimitry Andric GlobalModuleIndex::~GlobalModuleIndex() {
2489f4dbff6SDimitry Andric   delete static_cast<IdentifierIndexTable *>(IdentifierIndex);
2499f4dbff6SDimitry Andric }
250809500fcSDimitry Andric 
25122989816SDimitry Andric std::pair<GlobalModuleIndex *, llvm::Error>
readIndex(StringRef Path)252809500fcSDimitry Andric GlobalModuleIndex::readIndex(StringRef Path) {
253809500fcSDimitry Andric   // Load the index file, if it's there.
254809500fcSDimitry Andric   llvm::SmallString<128> IndexPath;
255809500fcSDimitry Andric   IndexPath += Path;
256809500fcSDimitry Andric   llvm::sys::path::append(IndexPath, IndexFileName);
257809500fcSDimitry Andric 
2589f4dbff6SDimitry Andric   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr =
2599f4dbff6SDimitry Andric       llvm::MemoryBuffer::getFile(IndexPath.c_str());
2609f4dbff6SDimitry Andric   if (!BufferOrErr)
26122989816SDimitry Andric     return std::make_pair(nullptr,
26222989816SDimitry Andric                           llvm::errorCodeToError(BufferOrErr.getError()));
2639f4dbff6SDimitry Andric   std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get());
264809500fcSDimitry Andric 
26548675466SDimitry Andric   /// The main bitstream cursor for the main block.
266bab175ecSDimitry Andric   llvm::BitstreamCursor Cursor(*Buffer);
267809500fcSDimitry Andric 
268809500fcSDimitry Andric   // Sniff for the signature.
26922989816SDimitry Andric   for (unsigned char C : {'B', 'C', 'G', 'I'}) {
27022989816SDimitry Andric     if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Cursor.Read(8)) {
27122989816SDimitry Andric       if (Res.get() != C)
27222989816SDimitry Andric         return std::make_pair(
27322989816SDimitry Andric             nullptr, llvm::createStringError(std::errc::illegal_byte_sequence,
27422989816SDimitry Andric                                              "expected signature BCGI"));
27522989816SDimitry Andric     } else
27622989816SDimitry Andric       return std::make_pair(nullptr, Res.takeError());
277809500fcSDimitry Andric   }
278809500fcSDimitry Andric 
279145449b1SDimitry Andric   return std::make_pair(new GlobalModuleIndex(std::move(Buffer), std::move(Cursor)),
28022989816SDimitry Andric                         llvm::Error::success());
281809500fcSDimitry Andric }
282809500fcSDimitry Andric 
getModuleDependencies(ModuleFile * File,SmallVectorImpl<ModuleFile * > & Dependencies)283809500fcSDimitry Andric void GlobalModuleIndex::getModuleDependencies(
284809500fcSDimitry Andric        ModuleFile *File,
285809500fcSDimitry Andric        SmallVectorImpl<ModuleFile *> &Dependencies) {
286809500fcSDimitry Andric   // Look for information about this module file.
287809500fcSDimitry Andric   llvm::DenseMap<ModuleFile *, unsigned>::iterator Known
288809500fcSDimitry Andric     = ModulesByFile.find(File);
289809500fcSDimitry Andric   if (Known == ModulesByFile.end())
290809500fcSDimitry Andric     return;
291809500fcSDimitry Andric 
292809500fcSDimitry Andric   // Record dependencies.
293809500fcSDimitry Andric   Dependencies.clear();
294809500fcSDimitry Andric   ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies;
295809500fcSDimitry Andric   for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) {
296809500fcSDimitry Andric     if (ModuleFile *MF = Modules[I].File)
297809500fcSDimitry Andric       Dependencies.push_back(MF);
298809500fcSDimitry Andric   }
299809500fcSDimitry Andric }
300809500fcSDimitry Andric 
lookupIdentifier(StringRef Name,HitSet & Hits)301809500fcSDimitry Andric bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) {
302809500fcSDimitry Andric   Hits.clear();
303809500fcSDimitry Andric 
304809500fcSDimitry Andric   // If there's no identifier index, there is nothing we can do.
305809500fcSDimitry Andric   if (!IdentifierIndex)
306809500fcSDimitry Andric     return false;
307809500fcSDimitry Andric 
308809500fcSDimitry Andric   // Look into the identifier index.
309809500fcSDimitry Andric   ++NumIdentifierLookups;
310809500fcSDimitry Andric   IdentifierIndexTable &Table
311809500fcSDimitry Andric     = *static_cast<IdentifierIndexTable *>(IdentifierIndex);
312809500fcSDimitry Andric   IdentifierIndexTable::iterator Known = Table.find(Name);
313809500fcSDimitry Andric   if (Known == Table.end()) {
314cfca06d7SDimitry Andric     return false;
315809500fcSDimitry Andric   }
316809500fcSDimitry Andric 
317809500fcSDimitry Andric   SmallVector<unsigned, 2> ModuleIDs = *Known;
318809500fcSDimitry Andric   for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) {
319809500fcSDimitry Andric     if (ModuleFile *MF = Modules[ModuleIDs[I]].File)
320809500fcSDimitry Andric       Hits.insert(MF);
321809500fcSDimitry Andric   }
322809500fcSDimitry Andric 
323809500fcSDimitry Andric   ++NumIdentifierLookupHits;
324809500fcSDimitry Andric   return true;
325809500fcSDimitry Andric }
326809500fcSDimitry Andric 
loadedModuleFile(ModuleFile * File)327809500fcSDimitry Andric bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) {
328809500fcSDimitry Andric   // Look for the module in the global module index based on the module name.
3299f4dbff6SDimitry Andric   StringRef Name = File->ModuleName;
330809500fcSDimitry Andric   llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name);
331809500fcSDimitry Andric   if (Known == UnresolvedModules.end()) {
332809500fcSDimitry Andric     return true;
333809500fcSDimitry Andric   }
334809500fcSDimitry Andric 
335809500fcSDimitry Andric   // Rectify this module with the global module index.
336809500fcSDimitry Andric   ModuleInfo &Info = Modules[Known->second];
337809500fcSDimitry Andric 
338809500fcSDimitry Andric   //  If the size and modification time match what we expected, record this
339809500fcSDimitry Andric   // module file.
340809500fcSDimitry Andric   bool Failed = true;
341b1c73532SDimitry Andric   if (File->File.getSize() == Info.Size &&
342b1c73532SDimitry Andric       File->File.getModificationTime() == Info.ModTime) {
343809500fcSDimitry Andric     Info.File = File;
344809500fcSDimitry Andric     ModulesByFile[File] = Known->second;
345809500fcSDimitry Andric 
346809500fcSDimitry Andric     Failed = false;
347809500fcSDimitry Andric   }
348809500fcSDimitry Andric 
349809500fcSDimitry Andric   // One way or another, we have resolved this module file.
350809500fcSDimitry Andric   UnresolvedModules.erase(Known);
351809500fcSDimitry Andric   return Failed;
352809500fcSDimitry Andric }
353809500fcSDimitry Andric 
printStats()354809500fcSDimitry Andric void GlobalModuleIndex::printStats() {
355809500fcSDimitry Andric   std::fprintf(stderr, "*** Global Module Index Statistics:\n");
356809500fcSDimitry Andric   if (NumIdentifierLookups) {
357809500fcSDimitry Andric     fprintf(stderr, "  %u / %u identifier lookups succeeded (%f%%)\n",
358809500fcSDimitry Andric             NumIdentifierLookupHits, NumIdentifierLookups,
359809500fcSDimitry Andric             (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
360809500fcSDimitry Andric   }
361809500fcSDimitry Andric   std::fprintf(stderr, "\n");
362809500fcSDimitry Andric }
363809500fcSDimitry Andric 
dump()3642b6b257fSDimitry Andric LLVM_DUMP_METHOD void GlobalModuleIndex::dump() {
3659f4dbff6SDimitry Andric   llvm::errs() << "*** Global Module Index Dump:\n";
3669f4dbff6SDimitry Andric   llvm::errs() << "Module files:\n";
3679f4dbff6SDimitry Andric   for (auto &MI : Modules) {
3689f4dbff6SDimitry Andric     llvm::errs() << "** " << MI.FileName << "\n";
3699f4dbff6SDimitry Andric     if (MI.File)
3709f4dbff6SDimitry Andric       MI.File->dump();
3719f4dbff6SDimitry Andric     else
3729f4dbff6SDimitry Andric       llvm::errs() << "\n";
3739f4dbff6SDimitry Andric   }
3749f4dbff6SDimitry Andric   llvm::errs() << "\n";
3759f4dbff6SDimitry Andric }
3769f4dbff6SDimitry Andric 
377809500fcSDimitry Andric //----------------------------------------------------------------------------//
378809500fcSDimitry Andric // Global module index writer.
379809500fcSDimitry Andric //----------------------------------------------------------------------------//
380809500fcSDimitry Andric 
381809500fcSDimitry Andric namespace {
38248675466SDimitry Andric   /// Provides information about a specific module file.
383809500fcSDimitry Andric   struct ModuleFileInfo {
38448675466SDimitry Andric     /// The numberic ID for this module file.
385809500fcSDimitry Andric     unsigned ID;
386809500fcSDimitry Andric 
38748675466SDimitry Andric     /// The set of modules on which this module depends. Each entry is
388809500fcSDimitry Andric     /// a module ID.
389809500fcSDimitry Andric     SmallVector<unsigned, 4> Dependencies;
3907442d6faSDimitry Andric     ASTFileSignature Signature;
3917442d6faSDimitry Andric   };
3927442d6faSDimitry Andric 
3937442d6faSDimitry Andric   struct ImportedModuleFileInfo {
3947442d6faSDimitry Andric     off_t StoredSize;
3957442d6faSDimitry Andric     time_t StoredModTime;
3967442d6faSDimitry Andric     ASTFileSignature StoredSignature;
ImportedModuleFileInfo__anon14b795cb0511::ImportedModuleFileInfo3977442d6faSDimitry Andric     ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig)
3987442d6faSDimitry Andric         : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {}
399809500fcSDimitry Andric   };
400809500fcSDimitry Andric 
40148675466SDimitry Andric   /// Builder that generates the global module index file.
402809500fcSDimitry Andric   class GlobalModuleIndexBuilder {
403809500fcSDimitry Andric     FileManager &FileMgr;
40436c5ade2SDimitry Andric     const PCHContainerReader &PCHContainerRdr;
405809500fcSDimitry Andric 
4067442d6faSDimitry Andric     /// Mapping from files to module file information.
407b1c73532SDimitry Andric     using ModuleFilesMap = llvm::MapVector<FileEntryRef, ModuleFileInfo>;
408809500fcSDimitry Andric 
4097442d6faSDimitry Andric     /// Information about each of the known module files.
410809500fcSDimitry Andric     ModuleFilesMap ModuleFiles;
411809500fcSDimitry Andric 
41248675466SDimitry Andric     /// Mapping from the imported module file to the imported
4137442d6faSDimitry Andric     /// information.
414b1c73532SDimitry Andric     using ImportedModuleFilesMap =
415b1c73532SDimitry Andric         std::multimap<FileEntryRef, ImportedModuleFileInfo>;
4167442d6faSDimitry Andric 
41748675466SDimitry Andric     /// Information about each importing of a module file.
4187442d6faSDimitry Andric     ImportedModuleFilesMap ImportedModuleFiles;
4197442d6faSDimitry Andric 
42048675466SDimitry Andric     /// Mapping from identifiers to the list of module file IDs that
421809500fcSDimitry Andric     /// consider this identifier to be interesting.
422809500fcSDimitry Andric     typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
423809500fcSDimitry Andric 
42448675466SDimitry Andric     /// A mapping from all interesting identifiers to the set of module
425809500fcSDimitry Andric     /// files in which those identifiers are considered interesting.
426809500fcSDimitry Andric     InterestingIdentifierMap InterestingIdentifiers;
427809500fcSDimitry Andric 
42848675466SDimitry Andric     /// Write the block-info block for the global module index file.
429809500fcSDimitry Andric     void emitBlockInfoBlock(llvm::BitstreamWriter &Stream);
430809500fcSDimitry Andric 
43148675466SDimitry Andric     /// Retrieve the module file information for the given file.
getModuleFileInfo(FileEntryRef File)432b1c73532SDimitry Andric     ModuleFileInfo &getModuleFileInfo(FileEntryRef File) {
433b1c73532SDimitry Andric       auto Known = ModuleFiles.find(File);
434809500fcSDimitry Andric       if (Known != ModuleFiles.end())
435809500fcSDimitry Andric         return Known->second;
436809500fcSDimitry Andric 
437809500fcSDimitry Andric       unsigned NewID = ModuleFiles.size();
438809500fcSDimitry Andric       ModuleFileInfo &Info = ModuleFiles[File];
439809500fcSDimitry Andric       Info.ID = NewID;
440809500fcSDimitry Andric       return Info;
441809500fcSDimitry Andric     }
442809500fcSDimitry Andric 
443809500fcSDimitry Andric   public:
GlobalModuleIndexBuilder(FileManager & FileMgr,const PCHContainerReader & PCHContainerRdr)4442e645aa5SDimitry Andric     explicit GlobalModuleIndexBuilder(
44536c5ade2SDimitry Andric         FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr)
44636c5ade2SDimitry Andric         : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr) {}
447809500fcSDimitry Andric 
44848675466SDimitry Andric     /// Load the contents of the given module file into the builder.
449b1c73532SDimitry Andric     llvm::Error loadModuleFile(FileEntryRef File);
450809500fcSDimitry Andric 
45148675466SDimitry Andric     /// Write the index to the given bitstream.
4527442d6faSDimitry Andric     /// \returns true if an error occurred, false otherwise.
4537442d6faSDimitry Andric     bool writeIndex(llvm::BitstreamWriter &Stream);
454809500fcSDimitry Andric   };
455809500fcSDimitry Andric }
456809500fcSDimitry Andric 
emitBlockID(unsigned ID,const char * Name,llvm::BitstreamWriter & Stream,SmallVectorImpl<uint64_t> & Record)457809500fcSDimitry Andric static void emitBlockID(unsigned ID, const char *Name,
458809500fcSDimitry Andric                         llvm::BitstreamWriter &Stream,
459809500fcSDimitry Andric                         SmallVectorImpl<uint64_t> &Record) {
460809500fcSDimitry Andric   Record.clear();
461809500fcSDimitry Andric   Record.push_back(ID);
462809500fcSDimitry Andric   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
463809500fcSDimitry Andric 
464809500fcSDimitry Andric   // Emit the block name if present.
4659f4dbff6SDimitry Andric   if (!Name || Name[0] == 0) return;
466809500fcSDimitry Andric   Record.clear();
467809500fcSDimitry Andric   while (*Name)
468809500fcSDimitry Andric     Record.push_back(*Name++);
469809500fcSDimitry Andric   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
470809500fcSDimitry Andric }
471809500fcSDimitry Andric 
emitRecordID(unsigned ID,const char * Name,llvm::BitstreamWriter & Stream,SmallVectorImpl<uint64_t> & Record)472809500fcSDimitry Andric static void emitRecordID(unsigned ID, const char *Name,
473809500fcSDimitry Andric                          llvm::BitstreamWriter &Stream,
474809500fcSDimitry Andric                          SmallVectorImpl<uint64_t> &Record) {
475809500fcSDimitry Andric   Record.clear();
476809500fcSDimitry Andric   Record.push_back(ID);
477809500fcSDimitry Andric   while (*Name)
478809500fcSDimitry Andric     Record.push_back(*Name++);
479809500fcSDimitry Andric   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
480809500fcSDimitry Andric }
481809500fcSDimitry Andric 
482809500fcSDimitry Andric void
emitBlockInfoBlock(llvm::BitstreamWriter & Stream)483809500fcSDimitry Andric GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) {
484809500fcSDimitry Andric   SmallVector<uint64_t, 64> Record;
485bab175ecSDimitry Andric   Stream.EnterBlockInfoBlock();
486809500fcSDimitry Andric 
487809500fcSDimitry Andric #define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
488809500fcSDimitry Andric #define RECORD(X) emitRecordID(X, #X, Stream, Record)
489809500fcSDimitry Andric   BLOCK(GLOBAL_INDEX_BLOCK);
490809500fcSDimitry Andric   RECORD(INDEX_METADATA);
491809500fcSDimitry Andric   RECORD(MODULE);
492809500fcSDimitry Andric   RECORD(IDENTIFIER_INDEX);
493809500fcSDimitry Andric #undef RECORD
494809500fcSDimitry Andric #undef BLOCK
495809500fcSDimitry Andric 
496809500fcSDimitry Andric   Stream.ExitBlock();
497809500fcSDimitry Andric }
498809500fcSDimitry Andric 
499809500fcSDimitry Andric namespace {
500809500fcSDimitry Andric   class InterestingASTIdentifierLookupTrait
501809500fcSDimitry Andric     : public serialization::reader::ASTIdentifierLookupTraitBase {
502809500fcSDimitry Andric 
503809500fcSDimitry Andric   public:
50448675466SDimitry Andric     /// The identifier and whether it is "interesting".
505809500fcSDimitry Andric     typedef std::pair<StringRef, bool> data_type;
506809500fcSDimitry Andric 
ReadData(const internal_key_type & k,const unsigned char * d,unsigned DataLen)507809500fcSDimitry Andric     data_type ReadData(const internal_key_type& k,
508809500fcSDimitry Andric                        const unsigned char* d,
509809500fcSDimitry Andric                        unsigned DataLen) {
510809500fcSDimitry Andric       // The first bit indicates whether this identifier is interesting.
511809500fcSDimitry Andric       // That's all we care about.
5129f4dbff6SDimitry Andric       using namespace llvm::support;
513ac9a064cSDimitry Andric       IdentifierID RawID =
514ac9a064cSDimitry Andric           endian::readNext<IdentifierID, llvm::endianness::little>(d);
515809500fcSDimitry Andric       bool IsInteresting = RawID & 0x01;
516809500fcSDimitry Andric       return std::make_pair(k, IsInteresting);
517809500fcSDimitry Andric     }
518809500fcSDimitry Andric   };
519809500fcSDimitry Andric }
520809500fcSDimitry Andric 
loadModuleFile(FileEntryRef File)521b1c73532SDimitry Andric llvm::Error GlobalModuleIndexBuilder::loadModuleFile(FileEntryRef File) {
522809500fcSDimitry Andric   // Open the module file.
52306d4ba38SDimitry Andric 
52406d4ba38SDimitry Andric   auto Buffer = FileMgr.getBufferForFile(File, /*isVolatile=*/true);
52522989816SDimitry Andric   if (!Buffer)
52622989816SDimitry Andric     return llvm::createStringError(Buffer.getError(),
52722989816SDimitry Andric                                    "failed getting buffer for module file");
528809500fcSDimitry Andric 
529809500fcSDimitry Andric   // Initialize the input stream
530bab175ecSDimitry Andric   llvm::BitstreamCursor InStream(PCHContainerRdr.ExtractPCH(**Buffer));
531809500fcSDimitry Andric 
532809500fcSDimitry Andric   // Sniff for the signature.
53322989816SDimitry Andric   for (unsigned char C : {'C', 'P', 'C', 'H'})
53422989816SDimitry Andric     if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = InStream.Read(8)) {
53522989816SDimitry Andric       if (Res.get() != C)
53622989816SDimitry Andric         return llvm::createStringError(std::errc::illegal_byte_sequence,
53722989816SDimitry Andric                                        "expected signature CPCH");
53822989816SDimitry Andric     } else
53922989816SDimitry Andric       return Res.takeError();
540809500fcSDimitry Andric 
541809500fcSDimitry Andric   // Record this module file and assign it a unique ID (if it doesn't have
542809500fcSDimitry Andric   // one already).
543809500fcSDimitry Andric   unsigned ID = getModuleFileInfo(File).ID;
544809500fcSDimitry Andric 
545809500fcSDimitry Andric   // Search for the blocks and records we care about.
5467442d6faSDimitry Andric   enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other;
547809500fcSDimitry Andric   bool Done = false;
548809500fcSDimitry Andric   while (!Done) {
54922989816SDimitry Andric     Expected<llvm::BitstreamEntry> MaybeEntry = InStream.advance();
55022989816SDimitry Andric     if (!MaybeEntry)
55122989816SDimitry Andric       return MaybeEntry.takeError();
55222989816SDimitry Andric     llvm::BitstreamEntry Entry = MaybeEntry.get();
55322989816SDimitry Andric 
554809500fcSDimitry Andric     switch (Entry.Kind) {
555809500fcSDimitry Andric     case llvm::BitstreamEntry::Error:
556809500fcSDimitry Andric       Done = true;
557809500fcSDimitry Andric       continue;
558809500fcSDimitry Andric 
559809500fcSDimitry Andric     case llvm::BitstreamEntry::Record:
560809500fcSDimitry Andric       // In the 'other' state, just skip the record. We don't care.
561809500fcSDimitry Andric       if (State == Other) {
56222989816SDimitry Andric         if (llvm::Expected<unsigned> Skipped = InStream.skipRecord(Entry.ID))
563809500fcSDimitry Andric           continue;
56422989816SDimitry Andric         else
56522989816SDimitry Andric           return Skipped.takeError();
566809500fcSDimitry Andric       }
567809500fcSDimitry Andric 
568809500fcSDimitry Andric       // Handle potentially-interesting records below.
569809500fcSDimitry Andric       break;
570809500fcSDimitry Andric 
571809500fcSDimitry Andric     case llvm::BitstreamEntry::SubBlock:
572809500fcSDimitry Andric       if (Entry.ID == CONTROL_BLOCK_ID) {
57322989816SDimitry Andric         if (llvm::Error Err = InStream.EnterSubBlock(CONTROL_BLOCK_ID))
57422989816SDimitry Andric           return Err;
575809500fcSDimitry Andric 
576809500fcSDimitry Andric         // Found the control block.
577809500fcSDimitry Andric         State = ControlBlock;
578809500fcSDimitry Andric         continue;
579809500fcSDimitry Andric       }
580809500fcSDimitry Andric 
581809500fcSDimitry Andric       if (Entry.ID == AST_BLOCK_ID) {
58222989816SDimitry Andric         if (llvm::Error Err = InStream.EnterSubBlock(AST_BLOCK_ID))
58322989816SDimitry Andric           return Err;
584809500fcSDimitry Andric 
585809500fcSDimitry Andric         // Found the AST block.
586809500fcSDimitry Andric         State = ASTBlock;
587809500fcSDimitry Andric         continue;
588809500fcSDimitry Andric       }
589809500fcSDimitry Andric 
5907442d6faSDimitry Andric       if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) {
59122989816SDimitry Andric         if (llvm::Error Err = InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID))
59222989816SDimitry Andric           return Err;
5937442d6faSDimitry Andric 
5947442d6faSDimitry Andric         // Found the Diagnostic Options block.
5957442d6faSDimitry Andric         State = DiagnosticOptionsBlock;
5967442d6faSDimitry Andric         continue;
5977442d6faSDimitry Andric       }
5987442d6faSDimitry Andric 
59922989816SDimitry Andric       if (llvm::Error Err = InStream.SkipBlock())
60022989816SDimitry Andric         return Err;
601809500fcSDimitry Andric 
602809500fcSDimitry Andric       continue;
603809500fcSDimitry Andric 
604809500fcSDimitry Andric     case llvm::BitstreamEntry::EndBlock:
605809500fcSDimitry Andric       State = Other;
606809500fcSDimitry Andric       continue;
607809500fcSDimitry Andric     }
608809500fcSDimitry Andric 
609809500fcSDimitry Andric     // Read the given record.
610809500fcSDimitry Andric     SmallVector<uint64_t, 64> Record;
611809500fcSDimitry Andric     StringRef Blob;
61222989816SDimitry Andric     Expected<unsigned> MaybeCode = InStream.readRecord(Entry.ID, Record, &Blob);
61322989816SDimitry Andric     if (!MaybeCode)
61422989816SDimitry Andric       return MaybeCode.takeError();
61522989816SDimitry Andric     unsigned Code = MaybeCode.get();
616809500fcSDimitry Andric 
617809500fcSDimitry Andric     // Handle module dependencies.
618809500fcSDimitry Andric     if (State == ControlBlock && Code == IMPORTS) {
619809500fcSDimitry Andric       // Load each of the imported PCH files.
620809500fcSDimitry Andric       unsigned Idx = 0, N = Record.size();
621809500fcSDimitry Andric       while (Idx < N) {
622809500fcSDimitry Andric         // Read information about the AST file.
623809500fcSDimitry Andric 
624809500fcSDimitry Andric         // Skip the imported kind
625809500fcSDimitry Andric         ++Idx;
626809500fcSDimitry Andric 
6277fa27ce4SDimitry Andric         // Skip if it is standard C++ module
6287fa27ce4SDimitry Andric         ++Idx;
6297fa27ce4SDimitry Andric 
630809500fcSDimitry Andric         // Skip the import location
631809500fcSDimitry Andric         ++Idx;
632809500fcSDimitry Andric 
633809500fcSDimitry Andric         // Load stored size/modification time.
634809500fcSDimitry Andric         off_t StoredSize = (off_t)Record[Idx++];
635809500fcSDimitry Andric         time_t StoredModTime = (time_t)Record[Idx++];
636809500fcSDimitry Andric 
63706d4ba38SDimitry Andric         // Skip the stored signature.
63806d4ba38SDimitry Andric         // FIXME: we could read the signature out of the import and validate it.
639cfca06d7SDimitry Andric         auto FirstSignatureByte = Record.begin() + Idx;
640cfca06d7SDimitry Andric         ASTFileSignature StoredSignature = ASTFileSignature::create(
641cfca06d7SDimitry Andric             FirstSignatureByte, FirstSignatureByte + ASTFileSignature::size);
642cfca06d7SDimitry Andric         Idx += ASTFileSignature::size;
64306d4ba38SDimitry Andric 
644461a67faSDimitry Andric         // Skip the module name (currently this is only used for prebuilt
645461a67faSDimitry Andric         // modules while here we are only dealing with cached).
646461a67faSDimitry Andric         Idx += Record[Idx] + 1;
647461a67faSDimitry Andric 
648809500fcSDimitry Andric         // Retrieve the imported file name.
649809500fcSDimitry Andric         unsigned Length = Record[Idx++];
650809500fcSDimitry Andric         SmallString<128> ImportedFile(Record.begin() + Idx,
651809500fcSDimitry Andric                                       Record.begin() + Idx + Length);
652809500fcSDimitry Andric         Idx += Length;
653809500fcSDimitry Andric 
654809500fcSDimitry Andric         // Find the imported module file.
655b1c73532SDimitry Andric         auto DependsOnFile =
656b1c73532SDimitry Andric             FileMgr.getOptionalFileRef(ImportedFile, /*OpenFile=*/false,
65722989816SDimitry Andric                                        /*CacheFailure=*/false);
6587442d6faSDimitry Andric 
6597442d6faSDimitry Andric         if (!DependsOnFile)
66022989816SDimitry Andric           return llvm::createStringError(std::errc::bad_file_descriptor,
66122989816SDimitry Andric                                          "imported file \"%s\" not found",
66222989816SDimitry Andric                                          ImportedFile.c_str());
663809500fcSDimitry Andric 
6647442d6faSDimitry Andric         // Save the information in ImportedModuleFileInfo so we can verify after
6657442d6faSDimitry Andric         // loading all pcms.
6667442d6faSDimitry Andric         ImportedModuleFiles.insert(std::make_pair(
667519fc96cSDimitry Andric             *DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
6687442d6faSDimitry Andric                                                    StoredSignature)));
6697442d6faSDimitry Andric 
670809500fcSDimitry Andric         // Record the dependency.
671519fc96cSDimitry Andric         unsigned DependsOnID = getModuleFileInfo(*DependsOnFile).ID;
672809500fcSDimitry Andric         getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
673809500fcSDimitry Andric       }
674809500fcSDimitry Andric 
675809500fcSDimitry Andric       continue;
676809500fcSDimitry Andric     }
677809500fcSDimitry Andric 
678809500fcSDimitry Andric     // Handle the identifier table
679809500fcSDimitry Andric     if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {
6809f4dbff6SDimitry Andric       typedef llvm::OnDiskIterableChainedHashTable<
6819f4dbff6SDimitry Andric           InterestingASTIdentifierLookupTrait> InterestingIdentifierTable;
6829f4dbff6SDimitry Andric       std::unique_ptr<InterestingIdentifierTable> Table(
6839f4dbff6SDimitry Andric           InterestingIdentifierTable::Create(
684809500fcSDimitry Andric               (const unsigned char *)Blob.data() + Record[0],
6859f4dbff6SDimitry Andric               (const unsigned char *)Blob.data() + sizeof(uint32_t),
686809500fcSDimitry Andric               (const unsigned char *)Blob.data()));
687809500fcSDimitry Andric       for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
688809500fcSDimitry Andric                                                      DEnd = Table->data_end();
689809500fcSDimitry Andric            D != DEnd; ++D) {
690809500fcSDimitry Andric         std::pair<StringRef, bool> Ident = *D;
691809500fcSDimitry Andric         if (Ident.second)
692809500fcSDimitry Andric           InterestingIdentifiers[Ident.first].push_back(ID);
693809500fcSDimitry Andric         else
694809500fcSDimitry Andric           (void)InterestingIdentifiers[Ident.first];
695809500fcSDimitry Andric       }
696809500fcSDimitry Andric     }
697809500fcSDimitry Andric 
6987442d6faSDimitry Andric     // Get Signature.
699b1c73532SDimitry Andric     if (State == DiagnosticOptionsBlock && Code == SIGNATURE) {
700b1c73532SDimitry Andric       auto Signature = ASTFileSignature::create(Blob.begin(), Blob.end());
701b1c73532SDimitry Andric       assert(Signature != ASTFileSignature::createDummy() &&
702b1c73532SDimitry Andric              "Dummy AST file signature not backpatched in ASTWriter.");
703b1c73532SDimitry Andric       getModuleFileInfo(File).Signature = Signature;
704b1c73532SDimitry Andric     }
7057442d6faSDimitry Andric 
706809500fcSDimitry Andric     // We don't care about this record.
707809500fcSDimitry Andric   }
708809500fcSDimitry Andric 
70922989816SDimitry Andric   return llvm::Error::success();
710809500fcSDimitry Andric }
711809500fcSDimitry Andric 
712809500fcSDimitry Andric namespace {
713809500fcSDimitry Andric 
71448675466SDimitry Andric /// Trait used to generate the identifier index as an on-disk hash
715809500fcSDimitry Andric /// table.
716809500fcSDimitry Andric class IdentifierIndexWriterTrait {
717809500fcSDimitry Andric public:
718809500fcSDimitry Andric   typedef StringRef key_type;
719809500fcSDimitry Andric   typedef StringRef key_type_ref;
720809500fcSDimitry Andric   typedef SmallVector<unsigned, 2> data_type;
721809500fcSDimitry Andric   typedef const SmallVector<unsigned, 2> &data_type_ref;
7229f4dbff6SDimitry Andric   typedef unsigned hash_value_type;
7239f4dbff6SDimitry Andric   typedef unsigned offset_type;
724809500fcSDimitry Andric 
ComputeHash(key_type_ref Key)7259f4dbff6SDimitry Andric   static hash_value_type ComputeHash(key_type_ref Key) {
72648675466SDimitry Andric     return llvm::djbHash(Key);
727809500fcSDimitry Andric   }
728809500fcSDimitry Andric 
729809500fcSDimitry Andric   std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream & Out,key_type_ref Key,data_type_ref Data)730809500fcSDimitry Andric   EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) {
7319f4dbff6SDimitry Andric     using namespace llvm::support;
732b1c73532SDimitry Andric     endian::Writer LE(Out, llvm::endianness::little);
733809500fcSDimitry Andric     unsigned KeyLen = Key.size();
734809500fcSDimitry Andric     unsigned DataLen = Data.size() * 4;
7359f4dbff6SDimitry Andric     LE.write<uint16_t>(KeyLen);
7369f4dbff6SDimitry Andric     LE.write<uint16_t>(DataLen);
737809500fcSDimitry Andric     return std::make_pair(KeyLen, DataLen);
738809500fcSDimitry Andric   }
739809500fcSDimitry Andric 
EmitKey(raw_ostream & Out,key_type_ref Key,unsigned KeyLen)740809500fcSDimitry Andric   void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
741809500fcSDimitry Andric     Out.write(Key.data(), KeyLen);
742809500fcSDimitry Andric   }
743809500fcSDimitry Andric 
EmitData(raw_ostream & Out,key_type_ref Key,data_type_ref Data,unsigned DataLen)744809500fcSDimitry Andric   void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
745809500fcSDimitry Andric                 unsigned DataLen) {
7469f4dbff6SDimitry Andric     using namespace llvm::support;
747809500fcSDimitry Andric     for (unsigned I = 0, N = Data.size(); I != N; ++I)
748b1c73532SDimitry Andric       endian::write<uint32_t>(Out, Data[I], llvm::endianness::little);
749809500fcSDimitry Andric   }
750809500fcSDimitry Andric };
751809500fcSDimitry Andric 
752809500fcSDimitry Andric }
753809500fcSDimitry Andric 
writeIndex(llvm::BitstreamWriter & Stream)7547442d6faSDimitry Andric bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
7557442d6faSDimitry Andric   for (auto MapEntry : ImportedModuleFiles) {
756b1c73532SDimitry Andric     auto File = MapEntry.first;
7577442d6faSDimitry Andric     ImportedModuleFileInfo &Info = MapEntry.second;
7587442d6faSDimitry Andric     if (getModuleFileInfo(File).Signature) {
7597442d6faSDimitry Andric       if (getModuleFileInfo(File).Signature != Info.StoredSignature)
7607442d6faSDimitry Andric         // Verify Signature.
7617442d6faSDimitry Andric         return true;
762b1c73532SDimitry Andric     } else if (Info.StoredSize != File.getSize() ||
763b1c73532SDimitry Andric                Info.StoredModTime != File.getModificationTime())
7647442d6faSDimitry Andric       // Verify Size and ModTime.
7657442d6faSDimitry Andric       return true;
7667442d6faSDimitry Andric   }
7677442d6faSDimitry Andric 
768809500fcSDimitry Andric   using namespace llvm;
769706b4fc4SDimitry Andric   llvm::TimeTraceScope TimeScope("Module WriteIndex");
770809500fcSDimitry Andric 
771809500fcSDimitry Andric   // Emit the file header.
772809500fcSDimitry Andric   Stream.Emit((unsigned)'B', 8);
773809500fcSDimitry Andric   Stream.Emit((unsigned)'C', 8);
774809500fcSDimitry Andric   Stream.Emit((unsigned)'G', 8);
775809500fcSDimitry Andric   Stream.Emit((unsigned)'I', 8);
776809500fcSDimitry Andric 
777809500fcSDimitry Andric   // Write the block-info block, which describes the records in this bitcode
778809500fcSDimitry Andric   // file.
779809500fcSDimitry Andric   emitBlockInfoBlock(Stream);
780809500fcSDimitry Andric 
781809500fcSDimitry Andric   Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);
782809500fcSDimitry Andric 
783809500fcSDimitry Andric   // Write the metadata.
784809500fcSDimitry Andric   SmallVector<uint64_t, 2> Record;
785809500fcSDimitry Andric   Record.push_back(CurrentVersion);
786809500fcSDimitry Andric   Stream.EmitRecord(INDEX_METADATA, Record);
787809500fcSDimitry Andric 
788809500fcSDimitry Andric   // Write the set of known module files.
789809500fcSDimitry Andric   for (ModuleFilesMap::iterator M = ModuleFiles.begin(),
790809500fcSDimitry Andric                                 MEnd = ModuleFiles.end();
791809500fcSDimitry Andric        M != MEnd; ++M) {
792809500fcSDimitry Andric     Record.clear();
793809500fcSDimitry Andric     Record.push_back(M->second.ID);
794b1c73532SDimitry Andric     Record.push_back(M->first.getSize());
795b1c73532SDimitry Andric     Record.push_back(M->first.getModificationTime());
796809500fcSDimitry Andric 
797809500fcSDimitry Andric     // File name
798b1c73532SDimitry Andric     StringRef Name(M->first.getName());
799809500fcSDimitry Andric     Record.push_back(Name.size());
800809500fcSDimitry Andric     Record.append(Name.begin(), Name.end());
801809500fcSDimitry Andric 
802809500fcSDimitry Andric     // Dependencies
803809500fcSDimitry Andric     Record.push_back(M->second.Dependencies.size());
804809500fcSDimitry Andric     Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());
805809500fcSDimitry Andric     Stream.EmitRecord(MODULE, Record);
806809500fcSDimitry Andric   }
807809500fcSDimitry Andric 
808809500fcSDimitry Andric   // Write the identifier -> module file mapping.
809809500fcSDimitry Andric   {
8109f4dbff6SDimitry Andric     llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
811809500fcSDimitry Andric     IdentifierIndexWriterTrait Trait;
812809500fcSDimitry Andric 
813809500fcSDimitry Andric     // Populate the hash table.
814809500fcSDimitry Andric     for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),
815809500fcSDimitry Andric                                             IEnd = InterestingIdentifiers.end();
816809500fcSDimitry Andric          I != IEnd; ++I) {
817809500fcSDimitry Andric       Generator.insert(I->first(), I->second, Trait);
818809500fcSDimitry Andric     }
819809500fcSDimitry Andric 
820809500fcSDimitry Andric     // Create the on-disk hash table in a buffer.
821809500fcSDimitry Andric     SmallString<4096> IdentifierTable;
822809500fcSDimitry Andric     uint32_t BucketOffset;
823809500fcSDimitry Andric     {
8249f4dbff6SDimitry Andric       using namespace llvm::support;
825809500fcSDimitry Andric       llvm::raw_svector_ostream Out(IdentifierTable);
826809500fcSDimitry Andric       // Make sure that no bucket is at offset 0
827b1c73532SDimitry Andric       endian::write<uint32_t>(Out, 0, llvm::endianness::little);
828809500fcSDimitry Andric       BucketOffset = Generator.Emit(Out, Trait);
829809500fcSDimitry Andric     }
830809500fcSDimitry Andric 
831809500fcSDimitry Andric     // Create a blob abbreviation
8326694ed09SDimitry Andric     auto Abbrev = std::make_shared<BitCodeAbbrev>();
833809500fcSDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX));
834809500fcSDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
835809500fcSDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
8366694ed09SDimitry Andric     unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
837809500fcSDimitry Andric 
838809500fcSDimitry Andric     // Write the identifier table
83945b53394SDimitry Andric     uint64_t Record[] = {IDENTIFIER_INDEX, BucketOffset};
8405e20cdd8SDimitry Andric     Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable);
841809500fcSDimitry Andric   }
842809500fcSDimitry Andric 
843809500fcSDimitry Andric   Stream.ExitBlock();
8447442d6faSDimitry Andric   return false;
845809500fcSDimitry Andric }
846809500fcSDimitry Andric 
84722989816SDimitry Andric llvm::Error
writeIndex(FileManager & FileMgr,const PCHContainerReader & PCHContainerRdr,StringRef Path)8482e645aa5SDimitry Andric GlobalModuleIndex::writeIndex(FileManager &FileMgr,
84936c5ade2SDimitry Andric                               const PCHContainerReader &PCHContainerRdr,
8502e645aa5SDimitry Andric                               StringRef Path) {
851809500fcSDimitry Andric   llvm::SmallString<128> IndexPath;
852809500fcSDimitry Andric   IndexPath += Path;
853809500fcSDimitry Andric   llvm::sys::path::append(IndexPath, IndexFileName);
854809500fcSDimitry Andric 
855809500fcSDimitry Andric   // Coordinate building the global index file with other processes that might
856809500fcSDimitry Andric   // try to do the same.
857809500fcSDimitry Andric   llvm::LockFileManager Locked(IndexPath);
858809500fcSDimitry Andric   switch (Locked) {
859809500fcSDimitry Andric   case llvm::LockFileManager::LFS_Error:
86022989816SDimitry Andric     return llvm::createStringError(std::errc::io_error, "LFS error");
861809500fcSDimitry Andric 
862809500fcSDimitry Andric   case llvm::LockFileManager::LFS_Owned:
863809500fcSDimitry Andric     // We're responsible for building the index ourselves. Do so below.
864809500fcSDimitry Andric     break;
865809500fcSDimitry Andric 
866809500fcSDimitry Andric   case llvm::LockFileManager::LFS_Shared:
867809500fcSDimitry Andric     // Someone else is responsible for building the index. We don't care
868809500fcSDimitry Andric     // when they finish, so we're done.
86922989816SDimitry Andric     return llvm::createStringError(std::errc::device_or_resource_busy,
87022989816SDimitry Andric                                    "someone else is building the index");
871809500fcSDimitry Andric   }
872809500fcSDimitry Andric 
873809500fcSDimitry Andric   // The module index builder.
87436c5ade2SDimitry Andric   GlobalModuleIndexBuilder Builder(FileMgr, PCHContainerRdr);
875809500fcSDimitry Andric 
876809500fcSDimitry Andric   // Load each of the module files.
8779f4dbff6SDimitry Andric   std::error_code EC;
878809500fcSDimitry Andric   for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
879809500fcSDimitry Andric        D != DEnd && !EC;
880809500fcSDimitry Andric        D.increment(EC)) {
881809500fcSDimitry Andric     // If this isn't a module file, we don't care.
882809500fcSDimitry Andric     if (llvm::sys::path::extension(D->path()) != ".pcm") {
883809500fcSDimitry Andric       // ... unless it's a .pcm.lock file, which indicates that someone is
884809500fcSDimitry Andric       // in the process of rebuilding a module. They'll rebuild the index
885809500fcSDimitry Andric       // at the end of that translation unit, so we don't have to.
886809500fcSDimitry Andric       if (llvm::sys::path::extension(D->path()) == ".pcm.lock")
88722989816SDimitry Andric         return llvm::createStringError(std::errc::device_or_resource_busy,
88822989816SDimitry Andric                                        "someone else is building the index");
889809500fcSDimitry Andric 
890809500fcSDimitry Andric       continue;
891809500fcSDimitry Andric     }
892809500fcSDimitry Andric 
893809500fcSDimitry Andric     // If we can't find the module file, skip it.
894b1c73532SDimitry Andric     auto ModuleFile = FileMgr.getOptionalFileRef(D->path());
895809500fcSDimitry Andric     if (!ModuleFile)
896809500fcSDimitry Andric       continue;
897809500fcSDimitry Andric 
898809500fcSDimitry Andric     // Load this module file.
899519fc96cSDimitry Andric     if (llvm::Error Err = Builder.loadModuleFile(*ModuleFile))
90022989816SDimitry Andric       return Err;
901809500fcSDimitry Andric   }
902809500fcSDimitry Andric 
903809500fcSDimitry Andric   // The output buffer, into which the global index will be written.
904b60736ecSDimitry Andric   SmallString<16> OutputBuffer;
905809500fcSDimitry Andric   {
906809500fcSDimitry Andric     llvm::BitstreamWriter OutputStream(OutputBuffer);
9077442d6faSDimitry Andric     if (Builder.writeIndex(OutputStream))
90822989816SDimitry Andric       return llvm::createStringError(std::errc::io_error,
90922989816SDimitry Andric                                      "failed writing index");
910809500fcSDimitry Andric   }
911809500fcSDimitry Andric 
9127fa27ce4SDimitry Andric   return llvm::writeToOutput(IndexPath, [&OutputBuffer](llvm::raw_ostream &OS) {
9137fa27ce4SDimitry Andric     OS << OutputBuffer;
9147fa27ce4SDimitry Andric     return llvm::Error::success();
9157fa27ce4SDimitry Andric   });
916809500fcSDimitry Andric }
9176a037251SDimitry Andric 
9186a037251SDimitry Andric namespace {
9196a037251SDimitry Andric   class GlobalIndexIdentifierIterator : public IdentifierIterator {
92048675466SDimitry Andric     /// The current position within the identifier lookup table.
9216a037251SDimitry Andric     IdentifierIndexTable::key_iterator Current;
9226a037251SDimitry Andric 
92348675466SDimitry Andric     /// The end position within the identifier lookup table.
9246a037251SDimitry Andric     IdentifierIndexTable::key_iterator End;
9256a037251SDimitry Andric 
9266a037251SDimitry Andric   public:
GlobalIndexIdentifierIterator(IdentifierIndexTable & Idx)9276a037251SDimitry Andric     explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) {
9286a037251SDimitry Andric       Current = Idx.key_begin();
9296a037251SDimitry Andric       End = Idx.key_end();
9306a037251SDimitry Andric     }
9316a037251SDimitry Andric 
Next()9329f4dbff6SDimitry Andric     StringRef Next() override {
9336a037251SDimitry Andric       if (Current == End)
9346a037251SDimitry Andric         return StringRef();
9356a037251SDimitry Andric 
9366a037251SDimitry Andric       StringRef Result = *Current;
9376a037251SDimitry Andric       ++Current;
9386a037251SDimitry Andric       return Result;
9396a037251SDimitry Andric     }
9406a037251SDimitry Andric   };
9416a037251SDimitry Andric }
9426a037251SDimitry Andric 
createIdentifierIterator() const9436a037251SDimitry Andric IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const {
9446a037251SDimitry Andric   IdentifierIndexTable &Table =
9456a037251SDimitry Andric     *static_cast<IdentifierIndexTable *>(IdentifierIndex);
9466a037251SDimitry Andric   return new GlobalIndexIdentifierIterator(Table);
9476a037251SDimitry Andric }
948