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