From 34522813e715638a30dc91faa88bcb4e3adaeee2 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Fri, 16 Jul 2010 17:50:48 +0000 Subject: [PATCH] First baby steps towards PCHReader being able to keep track of multiple PCH files. WIP llvm-svn: 108537 --- clang/include/clang/Frontend/PCHReader.h | 97 ++++++++++++++---------- clang/lib/Frontend/PCHReader.cpp | 66 +++++++++++----- clang/lib/Frontend/PCHReaderDecl.cpp | 2 + clang/lib/Frontend/PCHReaderStmt.cpp | 2 +- 4 files changed, 109 insertions(+), 58 deletions(-) diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index 47e871f50aeb..654f4a6e4f62 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -147,14 +147,14 @@ private: void Error(const char *Msg); }; -/// \brief Reads a precompiled head containing the contents of a +/// \brief Reads a precompiled header chain containing the contents of a /// translation unit. /// -/// The PCHReader class reads a bitstream (produced by the PCHWriter +/// The PCHReader class reads bitstreams (produced by the PCHWriter /// class) containing the serialized representation of a given /// abstract syntax tree and its supporting data structures. An /// instance of the PCHReader can be attached to an ASTContext object, -/// which will provide access to the contents of the PCH file. +/// which will provide access to the contents of the PCH files. /// /// The PCH reader provides lazy de-serialization of declarations, as /// required when traversing the AST. Only those AST nodes that are @@ -181,65 +181,86 @@ private: Diagnostic &Diags; /// \brief The semantic analysis object that will be processing the - /// PCH file and the translation unit that uses it. + /// PCH files and the translation unit that uses it. Sema *SemaObj; /// \brief The preprocessor that will be loading the source file. Preprocessor *PP; - /// \brief The AST context into which we'll read the PCH file. + /// \brief The AST context into which we'll read the PCH files. ASTContext *Context; - - /// \brief The PCH stat cache installed by this PCHReader, if any. - /// - /// The dynamic type of this stat cache is always PCHStatCache - void *StatCache; /// \brief The AST consumer. ASTConsumer *Consumer; - /// \brief The bitstream reader from which we'll read the PCH file. - llvm::BitstreamReader StreamFile; - llvm::BitstreamCursor Stream; + /// \brief Information that is needed for every file in the chain. + struct PerFileData { + PerFileData(); - /// \brief The cursor to the start of the preprocessor block, which stores - /// all of the macro definitions. - llvm::BitstreamCursor MacroCursor; + /// \brief The PCH stat cache installed for this file, if any. + /// + /// The dynamic type of this stat cache is always PCHStatCache + void *StatCache; + + /// \brief The bitstream reader from which we'll read the PCH file. + llvm::BitstreamReader StreamFile; + llvm::BitstreamCursor Stream; + + /// \brief The cursor to the start of the preprocessor block, which stores + /// all of the macro definitions. + llvm::BitstreamCursor MacroCursor; - /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It - /// has read all the abbreviations at the start of the block and is ready to - /// jump around with these in context. - llvm::BitstreamCursor DeclsCursor; + /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It + /// has read all the abbreviations at the start of the block and is ready to + /// jump around with these in context. + llvm::BitstreamCursor DeclsCursor; - /// \brief The file name of the PCH file. - std::string FileName; + /// \brief The file name of the PCH file. + std::string FileName; - /// \brief The memory buffer that stores the data associated with - /// this PCH file. - llvm::OwningPtr Buffer; + /// \brief The memory buffer that stores the data associated with + /// this PCH file. + llvm::OwningPtr Buffer; - /// \brief Offset type for all of the source location entries in the - /// PCH file. + /// \brief Cursor used to read source location entries. + llvm::BitstreamCursor SLocEntryCursor; + + /// \brief The number of source location entries in this PCH file. + unsigned LocalNumSLocEntries; + + /// \brief The number of types in this PCH file. + unsigned LocalNumTypes; + + /// \brief The number of declarations in this PCH file. + unsigned LocalNumDecls; + }; + + /// \brief The chain of PCH files. The first entry is the one named by the + /// user, the last one is the one that doesn't depend on anything further. + llvm::SmallVector Chain; + + /// \brief Offsets for all of the source location entries in the + /// PCH files. The offsets are relative to a particular file; the correct + /// file is chosen using their IDs. const uint32_t *SLocOffsets; - /// \brief The number of source location entries in the PCH file. + /// \brief The number of source location entries in all PCH files. unsigned TotalNumSLocEntries; - /// \brief Cursor used to read source location entries. - llvm::BitstreamCursor SLocEntryCursor; - /// \brief Offset of each type within the bitstream, indexed by the - /// type ID, or the representation of a Type*. + /// type ID, or the representation of a Type*. The offset is local to the + /// containing file; the file is chosen using the ID. const uint32_t *TypeOffsets; /// \brief Types that have already been loaded from the PCH file. /// /// When the pointer at index I is non-NULL, the type with - /// ID = (I + 1) << 3 has already been loaded from the PCH file. + /// ID = (I + 1) << FastQual::Width has already been loaded from the PCH chain std::vector TypesLoaded; /// \brief Offset of each declaration within the bitstream, indexed - /// by the declaration ID (-1). + /// by the declaration ID (-1). The offset is local to the containing file; + /// the file is chosen using the ID. const uint32_t *DeclOffsets; /// \brief Declarations that have already been loaded from the PCH file. @@ -588,8 +609,8 @@ public: /// \brief Sets and initializes the given Context. void InitializeContext(ASTContext &Context); - /// \brief Retrieve the name of the PCH file - const std::string &getFileName() const { return FileName; } + /// \brief Retrieve the name of the named (primary) PCH file + const std::string &getFileName() const { return Chain[0]->FileName; } /// \brief Retrieve the name of the original source file name const std::string &getOriginalSourceFile() { return OriginalFileName; } @@ -844,8 +865,8 @@ public: Sema *getSema() { return SemaObj; } /// \brief Retrieve the stream that this PCH reader is reading from. - llvm::BitstreamCursor &getStream() { return Stream; } - llvm::BitstreamCursor &getDeclsCursor() { return DeclsCursor; } + llvm::BitstreamCursor &getStream() { return Chain[0]->Stream; } + llvm::BitstreamCursor &getDeclsCursor() { return Chain[0]->DeclsCursor; } /// \brief Retrieve the identifier table associated with the /// preprocessor. diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index c0ad12f69908..08db0398828b 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -418,7 +418,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context), - StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), + Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), TotalSelectorsInMethodPool(0), SelectorOffsets(0), @@ -435,7 +435,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, Diagnostic &Diags, const char *isysroot) : DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr), - Diags(Diags), SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0), + Diags(Diags), SemaObj(0), PP(0), Context(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), @@ -450,7 +450,14 @@ PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, RelocatablePCH = false; } -PCHReader::~PCHReader() {} +PCHReader::~PCHReader() { + for (unsigned i = 0, e = Chain.size(); i != e; ++i) + delete Chain[e - i - 1]; +} + +PCHReader::PerFileData::PerFileData() + : StatCache(0) +{} namespace { @@ -878,14 +885,16 @@ public: PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { using namespace SrcMgr; + llvm::BitstreamCursor &SLocEntryCursor = Chain[0]->SLocEntryCursor; + // Set the source-location entry cursor to the current position in // the stream. This cursor will be used to read the contents of the // source manager block initially, and then lazily read // source-location entries as needed. - SLocEntryCursor = Stream; + SLocEntryCursor = Chain[0]->Stream; // The stream itself is going to skip over the source manager block. - if (Stream.SkipBlock()) { + if (Chain[0]->Stream.SkipBlock()) { Error("malformed block record in PCH file"); return Failure; } @@ -954,6 +963,8 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { return Failure; } + llvm::BitstreamCursor &SLocEntryCursor = Chain[0]->SLocEntryCursor; + ++NumSLocEntriesRead; SLocEntryCursor.JumpToBit(SLocOffsets[ID - 1]); unsigned Code = SLocEntryCursor.ReadCode(); @@ -1089,6 +1100,8 @@ bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, void PCHReader::ReadMacroRecord(uint64_t Offset) { assert(PP && "Forgot to set Preprocessor ?"); + llvm::BitstreamCursor &Stream = Chain[0]->Stream; + // Keep track of where we are in the stream, then jump back there // after reading this macro. SavedStreamPosition SavedPosition(Stream); @@ -1258,6 +1271,8 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { } void PCHReader::ReadDefinedMacros() { + llvm::BitstreamCursor &MacroCursor = Chain[0]->MacroCursor; + // If there was no preprocessor block, do nothing. if (!MacroCursor.getBitStreamReader()) return; @@ -1354,6 +1369,9 @@ void PCHReader::MaybeAddSystemRootToFilename(std::string &Filename) { PCHReader::PCHReadResult PCHReader::ReadPCHBlock() { + PerFileData &F = *Chain[0]; + llvm::BitstreamCursor &Stream = F.Stream; + if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { Error("malformed block record in PCH file"); return Failure; @@ -1379,17 +1397,17 @@ PCHReader::ReadPCHBlock() { // DeclsCursor cursor to point into it. Clone our current bitcode // cursor to it, enter the block and read the abbrevs in that block. // With the main cursor, we just skip over it. - DeclsCursor = Stream; + F.DeclsCursor = Stream; if (Stream.SkipBlock() || // Skip with the main cursor. // Read the abbrevs. - ReadBlockAbbrevs(DeclsCursor, pch::DECLTYPES_BLOCK_ID)) { + ReadBlockAbbrevs(F.DeclsCursor, pch::DECLTYPES_BLOCK_ID)) { Error("malformed block record in PCH file"); return Failure; } break; case pch::PREPROCESSOR_BLOCK_ID: - MacroCursor = Stream; + F.MacroCursor = Stream; if (PP) PP->setExternalSource(this); @@ -1578,7 +1596,7 @@ PCHReader::ReadPCHBlock() { (const unsigned char *)BlobStart, NumStatHits, NumStatMisses); FileMgr.addStatCache(MyStatCache); - StatCache = MyStatCache; + F.StatCache = MyStatCache; break; } @@ -1641,23 +1659,27 @@ PCHReader::ReadPCHBlock() { } PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { + Chain.push_back(new PerFileData()); + PerFileData &F = *Chain.back(); + // Set the PCH file name. - this->FileName = FileName; + F.FileName = FileName; // Open the PCH file. // // FIXME: This shouldn't be here, we should just take a raw_ostream. std::string ErrStr; - Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr)); - if (!Buffer) { + F.Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr)); + if (!F.Buffer) { Error(ErrStr.c_str()); return IgnorePCH; } // Initialize the stream - StreamFile.init((const unsigned char *)Buffer->getBufferStart(), - (const unsigned char *)Buffer->getBufferEnd()); - Stream.init(StreamFile); + F.StreamFile.init((const unsigned char *)F.Buffer->getBufferStart(), + (const unsigned char *)F.Buffer->getBufferEnd()); + llvm::BitstreamCursor &Stream = F.Stream; + Stream.init(F.StreamFile); // Sniff for the signature. if (Stream.Read(8) != 'C' || @@ -1704,8 +1726,8 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { SourceMgr.ClearPreallocatedSLocEntries(); // Remove the stat cache. - if (StatCache) - FileMgr.removeStatCache((PCHStatCache*)StatCache); + if (F.StatCache) + FileMgr.removeStatCache((PCHStatCache*)F.StatCache); return IgnorePCH; } @@ -2049,6 +2071,8 @@ void PCHReader::ReadPreprocessedEntities() { /// at the given offset in the bitstream. It is a helper routine for /// GetType, which deals with reading type IDs. QualType PCHReader::ReadTypeRecord(uint64_t Offset) { + llvm::BitstreamCursor &DeclsCursor = Chain[0]->DeclsCursor; + // Keep track of where we are in the stream, then jump back there // after reading this type. SavedStreamPosition SavedPosition(DeclsCursor); @@ -2716,8 +2740,8 @@ Decl *PCHReader::GetDecl(pch::DeclID ID) { Stmt *PCHReader::GetExternalDeclStmt(uint64_t Offset) { // Since we know tha this statement is part of a decl, make sure to use the // decl cursor to read it. - DeclsCursor.JumpToBit(Offset); - return ReadStmtFromStream(DeclsCursor); + Chain[0]->DeclsCursor.JumpToBit(Offset); + return ReadStmtFromStream(Chain[0]->DeclsCursor); } bool PCHReader::FindExternalLexicalDecls(const DeclContext *DC, @@ -2731,6 +2755,8 @@ bool PCHReader::FindExternalLexicalDecls(const DeclContext *DC, return true; } + llvm::BitstreamCursor &DeclsCursor = Chain[0]->DeclsCursor; + // Keep track of where we are in the stream, then jump back there // after reading this context. SavedStreamPosition SavedPosition(DeclsCursor); @@ -2765,6 +2791,8 @@ PCHReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclContext::lookup_iterator()); } + llvm::BitstreamCursor &DeclsCursor = Chain[0]->DeclsCursor; + // Keep track of where we are in the stream, then jump back there // after reading this context. SavedStreamPosition SavedPosition(DeclsCursor); diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index 742f0e46b92c..c8851a7ecc02 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -1038,6 +1038,7 @@ PCHDeclReader::VisitDeclContext(DeclContext *DC) { /// \brief Reads attributes from the current stream position. Attr *PCHReader::ReadAttributes() { + llvm::BitstreamCursor &DeclsCursor = Chain[0]->DeclsCursor; unsigned Code = DeclsCursor.ReadCode(); assert(Code == llvm::bitc::UNABBREV_RECORD && "Expected unabbreviated record"); (void)Code; @@ -1252,6 +1253,7 @@ static bool isConsumerInterestedIn(Decl *D) { /// \brief Read the declaration at the given offset from the PCH file. Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { + llvm::BitstreamCursor &DeclsCursor = Chain[0]->DeclsCursor; // Keep track of where we are in the stream, then jump back there // after reading this declaration. SavedStreamPosition SavedPosition(DeclsCursor); diff --git a/clang/lib/Frontend/PCHReaderStmt.cpp b/clang/lib/Frontend/PCHReaderStmt.cpp index ace62d787ed9..051b2257e47c 100644 --- a/clang/lib/Frontend/PCHReaderStmt.cpp +++ b/clang/lib/Frontend/PCHReaderStmt.cpp @@ -1215,7 +1215,7 @@ Stmt *PCHReader::ReadStmt() { case Read_Decl: case Read_Type: // Read a statement from the current DeclCursor. - return ReadStmtFromStream(DeclsCursor); + return ReadStmtFromStream(Chain[0]->DeclsCursor); case Read_Stmt: return ReadSubStmt(); }