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) {
346 ModulesByFile[
File] = Known->second;
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++]);
637 off_t StoredSize = (off_t)
Record[Idx++];
638 time_t StoredModTime = (time_t)
Record[Idx++];
645 SignatureBytes.end());
649 unsigned Length =
Record[Idx++];
650 StringRef ImportedFile = Blob.substr(0, Length);
651 Blob = Blob.substr(Length);
655 FileMgr.getOptionalFileRef(ImportedFile,
false,
659 return llvm::createStringError(std::errc::bad_file_descriptor,
660 "imported file \"%s\" not found",
661 std::string(ImportedFile).c_str());
665 ImportedModuleFiles.insert(std::make_pair(
666 *DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
670 unsigned DependsOnID = getModuleFileInfo(*DependsOnFile).ID;
671 getModuleFileInfo(
File).Dependencies.push_back(DependsOnID);
678 typedef llvm::OnDiskIterableChainedHashTable<
679 InterestingASTIdentifierLookupTrait> InterestingIdentifierTable;
680 std::unique_ptr<InterestingIdentifierTable> Table(
681 InterestingIdentifierTable::Create(
682 (
const unsigned char *)Blob.data() +
Record[0],
683 (
const unsigned char *)Blob.data() +
sizeof(
uint32_t),
684 (
const unsigned char *)Blob.data()));
685 for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
686 DEnd = Table->data_end();
688 std::pair<StringRef, bool> Ident = *D;
690 InterestingIdentifiers[Ident.first].push_back(ID);
692 (
void)InterestingIdentifiers[Ident.first];
697 if (State == DiagnosticOptionsBlock && Code ==
SIGNATURE) {
700 "Dummy AST file signature not backpatched in ASTWriter.");
701 getModuleFileInfo(
File).Signature = Signature;
707 return llvm::Error::success();
714class IdentifierIndexWriterTrait {
716 typedef StringRef key_type;
717 typedef StringRef key_type_ref;
718 typedef SmallVector<unsigned, 2> data_type;
719 typedef const SmallVector<unsigned, 2> &data_type_ref;
720 typedef unsigned hash_value_type;
721 typedef unsigned offset_type;
723 static hash_value_type
ComputeHash(key_type_ref Key) {
724 return llvm::djbHash(Key);
727 std::pair<unsigned,unsigned>
728 EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref
Data) {
729 using namespace llvm::support;
730 endian::Writer
LE(Out, llvm::endianness::little);
731 unsigned KeyLen = Key.size();
732 unsigned DataLen =
Data.size() * 4;
735 return std::make_pair(KeyLen, DataLen);
738 void EmitKey(raw_ostream& Out, key_type_ref Key,
unsigned KeyLen) {
739 Out.write(Key.data(), KeyLen);
742 void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref
Data,
744 using namespace llvm::support;
745 for (
unsigned I = 0, N =
Data.size(); I != N; ++I)
746 endian::write<uint32_t>(Out,
Data[I], llvm::endianness::little);
752bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
753 for (
auto MapEntry : ImportedModuleFiles) {
754 auto File = MapEntry.first;
755 ImportedModuleFileInfo &Info = MapEntry.second;
756 if (getModuleFileInfo(
File).Signature) {
757 if (getModuleFileInfo(
File).Signature != Info.StoredSignature)
760 }
else if (Info.StoredSize !=
File.getSize() ||
761 Info.StoredModTime !=
File.getModificationTime())
766 using namespace llvm;
767 llvm::TimeTraceScope TimeScope(
"Module WriteIndex");
770 Stream.Emit((
unsigned)
'B', 8);
771 Stream.Emit((
unsigned)
'C', 8);
772 Stream.Emit((
unsigned)
'G', 8);
773 Stream.Emit((
unsigned)
'I', 8);
777 emitBlockInfoBlock(Stream);
779 Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);
784 Stream.EmitRecord(INDEX_METADATA,
Record);
787 for (ModuleFilesMap::iterator M = ModuleFiles.begin(),
788 MEnd = ModuleFiles.end();
791 Record.push_back(M->second.ID);
792 Record.push_back(M->first.getSize());
793 Record.push_back(M->first.getModificationTime());
796 StringRef Name(M->first.getName());
797 Record.push_back(Name.size());
798 Record.append(Name.begin(), Name.end());
801 Record.push_back(M->second.Dependencies.size());
802 Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());
803 Stream.EmitRecord(MODULE,
Record);
808 llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait>
Generator;
809 IdentifierIndexWriterTrait Trait;
812 for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),
813 IEnd = InterestingIdentifiers.end();
815 Generator.insert(I->first(), I->second, Trait);
822 using namespace llvm::support;
825 endian::write<uint32_t>(Out, 0, llvm::endianness::little);
826 BucketOffset =
Generator.Emit(Out, Trait);
830 auto Abbrev = std::make_shared<BitCodeAbbrev>();
831 Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX));
832 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
833 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
834 unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
850 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
858 llvm::LockFileManager Lock(IndexPath);
860 if (llvm::Error Err = Lock.tryLock().moveInto(Owned)) {
861 llvm::consumeError(std::move(Err));
862 return llvm::createStringError(std::errc::io_error,
"LFS error");
867 return llvm::createStringError(std::errc::device_or_resource_busy,
868 "someone else is building the index");
874 GlobalModuleIndexBuilder Builder(
FileMgr, PCHContainerRdr);
878 for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
882 if (llvm::sys::path::extension(D->path()) !=
".pcm") {
886 if (llvm::sys::path::extension(D->path()) ==
".pcm.lock")
887 return llvm::createStringError(std::errc::device_or_resource_busy,
888 "someone else is building the index");
894 auto ModuleFile =
FileMgr.getOptionalFileRef(D->path());
899 if (llvm::Error Err = Builder.loadModuleFile(*ModuleFile))
906 llvm::BitstreamWriter OutputStream(OutputBuffer);
907 if (Builder.writeIndex(OutputStream))
908 return llvm::createStringError(std::errc::io_error,
909 "failed writing index");
912 return llvm::writeToOutput(IndexPath, [&OutputBuffer](llvm::raw_ostream &OS) {
914 return llvm::Error::success();
921 IdentifierIndexTable::key_iterator Current;
924 IdentifierIndexTable::key_iterator End;
927 explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) {
928 Current = Idx.key_begin();
932 StringRef
Next()
override {
936 StringRef
Result = *Current;
944 IdentifierIndexTable &Table =
945 *
static_cast<IdentifierIndexTable *
>(IdentifierIndex);
946 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.
The JSON file list parser is used to communicate input to InstallAPI.
@ Other
Other implicit parameter.
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 uint16_t
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_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()