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"
44 GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID
48 enum IndexRecordTypes {
73class IdentifierIndexReaderTrait {
75 typedef StringRef external_key_type;
76 typedef StringRef internal_key_type;
78 typedef unsigned hash_value_type;
79 typedef unsigned offset_type;
81 static bool EqualKey(
const internal_key_type& a,
const internal_key_type& b) {
85 static hash_value_type
ComputeHash(
const internal_key_type& a) {
86 return llvm::djbHash(a);
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);
97 static const internal_key_type&
98 GetInternalKey(
const external_key_type& x) {
return x; }
100 static const external_key_type&
101 GetExternalKey(
const internal_key_type& x) {
return x; }
103 static internal_key_type ReadKey(
const unsigned char* d,
unsigned n) {
104 return StringRef((
const char *)d, n);
107 static data_type ReadData(
const internal_key_type& k,
108 const unsigned char* d,
110 using namespace llvm::support;
113 while (DataLen > 0) {
114 unsigned ID = endian::readNext<uint32_t, llvm::endianness::little>(d);
123typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>
124 IdentifierIndexTable;
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)));
138 llvm::TimeTraceScope TimeScope(
"Module LoadIndex");
140 bool InGlobalIndexBlock =
false;
143 llvm::BitstreamEntry Entry;
147 Fail(Res.takeError());
149 switch (Entry.Kind) {
150 case llvm::BitstreamEntry::Error:
153 case llvm::BitstreamEntry::EndBlock:
154 if (InGlobalIndexBlock) {
155 InGlobalIndexBlock =
false;
162 case llvm::BitstreamEntry::Record:
164 if (InGlobalIndexBlock)
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));
183 if (!MaybeIndexRecord)
184 Fail(MaybeIndexRecord.takeError());
185 IndexRecordTypes IndexRecord =
186 static_cast<IndexRecordTypes
>(MaybeIndexRecord.get());
187 switch (IndexRecord) {
196 unsigned ID =
Record[Idx++];
199 if (ID == Modules.size())
200 Modules.push_back(ModuleInfo());
202 Modules.resize(ID + 1);
206 Modules[ID].Size =
Record[Idx++];
207 Modules[ID].ModTime =
Record[Idx++];
210 unsigned NameLen =
Record[Idx++];
211 Modules[ID].FileName.assign(
Record.begin() + Idx,
212 Record.begin() + Idx + NameLen);
216 unsigned NumDeps =
Record[Idx++];
217 Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),
219 Record.begin() + Idx + NumDeps);
223 assert(Idx ==
Record.size() &&
"More module info?");
228 StringRef ModuleName = llvm::sys::path::stem(Modules[ID].
FileName);
230 ModuleName = ModuleName.rsplit(
'-').first;
231 UnresolvedModules[ModuleName] = ID;
235 case IDENTIFIER_INDEX:
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());
249 delete static_cast<IdentifierIndexTable *
>(IdentifierIndex);
252std::pair<GlobalModuleIndex *, llvm::Error>
255 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
262 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr =
263 llvm::MemoryBuffer::getFile(IndexPath.c_str());
265 return std::make_pair(
nullptr,
266 llvm::errorCodeToError(BufferOrErr.getError()));
267 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get());
270 llvm::BitstreamCursor Cursor(*Buffer);
273 for (
unsigned char C : {
'B',
'C',
'G',
'I'}) {
276 return std::make_pair(
277 nullptr, llvm::createStringError(std::errc::illegal_byte_sequence,
278 "expected signature BCGI"));
280 return std::make_pair(
nullptr, Res.takeError());
283 return std::make_pair(
new GlobalModuleIndex(std::move(Buffer), std::move(Cursor)),
284 llvm::Error::success());
291 llvm::DenseMap<ModuleFile *, unsigned>::iterator
Known
292 = ModulesByFile.find(
File);
293 if (
Known == ModulesByFile.end())
297 Dependencies.clear();
299 for (
unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) {
300 if (ModuleFile *MF = Modules[I].
File)
301 Dependencies.push_back(MF);
309 if (!IdentifierIndex)
313 ++NumIdentifierLookups;
314 IdentifierIndexTable &Table
315 = *
static_cast<IdentifierIndexTable *
>(IdentifierIndex);
316 IdentifierIndexTable::iterator
Known = Table.find(Name);
317 if (
Known == Table.end()) {
321 for (
unsigned ModuleID : *
Known) {
322 if (ModuleFile *MF = Modules[ModuleID].
File)
326 ++NumIdentifierLookupHits;
332 StringRef Name =
File->ModuleName;
333 llvm::StringMap<unsigned>::iterator
Known = UnresolvedModules.find(Name);
334 if (
Known == UnresolvedModules.end()) {
339 ModuleInfo &Info = Modules[
Known->second];
344 if (
File->Size == Info.Size &&
File->ModTime == Info.ModTime) {
352 UnresolvedModules.erase(
Known);
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);
363 std::fprintf(
stderr,
"\n");
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";
374 llvm::errs() <<
"\n";
376 llvm::errs() <<
"\n";
385 struct ModuleFileInfo {
395 struct ImportedModuleFileInfo {
397 time_t StoredModTime;
400 : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {}
404 class GlobalModuleIndexBuilder {
405 FileManager &FileMgr;
406 const PCHContainerReader &PCHContainerRdr;
409 using ModuleFilesMap = llvm::MapVector<FileEntryRef, ModuleFileInfo>;
412 ModuleFilesMap ModuleFiles;
416 using ImportedModuleFilesMap =
417 std::multimap<FileEntryRef, ImportedModuleFileInfo>;
420 ImportedModuleFilesMap ImportedModuleFiles;
424 typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
428 InterestingIdentifierMap InterestingIdentifiers;
431 void emitBlockInfoBlock(llvm::BitstreamWriter &Stream);
435 auto [It, Inserted] = ModuleFiles.try_emplace(
File);
437 unsigned NewID = ModuleFiles.size();
445 explicit GlobalModuleIndexBuilder(
446 FileManager &FileMgr,
const PCHContainerReader &PCHContainerRdr)
447 : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr) {}
450 llvm::Error loadModuleFile(FileEntryRef
File);
454 bool writeIndex(llvm::BitstreamWriter &Stream);
459 llvm::BitstreamWriter &Stream,
463 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
Record);
466 if (!Name || Name[0] == 0)
return;
469 Record.push_back(*Name++);
470 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
Record);
474 llvm::BitstreamWriter &Stream,
479 Record.push_back(*Name++);
480 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME,
Record);
484GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) {
486 Stream.EnterBlockInfoBlock();
488#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
489#define RECORD(X) emitRecordID(X, #X, Stream, Record)
490 BLOCK(GLOBAL_INDEX_BLOCK);
501 class InterestingASTIdentifierLookupTrait
506 typedef std::pair<StringRef, bool> data_type;
508 data_type ReadData(
const internal_key_type& k,
509 const unsigned char* d,
513 using namespace llvm::support;
515 endian::readNext<IdentifierID, llvm::endianness::little>(d);
516 bool IsInteresting = RawID & 0x01;
517 return std::make_pair(k, IsInteresting);
525 auto Buffer =
FileMgr.getBufferForFile(
File,
true);
527 return llvm::createStringError(Buffer.getError(),
528 "failed getting buffer for module file");
531 llvm::BitstreamCursor InStream(PCHContainerRdr.
ExtractPCH(**Buffer));
534 for (
unsigned char C : {
'C',
'P',
'C',
'H'})
537 return llvm::createStringError(std::errc::illegal_byte_sequence,
538 "expected signature CPCH");
540 return Res.takeError();
544 unsigned ID = getModuleFileInfo(
File).ID;
547 enum {
Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State =
Other;
552 return MaybeEntry.takeError();
553 llvm::BitstreamEntry Entry = MaybeEntry.get();
555 switch (Entry.Kind) {
556 case llvm::BitstreamEntry::Error:
560 case llvm::BitstreamEntry::Record:
562 if (State ==
Other) {
566 return Skipped.takeError();
572 case llvm::BitstreamEntry::SubBlock:
578 State = ControlBlock;
583 if (llvm::Error Err = InStream.EnterSubBlock(
AST_BLOCK_ID))
596 State = DiagnosticOptionsBlock;
600 if (llvm::Error Err = InStream.SkipBlock())
605 case llvm::BitstreamEntry::EndBlock:
615 return MaybeCode.takeError();
616 unsigned Code = MaybeCode.get();
619 if (State == ControlBlock && Code ==
IMPORT) {
631 Blob = Blob.substr(
Record[Idx++]);
634 bool IsCXX20ModuleOrPrebuiltHeaderUnit =
Record[Idx++];
637 if (IsCXX20ModuleOrPrebuiltHeaderUnit)
641 off_t StoredSize = (off_t)
Record[Idx++];
642 time_t StoredModTime = (time_t)
Record[Idx++];
649 SignatureBytes.end());
653 unsigned Length =
Record[Idx++];
654 StringRef ImportedFile = Blob.substr(0, Length);
655 Blob = Blob.substr(Length);
659 FileMgr.getOptionalFileRef(ImportedFile,
false,
663 return llvm::createStringError(std::errc::bad_file_descriptor,
664 "imported file \"%s\" not found",
665 std::string(ImportedFile).c_str());
669 ImportedModuleFiles.insert(std::make_pair(
670 *DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
674 unsigned DependsOnID = getModuleFileInfo(*DependsOnFile).ID;
675 getModuleFileInfo(
File).Dependencies.push_back(DependsOnID);
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();
692 std::pair<StringRef, bool> Ident = *D;
694 InterestingIdentifiers[Ident.first].push_back(ID);
696 (
void)InterestingIdentifiers[Ident.first];
701 if (State == DiagnosticOptionsBlock && Code ==
SIGNATURE) {
704 "Dummy AST file signature not backpatched in ASTWriter.");
705 getModuleFileInfo(
File).Signature = Signature;
711 return llvm::Error::success();
718class IdentifierIndexWriterTrait {
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;
727 static hash_value_type
ComputeHash(key_type_ref Key) {
728 return llvm::djbHash(Key);
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;
739 return std::make_pair(KeyLen, DataLen);
742 void EmitKey(raw_ostream& Out, key_type_ref Key,
unsigned KeyLen) {
743 Out.write(Key.data(), KeyLen);
746 void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref
Data,
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);
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)
764 }
else if (Info.StoredSize !=
File.getSize() ||
765 Info.StoredModTime !=
File.getModificationTime())
770 using namespace llvm;
771 llvm::TimeTraceScope TimeScope(
"Module WriteIndex");
774 Stream.Emit((
unsigned)
'B', 8);
775 Stream.Emit((
unsigned)
'C', 8);
776 Stream.Emit((
unsigned)
'G', 8);
777 Stream.Emit((
unsigned)
'I', 8);
781 emitBlockInfoBlock(Stream);
783 Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);
788 Stream.EmitRecord(INDEX_METADATA,
Record);
791 for (ModuleFilesMap::iterator M = ModuleFiles.begin(),
792 MEnd = ModuleFiles.end();
795 Record.push_back(M->second.ID);
796 Record.push_back(M->first.getSize());
797 Record.push_back(M->first.getModificationTime());
800 StringRef Name(M->first.getName());
801 Record.push_back(Name.size());
802 Record.append(Name.begin(), Name.end());
805 Record.push_back(M->second.Dependencies.size());
806 Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());
807 Stream.EmitRecord(MODULE,
Record);
812 llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait>
Generator;
813 IdentifierIndexWriterTrait Trait;
816 for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),
817 IEnd = InterestingIdentifiers.end();
819 Generator.insert(I->first(), I->second, Trait);
826 using namespace llvm::support;
829 endian::write<uint32_t>(Out, 0, llvm::endianness::little);
830 BucketOffset =
Generator.Emit(Out, Trait);
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));
854 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
862 llvm::LockFileManager Lock(IndexPath);
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");
871 return llvm::createStringError(std::errc::device_or_resource_busy,
872 "someone else is building the index");
878 GlobalModuleIndexBuilder Builder(
FileMgr, PCHContainerRdr);
882 for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
886 if (llvm::sys::path::extension(D->path()) !=
".pcm") {
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");
898 auto ModuleFile =
FileMgr.getOptionalFileRef(D->path());
903 if (llvm::Error Err = Builder.loadModuleFile(*ModuleFile))
910 llvm::BitstreamWriter OutputStream(OutputBuffer);
911 if (Builder.writeIndex(OutputStream))
912 return llvm::createStringError(std::errc::io_error,
913 "failed writing index");
916 return llvm::writeToOutput(IndexPath, [&OutputBuffer](llvm::raw_ostream &OS) {
918 return llvm::Error::success();
925 IdentifierIndexTable::key_iterator Current;
928 IdentifierIndexTable::key_iterator End;
931 explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) {
932 Current = Idx.key_begin();
936 StringRef
Next()
override {
940 StringRef
Result = *Current;
948 IdentifierIndexTable &Table =
949 *
static_cast<IdentifierIndexTable *
>(IdentifierIndex);
950 return new GlobalIndexIdentifierIterator(Table);
#define RECORD(CLASS, BASE)
Defines the clang::FileManager interface and associated types.
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
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
#define IMPORT(DERIVED, BASE)
#define BLOCK(DERIVED, BASE)
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Implements support for file system lookup, file system caching, and directory search management.
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)
@ 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.
Top level wrappers for InstallAPI frontend operations.
@ Other
Other implicit parameter.
__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.
static constexpr size_t size
static ASTFileSignature create(std::array< uint8_t, 20 > Bytes)
static ASTFileSignature createDummy()