/// Populate \p extendedInfo with the data from the options block. /// /// Returns true on success. static bool readOptionsBlock(llvm::BitstreamCursor &cursor, SmallVectorImpl<uint64_t> &scratch, ExtendedValidationInfo &extendedInfo) { auto next = cursor.advance(); while (next.Kind != llvm::BitstreamEntry::EndBlock) { if (next.Kind == llvm::BitstreamEntry::Error) return false; if (next.Kind == llvm::BitstreamEntry::SubBlock) { // Unknown metadata sub-block, possibly for use by a future version of // the module format. if (cursor.SkipBlock()) return false; next = cursor.advance(); continue; } scratch.clear(); StringRef blobData; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case options_block::SDK_PATH: extendedInfo.setSDKPath(blobData); break; case options_block::XCC: extendedInfo.addExtraClangImporterOption(blobData); break; case options_block::IS_SIB: bool IsSIB; options_block::IsSIBLayout::readRecord(scratch, IsSIB); extendedInfo.setIsSIB(IsSIB); break; case options_block::IS_TESTABLE: extendedInfo.setIsTestable(true); break; case options_block::IS_RESILIENT: extendedInfo.setIsResilient(true); break; default: // Unknown options record, possibly for use by a future version of the // module format. break; } next = cursor.advance(); } return true; }
static bool enterTopLevelModuleBlock(llvm::BitstreamCursor &cursor, unsigned ID, bool shouldReadBlockInfo = true) { auto next = cursor.advance(); if (next.Kind != llvm::BitstreamEntry::SubBlock) return false; if (next.ID == llvm::bitc::BLOCKINFO_BLOCK_ID) { if (shouldReadBlockInfo) { if (cursor.ReadBlockInfoBlock()) return false; } else { if (cursor.SkipBlock()) return false; } return enterTopLevelModuleBlock(cursor, ID, false); } if (next.ID != ID) return false; cursor.EnterSubBlock(ID); return true; }
bool ModuleFile::readCommentBlock(llvm::BitstreamCursor &cursor) { cursor.EnterSubBlock(COMMENT_BLOCK_ID); SmallVector<uint64_t, 4> scratch; StringRef blobData; while (true) { auto next = cursor.advance(); switch (next.Kind) { case llvm::BitstreamEntry::EndBlock: return true; case llvm::BitstreamEntry::Error: return false; case llvm::BitstreamEntry::SubBlock: // Unknown sub-block, which this version of the compiler won't use. if (cursor.SkipBlock()) return false; break; case llvm::BitstreamEntry::Record: scratch.clear(); unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case comment_block::DECL_COMMENTS: DeclCommentTable = readDeclCommentTable(scratch, blobData); break; case comment_block::GROUP_NAMES: GroupNamesMap = readGroupTable(scratch, blobData); break; default: // Unknown index kind, which this version of the compiler won't use. break; } break; } } }
bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) { cursor.EnterSubBlock(INDEX_BLOCK_ID); SmallVector<uint64_t, 4> scratch; StringRef blobData; while (true) { auto next = cursor.advance(); switch (next.Kind) { case llvm::BitstreamEntry::EndBlock: return true; case llvm::BitstreamEntry::Error: return false; case llvm::BitstreamEntry::SubBlock: // Unknown sub-block, which this version of the compiler won't use. if (cursor.SkipBlock()) return false; break; case llvm::BitstreamEntry::Record: scratch.clear(); blobData = {}; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case index_block::DECL_OFFSETS: assert(blobData.empty()); Decls.assign(scratch.begin(), scratch.end()); break; case index_block::DECL_CONTEXT_OFFSETS: assert(blobData.empty()); DeclContexts.assign(scratch.begin(), scratch.end()); break; case index_block::TYPE_OFFSETS: assert(blobData.empty()); Types.assign(scratch.begin(), scratch.end()); break; case index_block::IDENTIFIER_OFFSETS: assert(blobData.empty()); Identifiers.assign(scratch.begin(), scratch.end()); break; case index_block::TOP_LEVEL_DECLS: TopLevelDecls = readDeclTable(scratch, blobData); break; case index_block::OPERATORS: OperatorDecls = readDeclTable(scratch, blobData); break; case index_block::EXTENSIONS: ExtensionDecls = readDeclTable(scratch, blobData); break; case index_block::CLASS_MEMBERS: ClassMembersByName = readDeclTable(scratch, blobData); break; case index_block::OPERATOR_METHODS: OperatorMethodDecls = readDeclTable(scratch, blobData); break; case index_block::OBJC_METHODS: ObjCMethods = readObjCMethodTable(scratch, blobData); break; case index_block::ENTRY_POINT: assert(blobData.empty()); setEntryPointClassID(scratch.front()); break; case index_block::LOCAL_TYPE_DECLS: LocalTypeDecls = readLocalDeclTable(scratch, blobData); break; case index_block::LOCAL_DECL_CONTEXT_OFFSETS: assert(blobData.empty()); LocalDeclContexts.assign(scratch.begin(), scratch.end()); break; case index_block::NORMAL_CONFORMANCE_OFFSETS: assert(blobData.empty()); NormalConformances.assign(scratch.begin(), scratch.end()); break; default: // Unknown index kind, which this version of the compiler won't use. break; } break; } } }
static ValidationInfo validateControlBlock(llvm::BitstreamCursor &cursor, SmallVectorImpl<uint64_t> &scratch, ExtendedValidationInfo *extendedInfo) { // The control block is malformed until we've at least read a major version // number. ValidationInfo result; bool versionSeen = false; auto next = cursor.advance(); while (next.Kind != llvm::BitstreamEntry::EndBlock) { if (next.Kind == llvm::BitstreamEntry::Error) { result.status = Status::Malformed; return result; } if (next.Kind == llvm::BitstreamEntry::SubBlock) { if (next.ID == OPTIONS_BLOCK_ID && extendedInfo) { cursor.EnterSubBlock(OPTIONS_BLOCK_ID); if (!readOptionsBlock(cursor, scratch, *extendedInfo)) { result.status = Status::Malformed; return result; } } else { // Unknown metadata sub-block, possibly for use by a future version of // the module format. if (cursor.SkipBlock()) { result.status = Status::Malformed; return result; } } next = cursor.advance(); continue; } scratch.clear(); StringRef blobData; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case control_block::METADATA: { if (versionSeen) { result.status = Status::Malformed; break; } uint16_t versionMajor = scratch[0]; if (versionMajor > VERSION_MAJOR) result.status = Status::FormatTooNew; else if (versionMajor < VERSION_MAJOR) result.status = Status::FormatTooOld; else result.status = Status::Valid; // Major version 0 does not have stable minor versions. if (versionMajor == 0) { uint16_t versionMinor = scratch[1]; if (versionMinor != VERSION_MINOR) { if (versionMinor < VERSION_MINOR) result.status = Status::FormatTooOld; else result.status = Status::FormatTooNew; } } versionSeen = true; break; } case control_block::MODULE_NAME: result.name = blobData; break; case control_block::TARGET: result.targetTriple = blobData; break; default: // Unknown metadata record, possibly for use by a future version of the // module format. break; } next = cursor.advance(); } return result; }
GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer, llvm::BitstreamCursor Cursor) : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(), NumIdentifierLookupHits() { // Read the global index. bool InGlobalIndexBlock = false; bool Done = false; while (!Done) { llvm::BitstreamEntry Entry = Cursor.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: return; case llvm::BitstreamEntry::EndBlock: if (InGlobalIndexBlock) { InGlobalIndexBlock = false; Done = true; continue; } return; case llvm::BitstreamEntry::Record: // Entries in the global index block are handled below. if (InGlobalIndexBlock) break; return; case llvm::BitstreamEntry::SubBlock: if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) return; InGlobalIndexBlock = true; } else if (Cursor.SkipBlock()) { return; } continue; } SmallVector<uint64_t, 64> Record; StringRef Blob; switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) { case INDEX_METADATA: // Make sure that the version matches. if (Record.size() < 1 || Record[0] != CurrentVersion) return; break; case MODULE: { unsigned Idx = 0; unsigned ID = Record[Idx++]; // Make room for this module's information. if (ID == Modules.size()) Modules.push_back(ModuleInfo()); else Modules.resize(ID + 1); // Size/modification time for this module file at the time the // global index was built. Modules[ID].Size = Record[Idx++]; Modules[ID].ModTime = Record[Idx++]; // File name. unsigned NameLen = Record[Idx++]; Modules[ID].FileName.assign(Record.begin() + Idx, Record.begin() + Idx + NameLen); Idx += NameLen; // Dependencies unsigned NumDeps = Record[Idx++]; Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(), Record.begin() + Idx, Record.begin() + Idx + NumDeps); Idx += NumDeps; // Make sure we're at the end of the record. assert(Idx == Record.size() && "More module info?"); // Record this module as an unresolved module. // FIXME: this doesn't work correctly for module names containing path // separators. StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName); // Remove the -<hash of ModuleMapPath> ModuleName = ModuleName.rsplit('-').first; UnresolvedModules[ModuleName] = ID; break; } case IDENTIFIER_INDEX: // Wire up the identifier index. if (Record[0]) { IdentifierIndex = IdentifierIndexTable::Create( (const unsigned char *)Blob.data() + Record[0], (const unsigned char *)Blob.data() + sizeof(uint32_t), (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait()); } break; } } }
GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr, llvm::MemoryBuffer *Buffer, llvm::BitstreamCursor Cursor) : Buffer(Buffer), IdentifierIndex(), NumIdentifierLookups(), NumIdentifierLookupHits() { typedef llvm::DenseMap<unsigned, LoadedModuleInfo> LoadedModulesMap; LoadedModulesMap LoadedModules; // Read the global index. unsigned LargestID = 0; bool InGlobalIndexBlock = false; bool Done = false; bool AnyOutOfDate = false; while (!Done) { llvm::BitstreamEntry Entry = Cursor.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: return; case llvm::BitstreamEntry::EndBlock: if (InGlobalIndexBlock) { InGlobalIndexBlock = false; Done = true; continue; } return; case llvm::BitstreamEntry::Record: // Entries in the global index block are handled below. if (InGlobalIndexBlock) break; return; case llvm::BitstreamEntry::SubBlock: if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) return; InGlobalIndexBlock = true; } else if (Cursor.SkipBlock()) { return; } continue; } SmallVector<uint64_t, 64> Record; StringRef Blob; switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) { case INDEX_METADATA: // Make sure that the version matches. if (Record.size() < 1 || Record[0] != CurrentVersion) return; break; case MODULE: { unsigned Idx = 0; unsigned ID = Record[Idx++]; if (ID > LargestID) LargestID = ID; off_t Size = Record[Idx++]; time_t ModTime = Record[Idx++]; // File name. unsigned NameLen = Record[Idx++]; llvm::SmallString<64> FileName(Record.begin() + Idx, Record.begin() + Idx + NameLen); Idx += NameLen; // Dependencies unsigned NumDeps = Record[Idx++]; llvm::SmallVector<unsigned, 2> Dependencies(Record.begin() + Idx, Record.begin() + Idx + NumDeps); // Find the file. If we can't find it, ignore it. const FileEntry *File = FileMgr.getFile(FileName); if (!File) { AnyOutOfDate = true; break; } // If the module file is newer than the index, ignore it. if (File->getSize() != Size || File->getModificationTime() != ModTime) { AnyOutOfDate = true; break; } // Record this module. The dependencies will be resolved later. LoadedModuleInfo &Info = LoadedModules[ID]; Info.File = File; Info.Dependencies.swap(Dependencies); break; } case IDENTIFIER_INDEX: // Wire up the identifier index. if (Record[0]) { IdentifierIndex = IdentifierIndexTable::Create( (const unsigned char *)Blob.data() + Record[0], (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait()); } break; } } // If there are any modules that have gone out-of-date, prune out any modules // that depend on them. if (AnyOutOfDate) { // First, build back links in the module dependency graph. SmallVector<unsigned, 4> Stack; for (LoadedModulesMap::iterator LM = LoadedModules.begin(), LMEnd = LoadedModules.end(); LM != LMEnd; ++LM) { unsigned ID = LM->first; // If this module is out-of-date, push it onto the stack. if (LM->second.File == 0) Stack.push_back(ID); for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) { unsigned DepID = LM->second.Dependencies[I]; LoadedModulesMap::iterator Known = LoadedModules.find(DepID); if (Known == LoadedModules.end() || !Known->second.File) { // The dependency was out-of-date, so mark us as out of date. // This is just an optimization. if (LM->second.File) Stack.push_back(ID); LM->second.File = 0; continue; } // Record this reverse dependency. Known->second.ImportedBy.push_back(ID); } } // Second, walk the back links from out-of-date modules to those modules // that depend on them, making those modules out-of-date as well. while (!Stack.empty()) { unsigned ID = Stack.back(); Stack.pop_back(); LoadedModuleInfo &Info = LoadedModules[ID]; for (unsigned I = 0, N = Info.ImportedBy.size(); I != N; ++I) { unsigned FromID = Info.ImportedBy[I]; if (LoadedModules[FromID].File) { LoadedModules[FromID].File = 0; Stack.push_back(FromID); } } } } // Allocate the vector containing information about all of the modules. Modules.resize(LargestID + 1); for (LoadedModulesMap::iterator LM = LoadedModules.begin(), LMEnd = LoadedModules.end(); LM != LMEnd; ++LM) { if (!LM->second.File) continue; Modules[LM->first].File = LM->second.File; // Resolve dependencies. Drop any we can't resolve due to out-of-date // module files. for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) { unsigned DepID = LM->second.Dependencies[I]; LoadedModulesMap::iterator Known = LoadedModules.find(DepID); if (Known == LoadedModules.end() || !Known->second.File) continue; Modules[LM->first].Dependencies.push_back(Known->second.File); } } }