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