diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-10-18 05:31:06 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-10-18 05:31:06 +0000 |
commit | 1d9d9898ce2b338314161d92f39561a09a2a8b6f (patch) | |
tree | 2975de225d66cfcc442f39732f1cea2e052c881d /lib/Serialization/ASTReader.cpp | |
parent | 7c008813e17ddc2bb3953e925a86db3e1bf30198 (diff) |
Start factoring the on-disk records for an AST file into a control
block, which stores information about how the AST file to generated,
from the AST block, which stores the actual serialized AST. The
information in the control block should be enough to determine whether
the AST file is up-to-date and compatible with the current translation
unit, and reading it should not cause any side effects that aren't
easy to undo. That way, we can back out from an attempt to read an
incompatible or out-of-date AST file.
Note that there is still more factoring to do. In particular,
information about the source files used to generate the AST file
(along with their time stamps, sizes, etc.) still resides in the
source manager block.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166166 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Serialization/ASTReader.cpp')
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 335 |
1 files changed, 203 insertions, 132 deletions
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 67a54caf64..5d2e8d6cfc 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1744,6 +1744,152 @@ void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) { Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end()); } +ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F, + llvm::SmallVectorImpl<ModuleFile *> &Loaded) { + llvm::BitstreamCursor &Stream = F.Stream; + + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { + Error("malformed block record in AST file"); + return Failure; + } + + // Read all of the records and blocks in the control block. + RecordData Record; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + Error("error at end of control block in AST file"); + return Failure; + } + + return Success; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + Stream.ReadSubBlockID(); + if (!Stream.SkipBlock()) + continue; + + Error("malformed block record in AST file"); + return Failure; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read and process a record. + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record, + &BlobStart, &BlobLen)) { + case METADATA: { + if (Record[0] != VERSION_MAJOR && !DisableValidation) { + Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old + : diag::warn_pch_version_too_new); + return IgnorePCH; + } + + bool hasErrors = Record[5]; + if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { + Diag(diag::err_pch_with_compiler_errors); + return IgnorePCH; + } + + RelocatablePCH = Record[4]; + if (Listener && &F == *ModuleMgr.begin()) { + unsigned Idx = 6; + TargetOptions TargetOpts; + TargetOpts.Triple = ReadString(Record, Idx); + TargetOpts.CPU = ReadString(Record, Idx); + TargetOpts.ABI = ReadString(Record, Idx); + TargetOpts.CXXABI = ReadString(Record, Idx); + TargetOpts.LinkerVersion = ReadString(Record, Idx); + for (unsigned N = Record[Idx++]; N; --N) { + TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx)); + } + for (unsigned N = Record[Idx++]; N; --N) { + TargetOpts.Features.push_back(ReadString(Record, Idx)); + } + + if (Listener->ReadTargetOptions(F, TargetOpts)) + return IgnorePCH; + } + break; + } + + case IMPORTS: { + // Load each of the imported PCH files. + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + // Read information about the AST file. + ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; + unsigned Length = Record[Idx++]; + SmallString<128> ImportedFile(Record.begin() + Idx, + Record.begin() + Idx + Length); + Idx += Length; + + // Load the AST file. + switch(ReadASTCore(ImportedFile, ImportedKind, &F, Loaded)) { + case Failure: return Failure; + // If we have to ignore the dependency, we'll have to ignore this too. + case IgnorePCH: return IgnorePCH; + case Success: break; + } + } + break; + } + + case LANGUAGE_OPTIONS: + if (&F == *ModuleMgr.begin() && + ParseLanguageOptions(F, Record) && !DisableValidation) + return IgnorePCH; + break; + + case ORIGINAL_FILE_NAME: + // Only record from the primary AST file. + if (&F == *ModuleMgr.begin()) { + // The primary AST will be the last to get here, so it will be the one + // that's used. + ActualOriginalFileName.assign(BlobStart, BlobLen); + OriginalFileName = ActualOriginalFileName; + MaybeAddSystemRootToFilename(OriginalFileName); + } + break; + + case ORIGINAL_FILE_ID: + // Only record from the primary AST file. + if (&F == *ModuleMgr.begin()) { + OriginalFileID = FileID::get(Record[0]); + } + break; + + case ORIGINAL_PCH_DIR: + // Only record from the primary AST file. + if (&F == *ModuleMgr.begin()) { + OriginalDir.assign(BlobStart, BlobLen); + } + break; + + case VERSION_CONTROL_BRANCH_REVISION: { + const std::string &CurBranch = getClangFullRepositoryVersion(); + StringRef ASTBranch(BlobStart, BlobLen); + if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { + Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; + return IgnorePCH; + } + break; + } + } + } + + Error("premature end of bitstream in AST file"); + return Failure; +} + ASTReader::ASTReadResult ASTReader::ReadASTBlock(ModuleFile &F) { llvm::BitstreamCursor &Stream = F.Stream; @@ -1753,7 +1899,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { return Failure; } - // Read all of the records and blocks for the ASt file. + // Read all of the records and blocks for the AST file. RecordData Record; while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); @@ -1885,63 +2031,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) { default: // Default behavior: ignore. break; - case METADATA: { - if (Record[0] != VERSION_MAJOR && !DisableValidation) { - Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old - : diag::warn_pch_version_too_new); - return IgnorePCH; - } - - bool hasErrors = Record[5]; - if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { - Diag(diag::err_pch_with_compiler_errors); - return IgnorePCH; - } - - RelocatablePCH = Record[4]; - if (Listener) { - unsigned Idx = 6; - TargetOptions TargetOpts; - TargetOpts.Triple = ReadString(Record, Idx); - TargetOpts.CPU = ReadString(Record, Idx); - TargetOpts.ABI = ReadString(Record, Idx); - TargetOpts.CXXABI = ReadString(Record, Idx); - TargetOpts.LinkerVersion = ReadString(Record, Idx); - for (unsigned N = Record[Idx++]; N; --N) { - TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx)); - } - for (unsigned N = Record[Idx++]; N; --N) { - TargetOpts.Features.push_back(ReadString(Record, Idx)); - } - - if (Listener->ReadTargetOptions(F, TargetOpts)) - return IgnorePCH; - } - break; - } - - case IMPORTS: { - // Load each of the imported PCH files. - unsigned Idx = 0, N = Record.size(); - while (Idx < N) { - // Read information about the AST file. - ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; - unsigned Length = Record[Idx++]; - SmallString<128> ImportedFile(Record.begin() + Idx, - Record.begin() + Idx + Length); - Idx += Length; - - // Load the AST file. - switch(ReadASTCore(ImportedFile, ImportedKind, &F)) { - case Failure: return Failure; - // If we have to ignore the dependency, we'll have to ignore this too. - case IgnorePCH: return IgnorePCH; - case Success: break; - } - } - break; - } - case TYPE_OFFSET: { if (F.LocalNumTypes != 0) { Error("duplicate TYPE_OFFSET record in AST file"); @@ -2023,11 +2112,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) { break; } - case LANGUAGE_OPTIONS: - if (ParseLanguageOptions(F, Record) && !DisableValidation) - return IgnorePCH; - break; - case IDENTIFIER_TABLE: F.IdentifierTableData = BlobStart; if (Record[0]) { @@ -2364,34 +2448,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) { SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; - case ORIGINAL_FILE_NAME: - // The primary AST will be the last to get here, so it will be the one - // that's used. - ActualOriginalFileName.assign(BlobStart, BlobLen); - OriginalFileName = ActualOriginalFileName; - MaybeAddSystemRootToFilename(OriginalFileName); - break; - - case ORIGINAL_FILE_ID: - OriginalFileID = FileID::get(Record[0]); - break; - - case ORIGINAL_PCH_DIR: - // The primary AST will be the last to get here, so it will be the one - // that's used. - OriginalDir.assign(BlobStart, BlobLen); - break; - - case VERSION_CONTROL_BRANCH_REVISION: { - const std::string &CurBranch = getClangFullRepositoryVersion(); - StringRef ASTBranch(BlobStart, BlobLen); - if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { - Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; - return IgnorePCH; - } - break; - } - case PPD_ENTITIES_OFFSETS: { F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart; assert(BlobLen % sizeof(PPEntityOffset) == 0); @@ -2839,8 +2895,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, ModuleKind Type) { // Bump the generation number. unsigned PreviousGeneration = CurrentGeneration++; - - switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) { + + // Load the core of the AST files. + llvm::SmallVector<ModuleFile *, 4> Loaded; + switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0, Loaded)) { case Failure: return Failure; case IgnorePCH: return IgnorePCH; case Success: break; @@ -2848,6 +2906,47 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, // Here comes stuff that we only do once the entire chain is loaded. + // Load the AST blocks of all of the modules that we loaded. + for (llvm::SmallVectorImpl<ModuleFile *>::iterator M = Loaded.begin(), + MEnd = Loaded.end(); + M != MEnd; ++M) { + ModuleFile &F = **M; + + // Read the AST block. + switch(ReadASTBlock(F)) { + case Failure: return Failure; + case IgnorePCH: return IgnorePCH; + case Success: break; + } + + // Once read, set the ModuleFile bit base offset and update the size in + // bits of all files we've seen. + F.GlobalBitOffset = TotalModulesSizeInBits; + TotalModulesSizeInBits += F.SizeInBits; + GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); + + // Make sure that the files this module was built against are + // still available. + // FIXME: Move this validation into ReadControlBlock. + if (!DisableValidation) { + switch(validateFileEntries(F)) { + case Failure: return Failure; + case IgnorePCH: return IgnorePCH; + case Success: break; + } + } + + // Preload SLocEntries. + for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) { + int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; + // Load it through the SourceManager and don't call ReadSLocEntryRecord() + // directly because the entry may have already been loaded in which case + // calling ReadSLocEntryRecord() directly would trigger an assertion in + // SourceManager. + SourceMgr.getLoadedSLocEntryByID(Index); + } + } + // Check the predefines buffers. if (!DisableValidation && Type == MK_PCH && // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines; @@ -2914,7 +3013,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, ModuleKind Type, - ModuleFile *ImportedBy) { + ModuleFile *ImportedBy, + llvm::SmallVectorImpl<ModuleFile *> &Loaded) { ModuleFile *M; bool NewModule; std::string ErrorStr; @@ -2973,8 +3073,8 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, return Failure; } break; - case AST_BLOCK_ID: - switch (ReadASTBlock(F)) { + case CONTROL_BLOCK_ID: + switch (ReadControlBlock(F, Loaded)) { case Success: break; @@ -2985,17 +3085,14 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, // FIXME: We could consider reading through to the end of this // AST block, skipping subblocks, to see if there are other // AST blocks elsewhere. - - // FIXME: We can't clear loaded slocentries anymore. - //SourceMgr.ClearPreallocatedSLocEntries(); - - // Remove the stat cache. - if (F.StatCache) - FileMgr.removeStatCache((ASTStatCache*)F.StatCache); - return IgnorePCH; } break; + case AST_BLOCK_ID: + // Record that we've loaded this module. + Loaded.push_back(M); + return Success; + default: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); @@ -3005,32 +3102,6 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, } } - // Once read, set the ModuleFile bit base offset and update the size in - // bits of all files we've seen. - F.GlobalBitOffset = TotalModulesSizeInBits; - TotalModulesSizeInBits += F.SizeInBits; - GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); - - // Make sure that the files this module was built against are still available. - if (!DisableValidation) { - switch(validateFileEntries(*M)) { - case Failure: return Failure; - case IgnorePCH: return IgnorePCH; - case Success: break; - } - } - - // Preload SLocEntries. - for (unsigned I = 0, N = M->PreloadSLocEntries.size(); I != N; ++I) { - int Index = int(M->PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; - // Load it through the SourceManager and don't call ReadSLocEntryRecord() - // directly because the entry may have already been loaded in which case - // calling ReadSLocEntryRecord() directly would trigger an assertion in - // SourceManager. - SourceMgr.getLoadedSLocEntryByID(Index); - } - - return Success; } @@ -3218,8 +3289,8 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, // We only know the AST subblock ID. switch (BlockID) { - case AST_BLOCK_ID: - if (Stream.EnterSubBlock(AST_BLOCK_ID)) { + case CONTROL_BLOCK_ID: + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } |