]> granicus.if.org Git - clang/commitdiff
First baby steps towards PCHReader being able to keep track of multiple PCH files...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Fri, 16 Jul 2010 17:50:48 +0000 (17:50 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Fri, 16 Jul 2010 17:50:48 +0000 (17:50 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108537 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Frontend/PCHReader.h
lib/Frontend/PCHReader.cpp
lib/Frontend/PCHReaderDecl.cpp
lib/Frontend/PCHReaderStmt.cpp

index 47e871f50aeba9405979da487ba4b2e8afb32337..654f4a6e4f62ef8bba3d38b8cb7385fddd725dbc 100644 (file)
@@ -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 PCH stat cache installed for this file, if any.
+    ///
+    /// The dynamic type of this stat cache is always PCHStatCache
+    void *StatCache;
 
-  /// \brief The cursor to the start of the preprocessor block, which stores
-  /// all of the macro definitions.
-  llvm::BitstreamCursor MacroCursor;
+    /// \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<llvm::MemoryBuffer> Buffer;
+    /// \brief The memory buffer that stores the data associated with
+    /// this PCH file.
+    llvm::OwningPtr<llvm::MemoryBuffer> 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<PerFileData*, 2> 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<QualType> 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.
index c0ad12f6990886cc364803970b54c4acef8bdffb..08db0398828b5661a3282a85053fc125b99c71cf 100644 (file)
@@ -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);
index 742f0e46b92ca4583a6517ce69051f2b799467fd..c8851a7ecc0249132e2ecfd06fbdb0e267dca5c8 100644 (file)
@@ -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);
index ace62d787ed91a1a0965a24fca1322f119602602..051b2257e47c4fd4c9f3a25cf8930746ace64ba4 100644 (file)
@@ -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();
   }