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