1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "ASTReaderInternals.h" |
14 | #include "clang/Basic/FileManager.h" |
15 | #include "clang/Lex/HeaderSearch.h" |
16 | #include "clang/Serialization/ASTBitCodes.h" |
17 | #include "clang/Serialization/GlobalModuleIndex.h" |
18 | #include "clang/Serialization/Module.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/Bitcode/BitstreamReader.h" |
24 | #include "llvm/Bitcode/BitstreamWriter.h" |
25 | #include "llvm/Support/DJB.h" |
26 | #include "llvm/Support/FileSystem.h" |
27 | #include "llvm/Support/LockFileManager.h" |
28 | #include "llvm/Support/MemoryBuffer.h" |
29 | #include "llvm/Support/OnDiskHashTable.h" |
30 | #include "llvm/Support/Path.h" |
31 | #include <cstdio> |
32 | using namespace clang; |
33 | using namespace serialization; |
34 | |
35 | |
36 | |
37 | |
38 | namespace { |
39 | enum { |
40 | |
41 | GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID |
42 | }; |
43 | |
44 | |
45 | enum IndexRecordTypes { |
46 | |
47 | |
48 | INDEX_METADATA, |
49 | |
50 | MODULE, |
51 | |
52 | IDENTIFIER_INDEX |
53 | }; |
54 | } |
55 | |
56 | |
57 | static const char * const IndexFileName = "modules.idx"; |
58 | |
59 | |
60 | static const unsigned CurrentVersion = 1; |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | namespace { |
67 | |
68 | |
69 | |
70 | class IdentifierIndexReaderTrait { |
71 | public: |
72 | typedef StringRef external_key_type; |
73 | typedef StringRef internal_key_type; |
74 | typedef SmallVector<unsigned, 2> data_type; |
75 | typedef unsigned hash_value_type; |
76 | typedef unsigned offset_type; |
77 | |
78 | static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { |
79 | return a == b; |
80 | } |
81 | |
82 | static hash_value_type ComputeHash(const internal_key_type& a) { |
83 | return llvm::djbHash(a); |
84 | } |
85 | |
86 | static std::pair<unsigned, unsigned> |
87 | ReadKeyDataLength(const unsigned char*& d) { |
88 | using namespace llvm::support; |
89 | unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d); |
90 | unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d); |
91 | return std::make_pair(KeyLen, DataLen); |
92 | } |
93 | |
94 | static const internal_key_type& |
95 | GetInternalKey(const external_key_type& x) { return x; } |
96 | |
97 | static const external_key_type& |
98 | GetExternalKey(const internal_key_type& x) { return x; } |
99 | |
100 | static internal_key_type ReadKey(const unsigned char* d, unsigned n) { |
101 | return StringRef((const char *)d, n); |
102 | } |
103 | |
104 | static data_type ReadData(const internal_key_type& k, |
105 | const unsigned char* d, |
106 | unsigned DataLen) { |
107 | using namespace llvm::support; |
108 | |
109 | data_type Result; |
110 | while (DataLen > 0) { |
111 | unsigned ID = endian::readNext<uint32_t, little, unaligned>(d); |
112 | Result.push_back(ID); |
113 | DataLen -= 4; |
114 | } |
115 | |
116 | return Result; |
117 | } |
118 | }; |
119 | |
120 | typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait> |
121 | IdentifierIndexTable; |
122 | |
123 | } |
124 | |
125 | GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer, |
126 | llvm::BitstreamCursor Cursor) |
127 | : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(), |
128 | NumIdentifierLookupHits() { |
129 | |
130 | bool InGlobalIndexBlock = false; |
131 | bool Done = false; |
132 | while (!Done) { |
133 | llvm::BitstreamEntry Entry = Cursor.advance(); |
134 | |
135 | switch (Entry.Kind) { |
136 | case llvm::BitstreamEntry::Error: |
137 | return; |
138 | |
139 | case llvm::BitstreamEntry::EndBlock: |
140 | if (InGlobalIndexBlock) { |
141 | InGlobalIndexBlock = false; |
142 | Done = true; |
143 | continue; |
144 | } |
145 | return; |
146 | |
147 | |
148 | case llvm::BitstreamEntry::Record: |
149 | |
150 | if (InGlobalIndexBlock) |
151 | break; |
152 | |
153 | return; |
154 | |
155 | case llvm::BitstreamEntry::SubBlock: |
156 | if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { |
157 | if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) |
158 | return; |
159 | |
160 | InGlobalIndexBlock = true; |
161 | } else if (Cursor.SkipBlock()) { |
162 | return; |
163 | } |
164 | continue; |
165 | } |
166 | |
167 | SmallVector<uint64_t, 64> Record; |
168 | StringRef Blob; |
169 | switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) { |
170 | case INDEX_METADATA: |
171 | |
172 | if (Record.size() < 1 || Record[0] != CurrentVersion) |
173 | return; |
174 | break; |
175 | |
176 | case MODULE: { |
177 | unsigned Idx = 0; |
178 | unsigned ID = Record[Idx++]; |
179 | |
180 | |
181 | if (ID == Modules.size()) |
182 | Modules.push_back(ModuleInfo()); |
183 | else |
184 | Modules.resize(ID + 1); |
185 | |
186 | |
187 | |
188 | Modules[ID].Size = Record[Idx++]; |
189 | Modules[ID].ModTime = Record[Idx++]; |
190 | |
191 | |
192 | unsigned NameLen = Record[Idx++]; |
193 | Modules[ID].FileName.assign(Record.begin() + Idx, |
194 | Record.begin() + Idx + NameLen); |
195 | Idx += NameLen; |
196 | |
197 | |
198 | unsigned NumDeps = Record[Idx++]; |
199 | Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(), |
200 | Record.begin() + Idx, |
201 | Record.begin() + Idx + NumDeps); |
202 | Idx += NumDeps; |
203 | |
204 | |
205 | (0) . __assert_fail ("Idx == Record.size() && \"More module info?\"", "/home/seafit/code_projects/clang_source/clang/lib/Serialization/GlobalModuleIndex.cpp", 205, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Idx == Record.size() && "More module info?"); |
206 | |
207 | |
208 | |
209 | |
210 | StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName); |
211 | |
212 | ModuleName = ModuleName.rsplit('-').first; |
213 | UnresolvedModules[ModuleName] = ID; |
214 | break; |
215 | } |
216 | |
217 | case IDENTIFIER_INDEX: |
218 | |
219 | if (Record[0]) { |
220 | IdentifierIndex = IdentifierIndexTable::Create( |
221 | (const unsigned char *)Blob.data() + Record[0], |
222 | (const unsigned char *)Blob.data() + sizeof(uint32_t), |
223 | (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait()); |
224 | } |
225 | break; |
226 | } |
227 | } |
228 | } |
229 | |
230 | GlobalModuleIndex::~GlobalModuleIndex() { |
231 | delete static_cast<IdentifierIndexTable *>(IdentifierIndex); |
232 | } |
233 | |
234 | std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> |
235 | GlobalModuleIndex::readIndex(StringRef Path) { |
236 | |
237 | llvm::SmallString<128> IndexPath; |
238 | IndexPath += Path; |
239 | llvm::sys::path::append(IndexPath, IndexFileName); |
240 | |
241 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr = |
242 | llvm::MemoryBuffer::getFile(IndexPath.c_str()); |
243 | if (!BufferOrErr) |
244 | return std::make_pair(nullptr, EC_NotFound); |
245 | std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get()); |
246 | |
247 | |
248 | llvm::BitstreamCursor Cursor(*Buffer); |
249 | |
250 | |
251 | if (Cursor.Read(8) != 'B' || |
252 | Cursor.Read(8) != 'C' || |
253 | Cursor.Read(8) != 'G' || |
254 | Cursor.Read(8) != 'I') { |
255 | return std::make_pair(nullptr, EC_IOError); |
256 | } |
257 | |
258 | return std::make_pair(new GlobalModuleIndex(std::move(Buffer), Cursor), |
259 | EC_None); |
260 | } |
261 | |
262 | void |
263 | GlobalModuleIndex::getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles) { |
264 | ModuleFiles.clear(); |
265 | for (unsigned I = 0, N = Modules.size(); I != N; ++I) { |
266 | if (ModuleFile *MF = Modules[I].File) |
267 | ModuleFiles.push_back(MF); |
268 | } |
269 | } |
270 | |
271 | void GlobalModuleIndex::getModuleDependencies( |
272 | ModuleFile *File, |
273 | SmallVectorImpl<ModuleFile *> &Dependencies) { |
274 | |
275 | llvm::DenseMap<ModuleFile *, unsigned>::iterator Known |
276 | = ModulesByFile.find(File); |
277 | if (Known == ModulesByFile.end()) |
278 | return; |
279 | |
280 | |
281 | Dependencies.clear(); |
282 | ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies; |
283 | for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) { |
284 | if (ModuleFile *MF = Modules[I].File) |
285 | Dependencies.push_back(MF); |
286 | } |
287 | } |
288 | |
289 | bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) { |
290 | Hits.clear(); |
291 | |
292 | |
293 | if (!IdentifierIndex) |
294 | return false; |
295 | |
296 | |
297 | ++NumIdentifierLookups; |
298 | IdentifierIndexTable &Table |
299 | = *static_cast<IdentifierIndexTable *>(IdentifierIndex); |
300 | IdentifierIndexTable::iterator Known = Table.find(Name); |
301 | if (Known == Table.end()) { |
302 | return true; |
303 | } |
304 | |
305 | SmallVector<unsigned, 2> ModuleIDs = *Known; |
306 | for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) { |
307 | if (ModuleFile *MF = Modules[ModuleIDs[I]].File) |
308 | Hits.insert(MF); |
309 | } |
310 | |
311 | ++NumIdentifierLookupHits; |
312 | return true; |
313 | } |
314 | |
315 | bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) { |
316 | |
317 | StringRef Name = File->ModuleName; |
318 | llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name); |
319 | if (Known == UnresolvedModules.end()) { |
320 | return true; |
321 | } |
322 | |
323 | |
324 | ModuleInfo &Info = Modules[Known->second]; |
325 | |
326 | |
327 | |
328 | bool Failed = true; |
329 | if (File->File->getSize() == Info.Size && |
330 | File->File->getModificationTime() == Info.ModTime) { |
331 | Info.File = File; |
332 | ModulesByFile[File] = Known->second; |
333 | |
334 | Failed = false; |
335 | } |
336 | |
337 | |
338 | UnresolvedModules.erase(Known); |
339 | return Failed; |
340 | } |
341 | |
342 | void GlobalModuleIndex::printStats() { |
343 | std::fprintf(stderr, "*** Global Module Index Statistics:\n"); |
344 | if (NumIdentifierLookups) { |
345 | fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n", |
346 | NumIdentifierLookupHits, NumIdentifierLookups, |
347 | (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups); |
348 | } |
349 | std::fprintf(stderr, "\n"); |
350 | } |
351 | |
352 | LLVM_DUMP_METHOD void GlobalModuleIndex::dump() { |
353 | llvm::errs() << "*** Global Module Index Dump:\n"; |
354 | llvm::errs() << "Module files:\n"; |
355 | for (auto &MI : Modules) { |
356 | llvm::errs() << "** " << MI.FileName << "\n"; |
357 | if (MI.File) |
358 | MI.File->dump(); |
359 | else |
360 | llvm::errs() << "\n"; |
361 | } |
362 | llvm::errs() << "\n"; |
363 | } |
364 | |
365 | |
366 | |
367 | |
368 | |
369 | namespace { |
370 | |
371 | struct ModuleFileInfo { |
372 | |
373 | unsigned ID; |
374 | |
375 | |
376 | |
377 | SmallVector<unsigned, 4> Dependencies; |
378 | ASTFileSignature Signature; |
379 | }; |
380 | |
381 | struct ImportedModuleFileInfo { |
382 | off_t StoredSize; |
383 | time_t StoredModTime; |
384 | ASTFileSignature StoredSignature; |
385 | ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig) |
386 | : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {} |
387 | }; |
388 | |
389 | |
390 | class GlobalModuleIndexBuilder { |
391 | FileManager &FileMgr; |
392 | const PCHContainerReader &PCHContainerRdr; |
393 | |
394 | |
395 | typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap; |
396 | |
397 | |
398 | ModuleFilesMap ModuleFiles; |
399 | |
400 | |
401 | |
402 | typedef std::multimap<const FileEntry *, ImportedModuleFileInfo> |
403 | ImportedModuleFilesMap; |
404 | |
405 | |
406 | ImportedModuleFilesMap ImportedModuleFiles; |
407 | |
408 | |
409 | |
410 | typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap; |
411 | |
412 | |
413 | |
414 | InterestingIdentifierMap InterestingIdentifiers; |
415 | |
416 | |
417 | void emitBlockInfoBlock(llvm::BitstreamWriter &Stream); |
418 | |
419 | |
420 | ModuleFileInfo &getModuleFileInfo(const FileEntry *File) { |
421 | llvm::MapVector<const FileEntry *, ModuleFileInfo>::iterator Known |
422 | = ModuleFiles.find(File); |
423 | if (Known != ModuleFiles.end()) |
424 | return Known->second; |
425 | |
426 | unsigned NewID = ModuleFiles.size(); |
427 | ModuleFileInfo &Info = ModuleFiles[File]; |
428 | Info.ID = NewID; |
429 | return Info; |
430 | } |
431 | |
432 | public: |
433 | explicit GlobalModuleIndexBuilder( |
434 | FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr) |
435 | : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr) {} |
436 | |
437 | |
438 | |
439 | |
440 | bool loadModuleFile(const FileEntry *File); |
441 | |
442 | |
443 | |
444 | bool writeIndex(llvm::BitstreamWriter &Stream); |
445 | }; |
446 | } |
447 | |
448 | static void emitBlockID(unsigned ID, const char *Name, |
449 | llvm::BitstreamWriter &Stream, |
450 | SmallVectorImpl<uint64_t> &Record) { |
451 | Record.clear(); |
452 | Record.push_back(ID); |
453 | Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); |
454 | |
455 | |
456 | if (!Name || Name[0] == 0) return; |
457 | Record.clear(); |
458 | while (*Name) |
459 | Record.push_back(*Name++); |
460 | Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); |
461 | } |
462 | |
463 | static void emitRecordID(unsigned ID, const char *Name, |
464 | llvm::BitstreamWriter &Stream, |
465 | SmallVectorImpl<uint64_t> &Record) { |
466 | Record.clear(); |
467 | Record.push_back(ID); |
468 | while (*Name) |
469 | Record.push_back(*Name++); |
470 | Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); |
471 | } |
472 | |
473 | void |
474 | GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) { |
475 | SmallVector<uint64_t, 64> Record; |
476 | Stream.EnterBlockInfoBlock(); |
477 | |
478 | #define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record) |
479 | #define RECORD(X) emitRecordID(X, #X, Stream, Record) |
480 | BLOCK(GLOBAL_INDEX_BLOCK); |
481 | RECORD(INDEX_METADATA); |
482 | RECORD(MODULE); |
483 | RECORD(IDENTIFIER_INDEX); |
484 | #undef RECORD |
485 | #undef BLOCK |
486 | |
487 | Stream.ExitBlock(); |
488 | } |
489 | |
490 | namespace { |
491 | class InterestingASTIdentifierLookupTrait |
492 | : public serialization::reader::ASTIdentifierLookupTraitBase { |
493 | |
494 | public: |
495 | |
496 | typedef std::pair<StringRef, bool> data_type; |
497 | |
498 | data_type ReadData(const internal_key_type& k, |
499 | const unsigned char* d, |
500 | unsigned DataLen) { |
501 | |
502 | |
503 | using namespace llvm::support; |
504 | unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d); |
505 | bool IsInteresting = RawID & 0x01; |
506 | return std::make_pair(k, IsInteresting); |
507 | } |
508 | }; |
509 | } |
510 | |
511 | bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { |
512 | |
513 | |
514 | auto Buffer = FileMgr.getBufferForFile(File, ); |
515 | if (!Buffer) { |
516 | return true; |
517 | } |
518 | |
519 | |
520 | llvm::BitstreamCursor InStream(PCHContainerRdr.ExtractPCH(**Buffer)); |
521 | |
522 | |
523 | if (InStream.Read(8) != 'C' || |
524 | InStream.Read(8) != 'P' || |
525 | InStream.Read(8) != 'C' || |
526 | InStream.Read(8) != 'H') { |
527 | return true; |
528 | } |
529 | |
530 | |
531 | |
532 | unsigned ID = getModuleFileInfo(File).ID; |
533 | |
534 | |
535 | enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other; |
536 | bool Done = false; |
537 | while (!Done) { |
538 | llvm::BitstreamEntry Entry = InStream.advance(); |
539 | switch (Entry.Kind) { |
540 | case llvm::BitstreamEntry::Error: |
541 | Done = true; |
542 | continue; |
543 | |
544 | case llvm::BitstreamEntry::Record: |
545 | |
546 | if (State == Other) { |
547 | InStream.skipRecord(Entry.ID); |
548 | continue; |
549 | } |
550 | |
551 | |
552 | break; |
553 | |
554 | case llvm::BitstreamEntry::SubBlock: |
555 | if (Entry.ID == CONTROL_BLOCK_ID) { |
556 | if (InStream.EnterSubBlock(CONTROL_BLOCK_ID)) |
557 | return true; |
558 | |
559 | |
560 | State = ControlBlock; |
561 | continue; |
562 | } |
563 | |
564 | if (Entry.ID == AST_BLOCK_ID) { |
565 | if (InStream.EnterSubBlock(AST_BLOCK_ID)) |
566 | return true; |
567 | |
568 | |
569 | State = ASTBlock; |
570 | continue; |
571 | } |
572 | |
573 | if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) { |
574 | if (InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID)) |
575 | return true; |
576 | |
577 | |
578 | State = DiagnosticOptionsBlock; |
579 | continue; |
580 | } |
581 | |
582 | if (InStream.SkipBlock()) |
583 | return true; |
584 | |
585 | continue; |
586 | |
587 | case llvm::BitstreamEntry::EndBlock: |
588 | State = Other; |
589 | continue; |
590 | } |
591 | |
592 | |
593 | SmallVector<uint64_t, 64> Record; |
594 | StringRef Blob; |
595 | unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob); |
596 | |
597 | |
598 | if (State == ControlBlock && Code == IMPORTS) { |
599 | |
600 | unsigned Idx = 0, N = Record.size(); |
601 | while (Idx < N) { |
602 | |
603 | |
604 | |
605 | ++Idx; |
606 | |
607 | |
608 | ++Idx; |
609 | |
610 | |
611 | off_t StoredSize = (off_t)Record[Idx++]; |
612 | time_t StoredModTime = (time_t)Record[Idx++]; |
613 | |
614 | |
615 | |
616 | ASTFileSignature StoredSignature = { |
617 | {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++], |
618 | (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], |
619 | (uint32_t)Record[Idx++]}}}; |
620 | |
621 | |
622 | |
623 | Idx += Record[Idx] + 1; |
624 | |
625 | |
626 | unsigned Length = Record[Idx++]; |
627 | SmallString<128> ImportedFile(Record.begin() + Idx, |
628 | Record.begin() + Idx + Length); |
629 | Idx += Length; |
630 | |
631 | |
632 | const FileEntry *DependsOnFile |
633 | = FileMgr.getFile(ImportedFile, , |
634 | ); |
635 | |
636 | if (!DependsOnFile) |
637 | return true; |
638 | |
639 | |
640 | |
641 | ImportedModuleFiles.insert(std::make_pair( |
642 | DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime, |
643 | StoredSignature))); |
644 | |
645 | |
646 | unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID; |
647 | getModuleFileInfo(File).Dependencies.push_back(DependsOnID); |
648 | } |
649 | |
650 | continue; |
651 | } |
652 | |
653 | |
654 | if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) { |
655 | typedef llvm::OnDiskIterableChainedHashTable< |
656 | InterestingASTIdentifierLookupTrait> InterestingIdentifierTable; |
657 | std::unique_ptr<InterestingIdentifierTable> Table( |
658 | InterestingIdentifierTable::Create( |
659 | (const unsigned char *)Blob.data() + Record[0], |
660 | (const unsigned char *)Blob.data() + sizeof(uint32_t), |
661 | (const unsigned char *)Blob.data())); |
662 | for (InterestingIdentifierTable::data_iterator D = Table->data_begin(), |
663 | DEnd = Table->data_end(); |
664 | D != DEnd; ++D) { |
665 | std::pair<StringRef, bool> Ident = *D; |
666 | if (Ident.second) |
667 | InterestingIdentifiers[Ident.first].push_back(ID); |
668 | else |
669 | (void)InterestingIdentifiers[Ident.first]; |
670 | } |
671 | } |
672 | |
673 | |
674 | if (State == DiagnosticOptionsBlock && Code == SIGNATURE) |
675 | getModuleFileInfo(File).Signature = { |
676 | {{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2], |
677 | (uint32_t)Record[3], (uint32_t)Record[4]}}}; |
678 | |
679 | |
680 | } |
681 | |
682 | return false; |
683 | } |
684 | |
685 | namespace { |
686 | |
687 | |
688 | |
689 | class IdentifierIndexWriterTrait { |
690 | public: |
691 | typedef StringRef key_type; |
692 | typedef StringRef key_type_ref; |
693 | typedef SmallVector<unsigned, 2> data_type; |
694 | typedef const SmallVector<unsigned, 2> &data_type_ref; |
695 | typedef unsigned hash_value_type; |
696 | typedef unsigned offset_type; |
697 | |
698 | static hash_value_type ComputeHash(key_type_ref Key) { |
699 | return llvm::djbHash(Key); |
700 | } |
701 | |
702 | std::pair<unsigned,unsigned> |
703 | EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) { |
704 | using namespace llvm::support; |
705 | endian::Writer LE(Out, little); |
706 | unsigned KeyLen = Key.size(); |
707 | unsigned DataLen = Data.size() * 4; |
708 | LE.write<uint16_t>(KeyLen); |
709 | LE.write<uint16_t>(DataLen); |
710 | return std::make_pair(KeyLen, DataLen); |
711 | } |
712 | |
713 | void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) { |
714 | Out.write(Key.data(), KeyLen); |
715 | } |
716 | |
717 | void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data, |
718 | unsigned DataLen) { |
719 | using namespace llvm::support; |
720 | for (unsigned I = 0, N = Data.size(); I != N; ++I) |
721 | endian::write<uint32_t>(Out, Data[I], little); |
722 | } |
723 | }; |
724 | |
725 | } |
726 | |
727 | bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { |
728 | for (auto MapEntry : ImportedModuleFiles) { |
729 | auto *File = MapEntry.first; |
730 | ImportedModuleFileInfo &Info = MapEntry.second; |
731 | if (getModuleFileInfo(File).Signature) { |
732 | if (getModuleFileInfo(File).Signature != Info.StoredSignature) |
733 | |
734 | return true; |
735 | } else if (Info.StoredSize != File->getSize() || |
736 | Info.StoredModTime != File->getModificationTime()) |
737 | |
738 | return true; |
739 | } |
740 | |
741 | using namespace llvm; |
742 | |
743 | |
744 | Stream.Emit((unsigned)'B', 8); |
745 | Stream.Emit((unsigned)'C', 8); |
746 | Stream.Emit((unsigned)'G', 8); |
747 | Stream.Emit((unsigned)'I', 8); |
748 | |
749 | |
750 | |
751 | emitBlockInfoBlock(Stream); |
752 | |
753 | Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3); |
754 | |
755 | |
756 | SmallVector<uint64_t, 2> Record; |
757 | Record.push_back(CurrentVersion); |
758 | Stream.EmitRecord(INDEX_METADATA, Record); |
759 | |
760 | |
761 | for (ModuleFilesMap::iterator M = ModuleFiles.begin(), |
762 | MEnd = ModuleFiles.end(); |
763 | M != MEnd; ++M) { |
764 | Record.clear(); |
765 | Record.push_back(M->second.ID); |
766 | Record.push_back(M->first->getSize()); |
767 | Record.push_back(M->first->getModificationTime()); |
768 | |
769 | |
770 | StringRef Name(M->first->getName()); |
771 | Record.push_back(Name.size()); |
772 | Record.append(Name.begin(), Name.end()); |
773 | |
774 | |
775 | Record.push_back(M->second.Dependencies.size()); |
776 | Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end()); |
777 | Stream.EmitRecord(MODULE, Record); |
778 | } |
779 | |
780 | |
781 | { |
782 | llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator; |
783 | IdentifierIndexWriterTrait Trait; |
784 | |
785 | |
786 | for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(), |
787 | IEnd = InterestingIdentifiers.end(); |
788 | I != IEnd; ++I) { |
789 | Generator.insert(I->first(), I->second, Trait); |
790 | } |
791 | |
792 | |
793 | SmallString<4096> IdentifierTable; |
794 | uint32_t BucketOffset; |
795 | { |
796 | using namespace llvm::support; |
797 | llvm::raw_svector_ostream Out(IdentifierTable); |
798 | |
799 | endian::write<uint32_t>(Out, 0, little); |
800 | BucketOffset = Generator.Emit(Out, Trait); |
801 | } |
802 | |
803 | |
804 | auto Abbrev = std::make_shared<BitCodeAbbrev>(); |
805 | Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX)); |
806 | Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); |
807 | Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); |
808 | unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); |
809 | |
810 | |
811 | uint64_t Record[] = {IDENTIFIER_INDEX, BucketOffset}; |
812 | Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable); |
813 | } |
814 | |
815 | Stream.ExitBlock(); |
816 | return false; |
817 | } |
818 | |
819 | GlobalModuleIndex::ErrorCode |
820 | GlobalModuleIndex::writeIndex(FileManager &FileMgr, |
821 | const PCHContainerReader &PCHContainerRdr, |
822 | StringRef Path) { |
823 | llvm::SmallString<128> IndexPath; |
824 | IndexPath += Path; |
825 | llvm::sys::path::append(IndexPath, IndexFileName); |
826 | |
827 | |
828 | |
829 | llvm::LockFileManager Locked(IndexPath); |
830 | switch (Locked) { |
831 | case llvm::LockFileManager::LFS_Error: |
832 | return EC_IOError; |
833 | |
834 | case llvm::LockFileManager::LFS_Owned: |
835 | |
836 | break; |
837 | |
838 | case llvm::LockFileManager::LFS_Shared: |
839 | |
840 | |
841 | return EC_Building; |
842 | } |
843 | |
844 | |
845 | GlobalModuleIndexBuilder Builder(FileMgr, PCHContainerRdr); |
846 | |
847 | |
848 | std::error_code EC; |
849 | for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd; |
850 | D != DEnd && !EC; |
851 | D.increment(EC)) { |
852 | |
853 | if (llvm::sys::path::extension(D->path()) != ".pcm") { |
854 | |
855 | |
856 | |
857 | if (llvm::sys::path::extension(D->path()) == ".pcm.lock") |
858 | return EC_Building; |
859 | |
860 | continue; |
861 | } |
862 | |
863 | |
864 | const FileEntry *ModuleFile = FileMgr.getFile(D->path()); |
865 | if (!ModuleFile) |
866 | continue; |
867 | |
868 | |
869 | if (Builder.loadModuleFile(ModuleFile)) |
870 | return EC_IOError; |
871 | } |
872 | |
873 | |
874 | SmallVector<char, 16> OutputBuffer; |
875 | { |
876 | llvm::BitstreamWriter OutputStream(OutputBuffer); |
877 | if (Builder.writeIndex(OutputStream)) |
878 | return EC_IOError; |
879 | } |
880 | |
881 | |
882 | llvm::SmallString<128> IndexTmpPath; |
883 | int TmpFD; |
884 | if (llvm::sys::fs::createUniqueFile(IndexPath + "-%%%%%%%%", TmpFD, |
885 | IndexTmpPath)) |
886 | return EC_IOError; |
887 | |
888 | |
889 | llvm::raw_fd_ostream Out(TmpFD, true); |
890 | if (Out.has_error()) |
891 | return EC_IOError; |
892 | |
893 | |
894 | Out.write(OutputBuffer.data(), OutputBuffer.size()); |
895 | Out.close(); |
896 | if (Out.has_error()) |
897 | return EC_IOError; |
898 | |
899 | |
900 | llvm::sys::fs::remove(IndexPath); |
901 | |
902 | |
903 | if (llvm::sys::fs::rename(IndexTmpPath, IndexPath)) { |
904 | |
905 | llvm::sys::fs::remove(IndexTmpPath); |
906 | return EC_IOError; |
907 | } |
908 | |
909 | |
910 | return EC_None; |
911 | } |
912 | |
913 | namespace { |
914 | class GlobalIndexIdentifierIterator : public IdentifierIterator { |
915 | |
916 | IdentifierIndexTable::key_iterator Current; |
917 | |
918 | |
919 | IdentifierIndexTable::key_iterator End; |
920 | |
921 | public: |
922 | explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) { |
923 | Current = Idx.key_begin(); |
924 | End = Idx.key_end(); |
925 | } |
926 | |
927 | StringRef Next() override { |
928 | if (Current == End) |
929 | return StringRef(); |
930 | |
931 | StringRef Result = *Current; |
932 | ++Current; |
933 | return Result; |
934 | } |
935 | }; |
936 | } |
937 | |
938 | IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const { |
939 | IdentifierIndexTable &Table = |
940 | *static_cast<IdentifierIndexTable *>(IdentifierIndex); |
941 | return new GlobalIndexIdentifierIterator(Table); |
942 | } |
943 | |