xref: /openbsd-src/gnu/llvm/clang/lib/Serialization/GlobalModuleIndex.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- GlobalModuleIndex.cpp - Global Module Index ------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements the GlobalModuleIndex class.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "clang/Serialization/GlobalModuleIndex.h"
14e5dd7070Spatrick #include "ASTReaderInternals.h"
15e5dd7070Spatrick #include "clang/Basic/FileManager.h"
16e5dd7070Spatrick #include "clang/Lex/HeaderSearch.h"
17e5dd7070Spatrick #include "clang/Serialization/ASTBitCodes.h"
18e5dd7070Spatrick #include "clang/Serialization/ModuleFile.h"
19e5dd7070Spatrick #include "clang/Serialization/PCHContainerOperations.h"
20e5dd7070Spatrick #include "llvm/ADT/DenseMap.h"
21e5dd7070Spatrick #include "llvm/ADT/MapVector.h"
22e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
23e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
24e5dd7070Spatrick #include "llvm/Bitstream/BitstreamReader.h"
25e5dd7070Spatrick #include "llvm/Bitstream/BitstreamWriter.h"
26e5dd7070Spatrick #include "llvm/Support/DJB.h"
27e5dd7070Spatrick #include "llvm/Support/FileSystem.h"
28e5dd7070Spatrick #include "llvm/Support/FileUtilities.h"
29e5dd7070Spatrick #include "llvm/Support/LockFileManager.h"
30e5dd7070Spatrick #include "llvm/Support/MemoryBuffer.h"
31e5dd7070Spatrick #include "llvm/Support/OnDiskHashTable.h"
32e5dd7070Spatrick #include "llvm/Support/Path.h"
33e5dd7070Spatrick #include "llvm/Support/TimeProfiler.h"
34e5dd7070Spatrick #include <cstdio>
35e5dd7070Spatrick using namespace clang;
36e5dd7070Spatrick using namespace serialization;
37e5dd7070Spatrick 
38e5dd7070Spatrick //----------------------------------------------------------------------------//
39e5dd7070Spatrick // Shared constants
40e5dd7070Spatrick //----------------------------------------------------------------------------//
41e5dd7070Spatrick namespace {
42e5dd7070Spatrick   enum {
43e5dd7070Spatrick     /// The block containing the index.
44e5dd7070Spatrick     GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID
45e5dd7070Spatrick   };
46e5dd7070Spatrick 
47e5dd7070Spatrick   /// Describes the record types in the index.
48e5dd7070Spatrick   enum IndexRecordTypes {
49e5dd7070Spatrick     /// Contains version information and potentially other metadata,
50e5dd7070Spatrick     /// used to determine if we can read this global index file.
51e5dd7070Spatrick     INDEX_METADATA,
52e5dd7070Spatrick     /// Describes a module, including its file name and dependencies.
53e5dd7070Spatrick     MODULE,
54e5dd7070Spatrick     /// The index for identifiers.
55e5dd7070Spatrick     IDENTIFIER_INDEX
56e5dd7070Spatrick   };
57e5dd7070Spatrick }
58e5dd7070Spatrick 
59e5dd7070Spatrick /// The name of the global index file.
60e5dd7070Spatrick static const char * const IndexFileName = "modules.idx";
61e5dd7070Spatrick 
62e5dd7070Spatrick /// The global index file version.
63e5dd7070Spatrick static const unsigned CurrentVersion = 1;
64e5dd7070Spatrick 
65e5dd7070Spatrick //----------------------------------------------------------------------------//
66e5dd7070Spatrick // Global module index reader.
67e5dd7070Spatrick //----------------------------------------------------------------------------//
68e5dd7070Spatrick 
69e5dd7070Spatrick namespace {
70e5dd7070Spatrick 
71e5dd7070Spatrick /// Trait used to read the identifier index from the on-disk hash
72e5dd7070Spatrick /// table.
73e5dd7070Spatrick class IdentifierIndexReaderTrait {
74e5dd7070Spatrick public:
75e5dd7070Spatrick   typedef StringRef external_key_type;
76e5dd7070Spatrick   typedef StringRef internal_key_type;
77e5dd7070Spatrick   typedef SmallVector<unsigned, 2> data_type;
78e5dd7070Spatrick   typedef unsigned hash_value_type;
79e5dd7070Spatrick   typedef unsigned offset_type;
80e5dd7070Spatrick 
EqualKey(const internal_key_type & a,const internal_key_type & b)81e5dd7070Spatrick   static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
82e5dd7070Spatrick     return a == b;
83e5dd7070Spatrick   }
84e5dd7070Spatrick 
ComputeHash(const internal_key_type & a)85e5dd7070Spatrick   static hash_value_type ComputeHash(const internal_key_type& a) {
86e5dd7070Spatrick     return llvm::djbHash(a);
87e5dd7070Spatrick   }
88e5dd7070Spatrick 
89e5dd7070Spatrick   static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char * & d)90e5dd7070Spatrick   ReadKeyDataLength(const unsigned char*& d) {
91e5dd7070Spatrick     using namespace llvm::support;
92e5dd7070Spatrick     unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
93e5dd7070Spatrick     unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
94e5dd7070Spatrick     return std::make_pair(KeyLen, DataLen);
95e5dd7070Spatrick   }
96e5dd7070Spatrick 
97e5dd7070Spatrick   static const internal_key_type&
GetInternalKey(const external_key_type & x)98e5dd7070Spatrick   GetInternalKey(const external_key_type& x) { return x; }
99e5dd7070Spatrick 
100e5dd7070Spatrick   static const external_key_type&
GetExternalKey(const internal_key_type & x)101e5dd7070Spatrick   GetExternalKey(const internal_key_type& x) { return x; }
102e5dd7070Spatrick 
ReadKey(const unsigned char * d,unsigned n)103e5dd7070Spatrick   static internal_key_type ReadKey(const unsigned char* d, unsigned n) {
104e5dd7070Spatrick     return StringRef((const char *)d, n);
105e5dd7070Spatrick   }
106e5dd7070Spatrick 
ReadData(const internal_key_type & k,const unsigned char * d,unsigned DataLen)107e5dd7070Spatrick   static data_type ReadData(const internal_key_type& k,
108e5dd7070Spatrick                             const unsigned char* d,
109e5dd7070Spatrick                             unsigned DataLen) {
110e5dd7070Spatrick     using namespace llvm::support;
111e5dd7070Spatrick 
112e5dd7070Spatrick     data_type Result;
113e5dd7070Spatrick     while (DataLen > 0) {
114e5dd7070Spatrick       unsigned ID = endian::readNext<uint32_t, little, unaligned>(d);
115e5dd7070Spatrick       Result.push_back(ID);
116e5dd7070Spatrick       DataLen -= 4;
117e5dd7070Spatrick     }
118e5dd7070Spatrick 
119e5dd7070Spatrick     return Result;
120e5dd7070Spatrick   }
121e5dd7070Spatrick };
122e5dd7070Spatrick 
123e5dd7070Spatrick typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>
124e5dd7070Spatrick     IdentifierIndexTable;
125e5dd7070Spatrick 
126e5dd7070Spatrick }
127e5dd7070Spatrick 
GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> IndexBuffer,llvm::BitstreamCursor Cursor)128e5dd7070Spatrick GlobalModuleIndex::GlobalModuleIndex(
129e5dd7070Spatrick     std::unique_ptr<llvm::MemoryBuffer> IndexBuffer,
130e5dd7070Spatrick     llvm::BitstreamCursor Cursor)
131e5dd7070Spatrick     : Buffer(std::move(IndexBuffer)), IdentifierIndex(), NumIdentifierLookups(),
132e5dd7070Spatrick       NumIdentifierLookupHits() {
133e5dd7070Spatrick   auto Fail = [&](llvm::Error &&Err) {
134e5dd7070Spatrick     report_fatal_error("Module index '" + Buffer->getBufferIdentifier() +
135e5dd7070Spatrick                        "' failed: " + toString(std::move(Err)));
136e5dd7070Spatrick   };
137e5dd7070Spatrick 
138e5dd7070Spatrick   llvm::TimeTraceScope TimeScope("Module LoadIndex");
139e5dd7070Spatrick   // Read the global index.
140e5dd7070Spatrick   bool InGlobalIndexBlock = false;
141e5dd7070Spatrick   bool Done = false;
142e5dd7070Spatrick   while (!Done) {
143e5dd7070Spatrick     llvm::BitstreamEntry Entry;
144e5dd7070Spatrick     if (Expected<llvm::BitstreamEntry> Res = Cursor.advance())
145e5dd7070Spatrick       Entry = Res.get();
146e5dd7070Spatrick     else
147e5dd7070Spatrick       Fail(Res.takeError());
148e5dd7070Spatrick 
149e5dd7070Spatrick     switch (Entry.Kind) {
150e5dd7070Spatrick     case llvm::BitstreamEntry::Error:
151e5dd7070Spatrick       return;
152e5dd7070Spatrick 
153e5dd7070Spatrick     case llvm::BitstreamEntry::EndBlock:
154e5dd7070Spatrick       if (InGlobalIndexBlock) {
155e5dd7070Spatrick         InGlobalIndexBlock = false;
156e5dd7070Spatrick         Done = true;
157e5dd7070Spatrick         continue;
158e5dd7070Spatrick       }
159e5dd7070Spatrick       return;
160e5dd7070Spatrick 
161e5dd7070Spatrick 
162e5dd7070Spatrick     case llvm::BitstreamEntry::Record:
163e5dd7070Spatrick       // Entries in the global index block are handled below.
164e5dd7070Spatrick       if (InGlobalIndexBlock)
165e5dd7070Spatrick         break;
166e5dd7070Spatrick 
167e5dd7070Spatrick       return;
168e5dd7070Spatrick 
169e5dd7070Spatrick     case llvm::BitstreamEntry::SubBlock:
170e5dd7070Spatrick       if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {
171e5dd7070Spatrick         if (llvm::Error Err = Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))
172e5dd7070Spatrick           Fail(std::move(Err));
173e5dd7070Spatrick         InGlobalIndexBlock = true;
174e5dd7070Spatrick       } else if (llvm::Error Err = Cursor.SkipBlock())
175e5dd7070Spatrick         Fail(std::move(Err));
176e5dd7070Spatrick       continue;
177e5dd7070Spatrick     }
178e5dd7070Spatrick 
179e5dd7070Spatrick     SmallVector<uint64_t, 64> Record;
180e5dd7070Spatrick     StringRef Blob;
181e5dd7070Spatrick     Expected<unsigned> MaybeIndexRecord =
182e5dd7070Spatrick         Cursor.readRecord(Entry.ID, Record, &Blob);
183e5dd7070Spatrick     if (!MaybeIndexRecord)
184e5dd7070Spatrick       Fail(MaybeIndexRecord.takeError());
185e5dd7070Spatrick     IndexRecordTypes IndexRecord =
186e5dd7070Spatrick         static_cast<IndexRecordTypes>(MaybeIndexRecord.get());
187e5dd7070Spatrick     switch (IndexRecord) {
188e5dd7070Spatrick     case INDEX_METADATA:
189e5dd7070Spatrick       // Make sure that the version matches.
190e5dd7070Spatrick       if (Record.size() < 1 || Record[0] != CurrentVersion)
191e5dd7070Spatrick         return;
192e5dd7070Spatrick       break;
193e5dd7070Spatrick 
194e5dd7070Spatrick     case MODULE: {
195e5dd7070Spatrick       unsigned Idx = 0;
196e5dd7070Spatrick       unsigned ID = Record[Idx++];
197e5dd7070Spatrick 
198e5dd7070Spatrick       // Make room for this module's information.
199e5dd7070Spatrick       if (ID == Modules.size())
200e5dd7070Spatrick         Modules.push_back(ModuleInfo());
201e5dd7070Spatrick       else
202e5dd7070Spatrick         Modules.resize(ID + 1);
203e5dd7070Spatrick 
204e5dd7070Spatrick       // Size/modification time for this module file at the time the
205e5dd7070Spatrick       // global index was built.
206e5dd7070Spatrick       Modules[ID].Size = Record[Idx++];
207e5dd7070Spatrick       Modules[ID].ModTime = Record[Idx++];
208e5dd7070Spatrick 
209e5dd7070Spatrick       // File name.
210e5dd7070Spatrick       unsigned NameLen = Record[Idx++];
211e5dd7070Spatrick       Modules[ID].FileName.assign(Record.begin() + Idx,
212e5dd7070Spatrick                                   Record.begin() + Idx + NameLen);
213e5dd7070Spatrick       Idx += NameLen;
214e5dd7070Spatrick 
215e5dd7070Spatrick       // Dependencies
216e5dd7070Spatrick       unsigned NumDeps = Record[Idx++];
217e5dd7070Spatrick       Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),
218e5dd7070Spatrick                                       Record.begin() + Idx,
219e5dd7070Spatrick                                       Record.begin() + Idx + NumDeps);
220e5dd7070Spatrick       Idx += NumDeps;
221e5dd7070Spatrick 
222e5dd7070Spatrick       // Make sure we're at the end of the record.
223e5dd7070Spatrick       assert(Idx == Record.size() && "More module info?");
224e5dd7070Spatrick 
225e5dd7070Spatrick       // Record this module as an unresolved module.
226e5dd7070Spatrick       // FIXME: this doesn't work correctly for module names containing path
227e5dd7070Spatrick       // separators.
228e5dd7070Spatrick       StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName);
229e5dd7070Spatrick       // Remove the -<hash of ModuleMapPath>
230e5dd7070Spatrick       ModuleName = ModuleName.rsplit('-').first;
231e5dd7070Spatrick       UnresolvedModules[ModuleName] = ID;
232e5dd7070Spatrick       break;
233e5dd7070Spatrick     }
234e5dd7070Spatrick 
235e5dd7070Spatrick     case IDENTIFIER_INDEX:
236e5dd7070Spatrick       // Wire up the identifier index.
237e5dd7070Spatrick       if (Record[0]) {
238e5dd7070Spatrick         IdentifierIndex = IdentifierIndexTable::Create(
239e5dd7070Spatrick             (const unsigned char *)Blob.data() + Record[0],
240e5dd7070Spatrick             (const unsigned char *)Blob.data() + sizeof(uint32_t),
241e5dd7070Spatrick             (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait());
242e5dd7070Spatrick       }
243e5dd7070Spatrick       break;
244e5dd7070Spatrick     }
245e5dd7070Spatrick   }
246e5dd7070Spatrick }
247e5dd7070Spatrick 
~GlobalModuleIndex()248e5dd7070Spatrick GlobalModuleIndex::~GlobalModuleIndex() {
249e5dd7070Spatrick   delete static_cast<IdentifierIndexTable *>(IdentifierIndex);
250e5dd7070Spatrick }
251e5dd7070Spatrick 
252e5dd7070Spatrick std::pair<GlobalModuleIndex *, llvm::Error>
readIndex(StringRef Path)253e5dd7070Spatrick GlobalModuleIndex::readIndex(StringRef Path) {
254e5dd7070Spatrick   // Load the index file, if it's there.
255e5dd7070Spatrick   llvm::SmallString<128> IndexPath;
256e5dd7070Spatrick   IndexPath += Path;
257e5dd7070Spatrick   llvm::sys::path::append(IndexPath, IndexFileName);
258e5dd7070Spatrick 
259e5dd7070Spatrick   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr =
260e5dd7070Spatrick       llvm::MemoryBuffer::getFile(IndexPath.c_str());
261e5dd7070Spatrick   if (!BufferOrErr)
262e5dd7070Spatrick     return std::make_pair(nullptr,
263e5dd7070Spatrick                           llvm::errorCodeToError(BufferOrErr.getError()));
264e5dd7070Spatrick   std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get());
265e5dd7070Spatrick 
266e5dd7070Spatrick   /// The main bitstream cursor for the main block.
267e5dd7070Spatrick   llvm::BitstreamCursor Cursor(*Buffer);
268e5dd7070Spatrick 
269e5dd7070Spatrick   // Sniff for the signature.
270e5dd7070Spatrick   for (unsigned char C : {'B', 'C', 'G', 'I'}) {
271e5dd7070Spatrick     if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Cursor.Read(8)) {
272e5dd7070Spatrick       if (Res.get() != C)
273e5dd7070Spatrick         return std::make_pair(
274e5dd7070Spatrick             nullptr, llvm::createStringError(std::errc::illegal_byte_sequence,
275e5dd7070Spatrick                                              "expected signature BCGI"));
276e5dd7070Spatrick     } else
277e5dd7070Spatrick       return std::make_pair(nullptr, Res.takeError());
278e5dd7070Spatrick   }
279e5dd7070Spatrick 
280*12c85518Srobert   return std::make_pair(new GlobalModuleIndex(std::move(Buffer), std::move(Cursor)),
281e5dd7070Spatrick                         llvm::Error::success());
282e5dd7070Spatrick }
283e5dd7070Spatrick 
284e5dd7070Spatrick void
getKnownModules(SmallVectorImpl<ModuleFile * > & ModuleFiles)285e5dd7070Spatrick GlobalModuleIndex::getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles) {
286e5dd7070Spatrick   ModuleFiles.clear();
287e5dd7070Spatrick   for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
288e5dd7070Spatrick     if (ModuleFile *MF = Modules[I].File)
289e5dd7070Spatrick       ModuleFiles.push_back(MF);
290e5dd7070Spatrick   }
291e5dd7070Spatrick }
292e5dd7070Spatrick 
getModuleDependencies(ModuleFile * File,SmallVectorImpl<ModuleFile * > & Dependencies)293e5dd7070Spatrick void GlobalModuleIndex::getModuleDependencies(
294e5dd7070Spatrick        ModuleFile *File,
295e5dd7070Spatrick        SmallVectorImpl<ModuleFile *> &Dependencies) {
296e5dd7070Spatrick   // Look for information about this module file.
297e5dd7070Spatrick   llvm::DenseMap<ModuleFile *, unsigned>::iterator Known
298e5dd7070Spatrick     = ModulesByFile.find(File);
299e5dd7070Spatrick   if (Known == ModulesByFile.end())
300e5dd7070Spatrick     return;
301e5dd7070Spatrick 
302e5dd7070Spatrick   // Record dependencies.
303e5dd7070Spatrick   Dependencies.clear();
304e5dd7070Spatrick   ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies;
305e5dd7070Spatrick   for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) {
306e5dd7070Spatrick     if (ModuleFile *MF = Modules[I].File)
307e5dd7070Spatrick       Dependencies.push_back(MF);
308e5dd7070Spatrick   }
309e5dd7070Spatrick }
310e5dd7070Spatrick 
lookupIdentifier(StringRef Name,HitSet & Hits)311e5dd7070Spatrick bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) {
312e5dd7070Spatrick   Hits.clear();
313e5dd7070Spatrick 
314e5dd7070Spatrick   // If there's no identifier index, there is nothing we can do.
315e5dd7070Spatrick   if (!IdentifierIndex)
316e5dd7070Spatrick     return false;
317e5dd7070Spatrick 
318e5dd7070Spatrick   // Look into the identifier index.
319e5dd7070Spatrick   ++NumIdentifierLookups;
320e5dd7070Spatrick   IdentifierIndexTable &Table
321e5dd7070Spatrick     = *static_cast<IdentifierIndexTable *>(IdentifierIndex);
322e5dd7070Spatrick   IdentifierIndexTable::iterator Known = Table.find(Name);
323e5dd7070Spatrick   if (Known == Table.end()) {
324ec727ea7Spatrick     return false;
325e5dd7070Spatrick   }
326e5dd7070Spatrick 
327e5dd7070Spatrick   SmallVector<unsigned, 2> ModuleIDs = *Known;
328e5dd7070Spatrick   for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) {
329e5dd7070Spatrick     if (ModuleFile *MF = Modules[ModuleIDs[I]].File)
330e5dd7070Spatrick       Hits.insert(MF);
331e5dd7070Spatrick   }
332e5dd7070Spatrick 
333e5dd7070Spatrick   ++NumIdentifierLookupHits;
334e5dd7070Spatrick   return true;
335e5dd7070Spatrick }
336e5dd7070Spatrick 
loadedModuleFile(ModuleFile * File)337e5dd7070Spatrick bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) {
338e5dd7070Spatrick   // Look for the module in the global module index based on the module name.
339e5dd7070Spatrick   StringRef Name = File->ModuleName;
340e5dd7070Spatrick   llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name);
341e5dd7070Spatrick   if (Known == UnresolvedModules.end()) {
342e5dd7070Spatrick     return true;
343e5dd7070Spatrick   }
344e5dd7070Spatrick 
345e5dd7070Spatrick   // Rectify this module with the global module index.
346e5dd7070Spatrick   ModuleInfo &Info = Modules[Known->second];
347e5dd7070Spatrick 
348e5dd7070Spatrick   //  If the size and modification time match what we expected, record this
349e5dd7070Spatrick   // module file.
350e5dd7070Spatrick   bool Failed = true;
351e5dd7070Spatrick   if (File->File->getSize() == Info.Size &&
352e5dd7070Spatrick       File->File->getModificationTime() == Info.ModTime) {
353e5dd7070Spatrick     Info.File = File;
354e5dd7070Spatrick     ModulesByFile[File] = Known->second;
355e5dd7070Spatrick 
356e5dd7070Spatrick     Failed = false;
357e5dd7070Spatrick   }
358e5dd7070Spatrick 
359e5dd7070Spatrick   // One way or another, we have resolved this module file.
360e5dd7070Spatrick   UnresolvedModules.erase(Known);
361e5dd7070Spatrick   return Failed;
362e5dd7070Spatrick }
363e5dd7070Spatrick 
printStats()364e5dd7070Spatrick void GlobalModuleIndex::printStats() {
365e5dd7070Spatrick   std::fprintf(stderr, "*** Global Module Index Statistics:\n");
366e5dd7070Spatrick   if (NumIdentifierLookups) {
367e5dd7070Spatrick     fprintf(stderr, "  %u / %u identifier lookups succeeded (%f%%)\n",
368e5dd7070Spatrick             NumIdentifierLookupHits, NumIdentifierLookups,
369e5dd7070Spatrick             (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
370e5dd7070Spatrick   }
371e5dd7070Spatrick   std::fprintf(stderr, "\n");
372e5dd7070Spatrick }
373e5dd7070Spatrick 
dump()374e5dd7070Spatrick LLVM_DUMP_METHOD void GlobalModuleIndex::dump() {
375e5dd7070Spatrick   llvm::errs() << "*** Global Module Index Dump:\n";
376e5dd7070Spatrick   llvm::errs() << "Module files:\n";
377e5dd7070Spatrick   for (auto &MI : Modules) {
378e5dd7070Spatrick     llvm::errs() << "** " << MI.FileName << "\n";
379e5dd7070Spatrick     if (MI.File)
380e5dd7070Spatrick       MI.File->dump();
381e5dd7070Spatrick     else
382e5dd7070Spatrick       llvm::errs() << "\n";
383e5dd7070Spatrick   }
384e5dd7070Spatrick   llvm::errs() << "\n";
385e5dd7070Spatrick }
386e5dd7070Spatrick 
387e5dd7070Spatrick //----------------------------------------------------------------------------//
388e5dd7070Spatrick // Global module index writer.
389e5dd7070Spatrick //----------------------------------------------------------------------------//
390e5dd7070Spatrick 
391e5dd7070Spatrick namespace {
392e5dd7070Spatrick   /// Provides information about a specific module file.
393e5dd7070Spatrick   struct ModuleFileInfo {
394e5dd7070Spatrick     /// The numberic ID for this module file.
395e5dd7070Spatrick     unsigned ID;
396e5dd7070Spatrick 
397e5dd7070Spatrick     /// The set of modules on which this module depends. Each entry is
398e5dd7070Spatrick     /// a module ID.
399e5dd7070Spatrick     SmallVector<unsigned, 4> Dependencies;
400e5dd7070Spatrick     ASTFileSignature Signature;
401e5dd7070Spatrick   };
402e5dd7070Spatrick 
403e5dd7070Spatrick   struct ImportedModuleFileInfo {
404e5dd7070Spatrick     off_t StoredSize;
405e5dd7070Spatrick     time_t StoredModTime;
406e5dd7070Spatrick     ASTFileSignature StoredSignature;
ImportedModuleFileInfo__anoncf781a4d0511::ImportedModuleFileInfo407e5dd7070Spatrick     ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig)
408e5dd7070Spatrick         : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {}
409e5dd7070Spatrick   };
410e5dd7070Spatrick 
411e5dd7070Spatrick   /// Builder that generates the global module index file.
412e5dd7070Spatrick   class GlobalModuleIndexBuilder {
413e5dd7070Spatrick     FileManager &FileMgr;
414e5dd7070Spatrick     const PCHContainerReader &PCHContainerRdr;
415e5dd7070Spatrick 
416e5dd7070Spatrick     /// Mapping from files to module file information.
417e5dd7070Spatrick     typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap;
418e5dd7070Spatrick 
419e5dd7070Spatrick     /// Information about each of the known module files.
420e5dd7070Spatrick     ModuleFilesMap ModuleFiles;
421e5dd7070Spatrick 
422e5dd7070Spatrick     /// Mapping from the imported module file to the imported
423e5dd7070Spatrick     /// information.
424e5dd7070Spatrick     typedef std::multimap<const FileEntry *, ImportedModuleFileInfo>
425e5dd7070Spatrick         ImportedModuleFilesMap;
426e5dd7070Spatrick 
427e5dd7070Spatrick     /// Information about each importing of a module file.
428e5dd7070Spatrick     ImportedModuleFilesMap ImportedModuleFiles;
429e5dd7070Spatrick 
430e5dd7070Spatrick     /// Mapping from identifiers to the list of module file IDs that
431e5dd7070Spatrick     /// consider this identifier to be interesting.
432e5dd7070Spatrick     typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
433e5dd7070Spatrick 
434e5dd7070Spatrick     /// A mapping from all interesting identifiers to the set of module
435e5dd7070Spatrick     /// files in which those identifiers are considered interesting.
436e5dd7070Spatrick     InterestingIdentifierMap InterestingIdentifiers;
437e5dd7070Spatrick 
438e5dd7070Spatrick     /// Write the block-info block for the global module index file.
439e5dd7070Spatrick     void emitBlockInfoBlock(llvm::BitstreamWriter &Stream);
440e5dd7070Spatrick 
441e5dd7070Spatrick     /// Retrieve the module file information for the given file.
getModuleFileInfo(const FileEntry * File)442e5dd7070Spatrick     ModuleFileInfo &getModuleFileInfo(const FileEntry *File) {
443e5dd7070Spatrick       llvm::MapVector<const FileEntry *, ModuleFileInfo>::iterator Known
444e5dd7070Spatrick         = ModuleFiles.find(File);
445e5dd7070Spatrick       if (Known != ModuleFiles.end())
446e5dd7070Spatrick         return Known->second;
447e5dd7070Spatrick 
448e5dd7070Spatrick       unsigned NewID = ModuleFiles.size();
449e5dd7070Spatrick       ModuleFileInfo &Info = ModuleFiles[File];
450e5dd7070Spatrick       Info.ID = NewID;
451e5dd7070Spatrick       return Info;
452e5dd7070Spatrick     }
453e5dd7070Spatrick 
454e5dd7070Spatrick   public:
GlobalModuleIndexBuilder(FileManager & FileMgr,const PCHContainerReader & PCHContainerRdr)455e5dd7070Spatrick     explicit GlobalModuleIndexBuilder(
456e5dd7070Spatrick         FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr)
457e5dd7070Spatrick         : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr) {}
458e5dd7070Spatrick 
459e5dd7070Spatrick     /// Load the contents of the given module file into the builder.
460e5dd7070Spatrick     llvm::Error loadModuleFile(const FileEntry *File);
461e5dd7070Spatrick 
462e5dd7070Spatrick     /// Write the index to the given bitstream.
463e5dd7070Spatrick     /// \returns true if an error occurred, false otherwise.
464e5dd7070Spatrick     bool writeIndex(llvm::BitstreamWriter &Stream);
465e5dd7070Spatrick   };
466e5dd7070Spatrick }
467e5dd7070Spatrick 
emitBlockID(unsigned ID,const char * Name,llvm::BitstreamWriter & Stream,SmallVectorImpl<uint64_t> & Record)468e5dd7070Spatrick static void emitBlockID(unsigned ID, const char *Name,
469e5dd7070Spatrick                         llvm::BitstreamWriter &Stream,
470e5dd7070Spatrick                         SmallVectorImpl<uint64_t> &Record) {
471e5dd7070Spatrick   Record.clear();
472e5dd7070Spatrick   Record.push_back(ID);
473e5dd7070Spatrick   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
474e5dd7070Spatrick 
475e5dd7070Spatrick   // Emit the block name if present.
476e5dd7070Spatrick   if (!Name || Name[0] == 0) return;
477e5dd7070Spatrick   Record.clear();
478e5dd7070Spatrick   while (*Name)
479e5dd7070Spatrick     Record.push_back(*Name++);
480e5dd7070Spatrick   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
481e5dd7070Spatrick }
482e5dd7070Spatrick 
emitRecordID(unsigned ID,const char * Name,llvm::BitstreamWriter & Stream,SmallVectorImpl<uint64_t> & Record)483e5dd7070Spatrick static void emitRecordID(unsigned ID, const char *Name,
484e5dd7070Spatrick                          llvm::BitstreamWriter &Stream,
485e5dd7070Spatrick                          SmallVectorImpl<uint64_t> &Record) {
486e5dd7070Spatrick   Record.clear();
487e5dd7070Spatrick   Record.push_back(ID);
488e5dd7070Spatrick   while (*Name)
489e5dd7070Spatrick     Record.push_back(*Name++);
490e5dd7070Spatrick   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
491e5dd7070Spatrick }
492e5dd7070Spatrick 
493e5dd7070Spatrick void
emitBlockInfoBlock(llvm::BitstreamWriter & Stream)494e5dd7070Spatrick GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) {
495e5dd7070Spatrick   SmallVector<uint64_t, 64> Record;
496e5dd7070Spatrick   Stream.EnterBlockInfoBlock();
497e5dd7070Spatrick 
498e5dd7070Spatrick #define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
499e5dd7070Spatrick #define RECORD(X) emitRecordID(X, #X, Stream, Record)
500e5dd7070Spatrick   BLOCK(GLOBAL_INDEX_BLOCK);
501e5dd7070Spatrick   RECORD(INDEX_METADATA);
502e5dd7070Spatrick   RECORD(MODULE);
503e5dd7070Spatrick   RECORD(IDENTIFIER_INDEX);
504e5dd7070Spatrick #undef RECORD
505e5dd7070Spatrick #undef BLOCK
506e5dd7070Spatrick 
507e5dd7070Spatrick   Stream.ExitBlock();
508e5dd7070Spatrick }
509e5dd7070Spatrick 
510e5dd7070Spatrick namespace {
511e5dd7070Spatrick   class InterestingASTIdentifierLookupTrait
512e5dd7070Spatrick     : public serialization::reader::ASTIdentifierLookupTraitBase {
513e5dd7070Spatrick 
514e5dd7070Spatrick   public:
515e5dd7070Spatrick     /// The identifier and whether it is "interesting".
516e5dd7070Spatrick     typedef std::pair<StringRef, bool> data_type;
517e5dd7070Spatrick 
ReadData(const internal_key_type & k,const unsigned char * d,unsigned DataLen)518e5dd7070Spatrick     data_type ReadData(const internal_key_type& k,
519e5dd7070Spatrick                        const unsigned char* d,
520e5dd7070Spatrick                        unsigned DataLen) {
521e5dd7070Spatrick       // The first bit indicates whether this identifier is interesting.
522e5dd7070Spatrick       // That's all we care about.
523e5dd7070Spatrick       using namespace llvm::support;
524e5dd7070Spatrick       unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d);
525e5dd7070Spatrick       bool IsInteresting = RawID & 0x01;
526e5dd7070Spatrick       return std::make_pair(k, IsInteresting);
527e5dd7070Spatrick     }
528e5dd7070Spatrick   };
529e5dd7070Spatrick }
530e5dd7070Spatrick 
loadModuleFile(const FileEntry * File)531e5dd7070Spatrick llvm::Error GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
532e5dd7070Spatrick   // Open the module file.
533e5dd7070Spatrick 
534e5dd7070Spatrick   auto Buffer = FileMgr.getBufferForFile(File, /*isVolatile=*/true);
535e5dd7070Spatrick   if (!Buffer)
536e5dd7070Spatrick     return llvm::createStringError(Buffer.getError(),
537e5dd7070Spatrick                                    "failed getting buffer for module file");
538e5dd7070Spatrick 
539e5dd7070Spatrick   // Initialize the input stream
540e5dd7070Spatrick   llvm::BitstreamCursor InStream(PCHContainerRdr.ExtractPCH(**Buffer));
541e5dd7070Spatrick 
542e5dd7070Spatrick   // Sniff for the signature.
543e5dd7070Spatrick   for (unsigned char C : {'C', 'P', 'C', 'H'})
544e5dd7070Spatrick     if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = InStream.Read(8)) {
545e5dd7070Spatrick       if (Res.get() != C)
546e5dd7070Spatrick         return llvm::createStringError(std::errc::illegal_byte_sequence,
547e5dd7070Spatrick                                        "expected signature CPCH");
548e5dd7070Spatrick     } else
549e5dd7070Spatrick       return Res.takeError();
550e5dd7070Spatrick 
551e5dd7070Spatrick   // Record this module file and assign it a unique ID (if it doesn't have
552e5dd7070Spatrick   // one already).
553e5dd7070Spatrick   unsigned ID = getModuleFileInfo(File).ID;
554e5dd7070Spatrick 
555e5dd7070Spatrick   // Search for the blocks and records we care about.
556e5dd7070Spatrick   enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other;
557e5dd7070Spatrick   bool Done = false;
558e5dd7070Spatrick   while (!Done) {
559e5dd7070Spatrick     Expected<llvm::BitstreamEntry> MaybeEntry = InStream.advance();
560e5dd7070Spatrick     if (!MaybeEntry)
561e5dd7070Spatrick       return MaybeEntry.takeError();
562e5dd7070Spatrick     llvm::BitstreamEntry Entry = MaybeEntry.get();
563e5dd7070Spatrick 
564e5dd7070Spatrick     switch (Entry.Kind) {
565e5dd7070Spatrick     case llvm::BitstreamEntry::Error:
566e5dd7070Spatrick       Done = true;
567e5dd7070Spatrick       continue;
568e5dd7070Spatrick 
569e5dd7070Spatrick     case llvm::BitstreamEntry::Record:
570e5dd7070Spatrick       // In the 'other' state, just skip the record. We don't care.
571e5dd7070Spatrick       if (State == Other) {
572e5dd7070Spatrick         if (llvm::Expected<unsigned> Skipped = InStream.skipRecord(Entry.ID))
573e5dd7070Spatrick           continue;
574e5dd7070Spatrick         else
575e5dd7070Spatrick           return Skipped.takeError();
576e5dd7070Spatrick       }
577e5dd7070Spatrick 
578e5dd7070Spatrick       // Handle potentially-interesting records below.
579e5dd7070Spatrick       break;
580e5dd7070Spatrick 
581e5dd7070Spatrick     case llvm::BitstreamEntry::SubBlock:
582e5dd7070Spatrick       if (Entry.ID == CONTROL_BLOCK_ID) {
583e5dd7070Spatrick         if (llvm::Error Err = InStream.EnterSubBlock(CONTROL_BLOCK_ID))
584e5dd7070Spatrick           return Err;
585e5dd7070Spatrick 
586e5dd7070Spatrick         // Found the control block.
587e5dd7070Spatrick         State = ControlBlock;
588e5dd7070Spatrick         continue;
589e5dd7070Spatrick       }
590e5dd7070Spatrick 
591e5dd7070Spatrick       if (Entry.ID == AST_BLOCK_ID) {
592e5dd7070Spatrick         if (llvm::Error Err = InStream.EnterSubBlock(AST_BLOCK_ID))
593e5dd7070Spatrick           return Err;
594e5dd7070Spatrick 
595e5dd7070Spatrick         // Found the AST block.
596e5dd7070Spatrick         State = ASTBlock;
597e5dd7070Spatrick         continue;
598e5dd7070Spatrick       }
599e5dd7070Spatrick 
600e5dd7070Spatrick       if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) {
601e5dd7070Spatrick         if (llvm::Error Err = InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID))
602e5dd7070Spatrick           return Err;
603e5dd7070Spatrick 
604e5dd7070Spatrick         // Found the Diagnostic Options block.
605e5dd7070Spatrick         State = DiagnosticOptionsBlock;
606e5dd7070Spatrick         continue;
607e5dd7070Spatrick       }
608e5dd7070Spatrick 
609e5dd7070Spatrick       if (llvm::Error Err = InStream.SkipBlock())
610e5dd7070Spatrick         return Err;
611e5dd7070Spatrick 
612e5dd7070Spatrick       continue;
613e5dd7070Spatrick 
614e5dd7070Spatrick     case llvm::BitstreamEntry::EndBlock:
615e5dd7070Spatrick       State = Other;
616e5dd7070Spatrick       continue;
617e5dd7070Spatrick     }
618e5dd7070Spatrick 
619e5dd7070Spatrick     // Read the given record.
620e5dd7070Spatrick     SmallVector<uint64_t, 64> Record;
621e5dd7070Spatrick     StringRef Blob;
622e5dd7070Spatrick     Expected<unsigned> MaybeCode = InStream.readRecord(Entry.ID, Record, &Blob);
623e5dd7070Spatrick     if (!MaybeCode)
624e5dd7070Spatrick       return MaybeCode.takeError();
625e5dd7070Spatrick     unsigned Code = MaybeCode.get();
626e5dd7070Spatrick 
627e5dd7070Spatrick     // Handle module dependencies.
628e5dd7070Spatrick     if (State == ControlBlock && Code == IMPORTS) {
629e5dd7070Spatrick       // Load each of the imported PCH files.
630e5dd7070Spatrick       unsigned Idx = 0, N = Record.size();
631e5dd7070Spatrick       while (Idx < N) {
632e5dd7070Spatrick         // Read information about the AST file.
633e5dd7070Spatrick 
634e5dd7070Spatrick         // Skip the imported kind
635e5dd7070Spatrick         ++Idx;
636e5dd7070Spatrick 
637e5dd7070Spatrick         // Skip the import location
638e5dd7070Spatrick         ++Idx;
639e5dd7070Spatrick 
640e5dd7070Spatrick         // Load stored size/modification time.
641e5dd7070Spatrick         off_t StoredSize = (off_t)Record[Idx++];
642e5dd7070Spatrick         time_t StoredModTime = (time_t)Record[Idx++];
643e5dd7070Spatrick 
644e5dd7070Spatrick         // Skip the stored signature.
645e5dd7070Spatrick         // FIXME: we could read the signature out of the import and validate it.
646ec727ea7Spatrick         auto FirstSignatureByte = Record.begin() + Idx;
647ec727ea7Spatrick         ASTFileSignature StoredSignature = ASTFileSignature::create(
648ec727ea7Spatrick             FirstSignatureByte, FirstSignatureByte + ASTFileSignature::size);
649ec727ea7Spatrick         Idx += ASTFileSignature::size;
650e5dd7070Spatrick 
651e5dd7070Spatrick         // Skip the module name (currently this is only used for prebuilt
652e5dd7070Spatrick         // modules while here we are only dealing with cached).
653e5dd7070Spatrick         Idx += Record[Idx] + 1;
654e5dd7070Spatrick 
655e5dd7070Spatrick         // Retrieve the imported file name.
656e5dd7070Spatrick         unsigned Length = Record[Idx++];
657e5dd7070Spatrick         SmallString<128> ImportedFile(Record.begin() + Idx,
658e5dd7070Spatrick                                       Record.begin() + Idx + Length);
659e5dd7070Spatrick         Idx += Length;
660e5dd7070Spatrick 
661e5dd7070Spatrick         // Find the imported module file.
662e5dd7070Spatrick         auto DependsOnFile
663e5dd7070Spatrick           = FileMgr.getFile(ImportedFile, /*OpenFile=*/false,
664e5dd7070Spatrick                             /*CacheFailure=*/false);
665e5dd7070Spatrick 
666e5dd7070Spatrick         if (!DependsOnFile)
667e5dd7070Spatrick           return llvm::createStringError(std::errc::bad_file_descriptor,
668e5dd7070Spatrick                                          "imported file \"%s\" not found",
669e5dd7070Spatrick                                          ImportedFile.c_str());
670e5dd7070Spatrick 
671e5dd7070Spatrick         // Save the information in ImportedModuleFileInfo so we can verify after
672e5dd7070Spatrick         // loading all pcms.
673e5dd7070Spatrick         ImportedModuleFiles.insert(std::make_pair(
674e5dd7070Spatrick             *DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
675e5dd7070Spatrick                                                    StoredSignature)));
676e5dd7070Spatrick 
677e5dd7070Spatrick         // Record the dependency.
678e5dd7070Spatrick         unsigned DependsOnID = getModuleFileInfo(*DependsOnFile).ID;
679e5dd7070Spatrick         getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
680e5dd7070Spatrick       }
681e5dd7070Spatrick 
682e5dd7070Spatrick       continue;
683e5dd7070Spatrick     }
684e5dd7070Spatrick 
685e5dd7070Spatrick     // Handle the identifier table
686e5dd7070Spatrick     if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {
687e5dd7070Spatrick       typedef llvm::OnDiskIterableChainedHashTable<
688e5dd7070Spatrick           InterestingASTIdentifierLookupTrait> InterestingIdentifierTable;
689e5dd7070Spatrick       std::unique_ptr<InterestingIdentifierTable> Table(
690e5dd7070Spatrick           InterestingIdentifierTable::Create(
691e5dd7070Spatrick               (const unsigned char *)Blob.data() + Record[0],
692e5dd7070Spatrick               (const unsigned char *)Blob.data() + sizeof(uint32_t),
693e5dd7070Spatrick               (const unsigned char *)Blob.data()));
694e5dd7070Spatrick       for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
695e5dd7070Spatrick                                                      DEnd = Table->data_end();
696e5dd7070Spatrick            D != DEnd; ++D) {
697e5dd7070Spatrick         std::pair<StringRef, bool> Ident = *D;
698e5dd7070Spatrick         if (Ident.second)
699e5dd7070Spatrick           InterestingIdentifiers[Ident.first].push_back(ID);
700e5dd7070Spatrick         else
701e5dd7070Spatrick           (void)InterestingIdentifiers[Ident.first];
702e5dd7070Spatrick       }
703e5dd7070Spatrick     }
704e5dd7070Spatrick 
705e5dd7070Spatrick     // Get Signature.
706e5dd7070Spatrick     if (State == DiagnosticOptionsBlock && Code == SIGNATURE)
707ec727ea7Spatrick       getModuleFileInfo(File).Signature = ASTFileSignature::create(
708ec727ea7Spatrick           Record.begin(), Record.begin() + ASTFileSignature::size);
709e5dd7070Spatrick 
710e5dd7070Spatrick     // We don't care about this record.
711e5dd7070Spatrick   }
712e5dd7070Spatrick 
713e5dd7070Spatrick   return llvm::Error::success();
714e5dd7070Spatrick }
715e5dd7070Spatrick 
716e5dd7070Spatrick namespace {
717e5dd7070Spatrick 
718e5dd7070Spatrick /// Trait used to generate the identifier index as an on-disk hash
719e5dd7070Spatrick /// table.
720e5dd7070Spatrick class IdentifierIndexWriterTrait {
721e5dd7070Spatrick public:
722e5dd7070Spatrick   typedef StringRef key_type;
723e5dd7070Spatrick   typedef StringRef key_type_ref;
724e5dd7070Spatrick   typedef SmallVector<unsigned, 2> data_type;
725e5dd7070Spatrick   typedef const SmallVector<unsigned, 2> &data_type_ref;
726e5dd7070Spatrick   typedef unsigned hash_value_type;
727e5dd7070Spatrick   typedef unsigned offset_type;
728e5dd7070Spatrick 
ComputeHash(key_type_ref Key)729e5dd7070Spatrick   static hash_value_type ComputeHash(key_type_ref Key) {
730e5dd7070Spatrick     return llvm::djbHash(Key);
731e5dd7070Spatrick   }
732e5dd7070Spatrick 
733e5dd7070Spatrick   std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream & Out,key_type_ref Key,data_type_ref Data)734e5dd7070Spatrick   EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) {
735e5dd7070Spatrick     using namespace llvm::support;
736e5dd7070Spatrick     endian::Writer LE(Out, little);
737e5dd7070Spatrick     unsigned KeyLen = Key.size();
738e5dd7070Spatrick     unsigned DataLen = Data.size() * 4;
739e5dd7070Spatrick     LE.write<uint16_t>(KeyLen);
740e5dd7070Spatrick     LE.write<uint16_t>(DataLen);
741e5dd7070Spatrick     return std::make_pair(KeyLen, DataLen);
742e5dd7070Spatrick   }
743e5dd7070Spatrick 
EmitKey(raw_ostream & Out,key_type_ref Key,unsigned KeyLen)744e5dd7070Spatrick   void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
745e5dd7070Spatrick     Out.write(Key.data(), KeyLen);
746e5dd7070Spatrick   }
747e5dd7070Spatrick 
EmitData(raw_ostream & Out,key_type_ref Key,data_type_ref Data,unsigned DataLen)748e5dd7070Spatrick   void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
749e5dd7070Spatrick                 unsigned DataLen) {
750e5dd7070Spatrick     using namespace llvm::support;
751e5dd7070Spatrick     for (unsigned I = 0, N = Data.size(); I != N; ++I)
752e5dd7070Spatrick       endian::write<uint32_t>(Out, Data[I], little);
753e5dd7070Spatrick   }
754e5dd7070Spatrick };
755e5dd7070Spatrick 
756e5dd7070Spatrick }
757e5dd7070Spatrick 
writeIndex(llvm::BitstreamWriter & Stream)758e5dd7070Spatrick bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
759e5dd7070Spatrick   for (auto MapEntry : ImportedModuleFiles) {
760e5dd7070Spatrick     auto *File = MapEntry.first;
761e5dd7070Spatrick     ImportedModuleFileInfo &Info = MapEntry.second;
762e5dd7070Spatrick     if (getModuleFileInfo(File).Signature) {
763e5dd7070Spatrick       if (getModuleFileInfo(File).Signature != Info.StoredSignature)
764e5dd7070Spatrick         // Verify Signature.
765e5dd7070Spatrick         return true;
766e5dd7070Spatrick     } else if (Info.StoredSize != File->getSize() ||
767e5dd7070Spatrick                Info.StoredModTime != File->getModificationTime())
768e5dd7070Spatrick       // Verify Size and ModTime.
769e5dd7070Spatrick       return true;
770e5dd7070Spatrick   }
771e5dd7070Spatrick 
772e5dd7070Spatrick   using namespace llvm;
773e5dd7070Spatrick   llvm::TimeTraceScope TimeScope("Module WriteIndex");
774e5dd7070Spatrick 
775e5dd7070Spatrick   // Emit the file header.
776e5dd7070Spatrick   Stream.Emit((unsigned)'B', 8);
777e5dd7070Spatrick   Stream.Emit((unsigned)'C', 8);
778e5dd7070Spatrick   Stream.Emit((unsigned)'G', 8);
779e5dd7070Spatrick   Stream.Emit((unsigned)'I', 8);
780e5dd7070Spatrick 
781e5dd7070Spatrick   // Write the block-info block, which describes the records in this bitcode
782e5dd7070Spatrick   // file.
783e5dd7070Spatrick   emitBlockInfoBlock(Stream);
784e5dd7070Spatrick 
785e5dd7070Spatrick   Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);
786e5dd7070Spatrick 
787e5dd7070Spatrick   // Write the metadata.
788e5dd7070Spatrick   SmallVector<uint64_t, 2> Record;
789e5dd7070Spatrick   Record.push_back(CurrentVersion);
790e5dd7070Spatrick   Stream.EmitRecord(INDEX_METADATA, Record);
791e5dd7070Spatrick 
792e5dd7070Spatrick   // Write the set of known module files.
793e5dd7070Spatrick   for (ModuleFilesMap::iterator M = ModuleFiles.begin(),
794e5dd7070Spatrick                                 MEnd = ModuleFiles.end();
795e5dd7070Spatrick        M != MEnd; ++M) {
796e5dd7070Spatrick     Record.clear();
797e5dd7070Spatrick     Record.push_back(M->second.ID);
798e5dd7070Spatrick     Record.push_back(M->first->getSize());
799e5dd7070Spatrick     Record.push_back(M->first->getModificationTime());
800e5dd7070Spatrick 
801e5dd7070Spatrick     // File name
802e5dd7070Spatrick     StringRef Name(M->first->getName());
803e5dd7070Spatrick     Record.push_back(Name.size());
804e5dd7070Spatrick     Record.append(Name.begin(), Name.end());
805e5dd7070Spatrick 
806e5dd7070Spatrick     // Dependencies
807e5dd7070Spatrick     Record.push_back(M->second.Dependencies.size());
808e5dd7070Spatrick     Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());
809e5dd7070Spatrick     Stream.EmitRecord(MODULE, Record);
810e5dd7070Spatrick   }
811e5dd7070Spatrick 
812e5dd7070Spatrick   // Write the identifier -> module file mapping.
813e5dd7070Spatrick   {
814e5dd7070Spatrick     llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
815e5dd7070Spatrick     IdentifierIndexWriterTrait Trait;
816e5dd7070Spatrick 
817e5dd7070Spatrick     // Populate the hash table.
818e5dd7070Spatrick     for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),
819e5dd7070Spatrick                                             IEnd = InterestingIdentifiers.end();
820e5dd7070Spatrick          I != IEnd; ++I) {
821e5dd7070Spatrick       Generator.insert(I->first(), I->second, Trait);
822e5dd7070Spatrick     }
823e5dd7070Spatrick 
824e5dd7070Spatrick     // Create the on-disk hash table in a buffer.
825e5dd7070Spatrick     SmallString<4096> IdentifierTable;
826e5dd7070Spatrick     uint32_t BucketOffset;
827e5dd7070Spatrick     {
828e5dd7070Spatrick       using namespace llvm::support;
829e5dd7070Spatrick       llvm::raw_svector_ostream Out(IdentifierTable);
830e5dd7070Spatrick       // Make sure that no bucket is at offset 0
831e5dd7070Spatrick       endian::write<uint32_t>(Out, 0, little);
832e5dd7070Spatrick       BucketOffset = Generator.Emit(Out, Trait);
833e5dd7070Spatrick     }
834e5dd7070Spatrick 
835e5dd7070Spatrick     // Create a blob abbreviation
836e5dd7070Spatrick     auto Abbrev = std::make_shared<BitCodeAbbrev>();
837e5dd7070Spatrick     Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX));
838e5dd7070Spatrick     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
839e5dd7070Spatrick     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
840e5dd7070Spatrick     unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
841e5dd7070Spatrick 
842e5dd7070Spatrick     // Write the identifier table
843e5dd7070Spatrick     uint64_t Record[] = {IDENTIFIER_INDEX, BucketOffset};
844e5dd7070Spatrick     Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable);
845e5dd7070Spatrick   }
846e5dd7070Spatrick 
847e5dd7070Spatrick   Stream.ExitBlock();
848e5dd7070Spatrick   return false;
849e5dd7070Spatrick }
850e5dd7070Spatrick 
851e5dd7070Spatrick llvm::Error
writeIndex(FileManager & FileMgr,const PCHContainerReader & PCHContainerRdr,StringRef Path)852e5dd7070Spatrick GlobalModuleIndex::writeIndex(FileManager &FileMgr,
853e5dd7070Spatrick                               const PCHContainerReader &PCHContainerRdr,
854e5dd7070Spatrick                               StringRef Path) {
855e5dd7070Spatrick   llvm::SmallString<128> IndexPath;
856e5dd7070Spatrick   IndexPath += Path;
857e5dd7070Spatrick   llvm::sys::path::append(IndexPath, IndexFileName);
858e5dd7070Spatrick 
859e5dd7070Spatrick   // Coordinate building the global index file with other processes that might
860e5dd7070Spatrick   // try to do the same.
861e5dd7070Spatrick   llvm::LockFileManager Locked(IndexPath);
862e5dd7070Spatrick   switch (Locked) {
863e5dd7070Spatrick   case llvm::LockFileManager::LFS_Error:
864e5dd7070Spatrick     return llvm::createStringError(std::errc::io_error, "LFS error");
865e5dd7070Spatrick 
866e5dd7070Spatrick   case llvm::LockFileManager::LFS_Owned:
867e5dd7070Spatrick     // We're responsible for building the index ourselves. Do so below.
868e5dd7070Spatrick     break;
869e5dd7070Spatrick 
870e5dd7070Spatrick   case llvm::LockFileManager::LFS_Shared:
871e5dd7070Spatrick     // Someone else is responsible for building the index. We don't care
872e5dd7070Spatrick     // when they finish, so we're done.
873e5dd7070Spatrick     return llvm::createStringError(std::errc::device_or_resource_busy,
874e5dd7070Spatrick                                    "someone else is building the index");
875e5dd7070Spatrick   }
876e5dd7070Spatrick 
877e5dd7070Spatrick   // The module index builder.
878e5dd7070Spatrick   GlobalModuleIndexBuilder Builder(FileMgr, PCHContainerRdr);
879e5dd7070Spatrick 
880e5dd7070Spatrick   // Load each of the module files.
881e5dd7070Spatrick   std::error_code EC;
882e5dd7070Spatrick   for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
883e5dd7070Spatrick        D != DEnd && !EC;
884e5dd7070Spatrick        D.increment(EC)) {
885e5dd7070Spatrick     // If this isn't a module file, we don't care.
886e5dd7070Spatrick     if (llvm::sys::path::extension(D->path()) != ".pcm") {
887e5dd7070Spatrick       // ... unless it's a .pcm.lock file, which indicates that someone is
888e5dd7070Spatrick       // in the process of rebuilding a module. They'll rebuild the index
889e5dd7070Spatrick       // at the end of that translation unit, so we don't have to.
890e5dd7070Spatrick       if (llvm::sys::path::extension(D->path()) == ".pcm.lock")
891e5dd7070Spatrick         return llvm::createStringError(std::errc::device_or_resource_busy,
892e5dd7070Spatrick                                        "someone else is building the index");
893e5dd7070Spatrick 
894e5dd7070Spatrick       continue;
895e5dd7070Spatrick     }
896e5dd7070Spatrick 
897e5dd7070Spatrick     // If we can't find the module file, skip it.
898e5dd7070Spatrick     auto ModuleFile = FileMgr.getFile(D->path());
899e5dd7070Spatrick     if (!ModuleFile)
900e5dd7070Spatrick       continue;
901e5dd7070Spatrick 
902e5dd7070Spatrick     // Load this module file.
903e5dd7070Spatrick     if (llvm::Error Err = Builder.loadModuleFile(*ModuleFile))
904e5dd7070Spatrick       return Err;
905e5dd7070Spatrick   }
906e5dd7070Spatrick 
907e5dd7070Spatrick   // The output buffer, into which the global index will be written.
908a9ac8606Spatrick   SmallString<16> OutputBuffer;
909e5dd7070Spatrick   {
910e5dd7070Spatrick     llvm::BitstreamWriter OutputStream(OutputBuffer);
911e5dd7070Spatrick     if (Builder.writeIndex(OutputStream))
912e5dd7070Spatrick       return llvm::createStringError(std::errc::io_error,
913e5dd7070Spatrick                                      "failed writing index");
914e5dd7070Spatrick   }
915e5dd7070Spatrick 
916a9ac8606Spatrick   return llvm::writeFileAtomically((IndexPath + "-%%%%%%%%").str(), IndexPath,
917a9ac8606Spatrick                                    OutputBuffer);
918e5dd7070Spatrick }
919e5dd7070Spatrick 
920e5dd7070Spatrick namespace {
921e5dd7070Spatrick   class GlobalIndexIdentifierIterator : public IdentifierIterator {
922e5dd7070Spatrick     /// The current position within the identifier lookup table.
923e5dd7070Spatrick     IdentifierIndexTable::key_iterator Current;
924e5dd7070Spatrick 
925e5dd7070Spatrick     /// The end position within the identifier lookup table.
926e5dd7070Spatrick     IdentifierIndexTable::key_iterator End;
927e5dd7070Spatrick 
928e5dd7070Spatrick   public:
GlobalIndexIdentifierIterator(IdentifierIndexTable & Idx)929e5dd7070Spatrick     explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) {
930e5dd7070Spatrick       Current = Idx.key_begin();
931e5dd7070Spatrick       End = Idx.key_end();
932e5dd7070Spatrick     }
933e5dd7070Spatrick 
Next()934e5dd7070Spatrick     StringRef Next() override {
935e5dd7070Spatrick       if (Current == End)
936e5dd7070Spatrick         return StringRef();
937e5dd7070Spatrick 
938e5dd7070Spatrick       StringRef Result = *Current;
939e5dd7070Spatrick       ++Current;
940e5dd7070Spatrick       return Result;
941e5dd7070Spatrick     }
942e5dd7070Spatrick   };
943e5dd7070Spatrick }
944e5dd7070Spatrick 
createIdentifierIterator() const945e5dd7070Spatrick IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const {
946e5dd7070Spatrick   IdentifierIndexTable &Table =
947e5dd7070Spatrick     *static_cast<IdentifierIndexTable *>(IdentifierIndex);
948e5dd7070Spatrick   return new GlobalIndexIdentifierIterator(Table);
949e5dd7070Spatrick }
950