[cfe-commits] r70196 - in /cfe/trunk: include/clang/Basic/SourceManager.h include/clang/Frontend/PCHBitCodes.h include/clang/Frontend/PCHReader.h lib/Basic/SourceManager.cpp lib/Frontend/PCHReader.cpp lib/Frontend/PCHWriter.cpp

Douglas Gregor dgregor at apple.com
Sun Apr 26 23:38:35 PDT 2009


Author: dgregor
Date: Mon Apr 27 01:38:32 2009
New Revision: 70196

URL: http://llvm.org/viewvc/llvm-project?rev=70196&view=rev
Log:
Load most of the source manager's information lazily from the PCH
file. In particular, only eagerly load source location entries for
files and for the predefines buffer. Other buffers and
macro-instantiation source location entries are loaded lazily.

With the Cocoa-prefixed "Hello, World", we only load 815/26555 source
location entities. This halves the amount of user time we spend in
this "Hello, World" program with -fsyntax-only (down to .007s).

This optimization is part 1 of 2 for the source manager. This
eliminates most of the user time in loading a PCH file. We still spend
too much time initialize File structures (especially in the calls to
stat), so we need to either make the loading of source location
entries for files lazy or import the stat cache from the PTH
implementation.


Modified:
    cfe/trunk/include/clang/Basic/SourceManager.h
    cfe/trunk/include/clang/Frontend/PCHBitCodes.h
    cfe/trunk/include/clang/Frontend/PCHReader.h
    cfe/trunk/lib/Basic/SourceManager.cpp
    cfe/trunk/lib/Frontend/PCHReader.cpp
    cfe/trunk/lib/Frontend/PCHWriter.cpp

Modified: cfe/trunk/include/clang/Basic/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/SourceManager.h?rev=70196&r1=70195&r2=70196&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/SourceManager.h (original)
+++ cfe/trunk/include/clang/Basic/SourceManager.h Mon Apr 27 01:38:32 2009
@@ -249,7 +249,16 @@
     }
   };
 }  // end SrcMgr namespace.
-  
+
+/// \brief External source of source location entries.
+class ExternalSLocEntrySource {
+public:
+  virtual ~ExternalSLocEntrySource();
+
+  /// \brief Read the source location entry with index ID.
+  virtual void ReadSLocEntry(unsigned ID) = 0;
+};
+
 /// SourceManager - This file handles loading and caching of source files into
 /// memory.  This object owns the MemoryBuffer objects for all of the loaded
 /// files and assigns unique FileID's for each unique #include chain.
@@ -281,7 +290,15 @@
   /// NextOffset - This is the next available offset that a new SLocEntry can
   /// start at.  It is SLocEntryTable.back().getOffset()+size of back() entry.
   unsigned NextOffset;
-  
+
+  /// \brief If source location entries are being lazily loaded from
+  /// an external source, this vector indicates whether the Ith source
+  /// location entry has already been loaded from the external storage.
+  std::vector<bool> SLocEntryLoaded;
+
+  /// \brief An external source for source location entries.
+  ExternalSLocEntrySource *ExternalSLocEntries;
+
   /// LastFileIDLookup - This is a one-entry cache to speed up getFileID.
   /// LastFileIDLookup records the last FileID looked up or created, because it
   /// is very common to look up many tokens from the same file.
@@ -308,7 +325,9 @@
   explicit SourceManager(const SourceManager&);
   void operator=(const SourceManager&);  
 public:
-  SourceManager() : LineTable(0), NumLinearScans(0), NumBinaryProbes(0) {
+  SourceManager() 
+    : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), 
+      NumBinaryProbes(0) {
     clearIDTables();
   }
   ~SourceManager();
@@ -337,19 +356,25 @@
   /// createFileID - Create a new FileID that represents the specified file
   /// being #included from the specified IncludePosition.  This returns 0 on
   /// error and translates NULL into standard input.
+  /// PreallocateID should be non-zero to specify which a pre-allocated, 
+  /// lazily computed source location is being filled in by this operation.
   FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos,
-                      SrcMgr::CharacteristicKind FileCharacter) {
+                      SrcMgr::CharacteristicKind FileCharacter,
+                      unsigned PreallocatedID = 0,
+                      unsigned Offset = 0) {
     const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
     if (IR == 0) return FileID();    // Error opening file?
-    return createFileID(IR, IncludePos, FileCharacter);
+    return createFileID(IR, IncludePos, FileCharacter, PreallocatedID, Offset);
   }
   
   /// createFileIDForMemBuffer - Create a new FileID that represents the
   /// specified memory buffer.  This does no caching of the buffer and takes
   /// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once.
-  FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
+  FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer,
+                                  unsigned PreallocatedID = 0,
+                                  unsigned Offset = 0) {
     return createFileID(createMemBufferContentCache(Buffer), SourceLocation(),
-                        SrcMgr::C_User);
+                        SrcMgr::C_User, PreallocatedID, Offset);
   }
   
   /// createMainFileIDForMembuffer - Create the FileID for a memory buffer
@@ -367,7 +392,9 @@
   SourceLocation createInstantiationLoc(SourceLocation Loc,
                                         SourceLocation InstantiationLocStart,
                                         SourceLocation InstantiationLocEnd,
-                                        unsigned TokLength);
+                                        unsigned TokLength,
+                                        unsigned PreallocatedID = 0,
+                                        unsigned Offset = 0);
   
   //===--------------------------------------------------------------------===//
   // FileID manipulation methods.
@@ -411,8 +438,9 @@
   /// getLocForStartOfFile - Return the source location corresponding to the
   /// first byte of the specified file.
   SourceLocation getLocForStartOfFile(FileID FID) const {
-    assert(FID.ID < SLocEntryTable.size() && SLocEntryTable[FID.ID].isFile());
-    unsigned FileOffset = SLocEntryTable[FID.ID].getOffset();
+    assert(FID.ID < SLocEntryTable.size() && "FileID out of range");
+    assert(getSLocEntry(FID).isFile() && "FileID is not a file");
+    unsigned FileOffset = getSLocEntry(FID).getOffset();
     return SourceLocation::getFileLoc(FileOffset);
   }
   
@@ -616,11 +644,21 @@
 
   const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const {
     assert(FID.ID < SLocEntryTable.size() && "Invalid id");
+    if (ExternalSLocEntries && 
+        FID.ID < SLocEntryLoaded.size() &&
+        !SLocEntryLoaded[FID.ID])
+      ExternalSLocEntries->ReadSLocEntry(FID.ID);
     return SLocEntryTable[FID.ID];
   }
 
   unsigned getNextOffset() const { return NextOffset; }
 
+  /// \brief Preallocate some number of source location entries, which
+  /// will be loaded as needed from the given external source.
+  void PreallocateSLocEntries(ExternalSLocEntrySource *Source,
+                              unsigned NumSLocEntries,
+                              unsigned NextOffset);
+
 private:
   /// isOffsetInFileID - Return true if the specified FileID contains the
   /// specified SourceLocation offset.  This is a very hot method.
@@ -632,7 +670,8 @@
     // If this is the last entry than it does.  Otherwise, the entry after it
     // has to not include it.
     if (FID.ID+1 == SLocEntryTable.size()) return true;
-    return SLocOffset < SLocEntryTable[FID.ID+1].getOffset();
+
+    return SLocOffset < getSLocEntry(FileID::get(FID.ID+1)).getOffset();
   }
   
   /// createFileID - Create a new fileID for the specified ContentCache and
@@ -640,7 +679,9 @@
   ///  corresponds to a file or some other input source.
   FileID createFileID(const SrcMgr::ContentCache* File,
                       SourceLocation IncludePos,
-                      SrcMgr::CharacteristicKind DirCharacter);
+                      SrcMgr::CharacteristicKind DirCharacter,
+                      unsigned PreallocatedID = 0,
+                      unsigned Offset = 0);
     
   const SrcMgr::ContentCache *
     getOrCreateContentCache(const FileEntry *SourceFile);

Modified: cfe/trunk/include/clang/Frontend/PCHBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHBitCodes.h?rev=70196&r1=70195&r2=70196&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHBitCodes.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Mon Apr 27 01:38:32 2009
@@ -173,7 +173,19 @@
 
       /// \brief The value of the next __COUNTER__ to dispense.
       /// [PP_COUNTER_VALUE, Val]
-      PP_COUNTER_VALUE = 14
+      PP_COUNTER_VALUE = 14,
+
+      /// \brief Record code for the table of offsets into the block
+      /// of source-location information.
+      SOURCE_LOCATION_OFFSETS = 15,
+
+      /// \brief Record code for the set of source location entries
+      /// that need to be preloaded by the PCH reader.
+      ///
+      /// This set contains the source location entry for the
+      /// predefines buffer and for any file entries that need to be
+      /// preloaded.
+      SOURCE_LOCATION_PRELOADS = 16
     };
 
     /// \brief Record types used within a source manager block.

Modified: cfe/trunk/include/clang/Frontend/PCHReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=70196&r1=70195&r2=70196&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHReader.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHReader.h Mon Apr 27 01:38:32 2009
@@ -21,6 +21,7 @@
 #include "clang/AST/Type.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
@@ -68,7 +69,8 @@
 class PCHReader 
   : public ExternalSemaSource, 
     public IdentifierInfoLookup,
-    public ExternalIdentifierLookup {
+    public ExternalIdentifierLookup,
+    public ExternalSLocEntrySource {
 public:
   enum PCHReadResult { Success, Failure, IgnorePCH };
 
@@ -102,6 +104,16 @@
   /// this PCH file.
   llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
 
+  /// \brief Offset type for all of the source location entries in the
+  /// PCH file.
+  const uint64_t *SLocOffsets;
+
+  /// \brief The number of source location entries in the PCH file.
+  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*.
   const uint64_t *TypeOffsets;
@@ -214,6 +226,10 @@
   /// been de-serialized.
   std::multimap<unsigned, AddrLabelExpr *> UnresolvedAddrLabelExprs;
 
+  /// \brief The number of source location entries de-serialized from
+  /// the PCH file.
+  unsigned NumSLocEntriesRead;
+
   /// \brief The number of statements (and expressions) de-serialized
   /// from the PCH file.
   unsigned NumStatementsRead;
@@ -257,6 +273,7 @@
                              unsigned PCHPredefLen,
                              FileID PCHBufferID);
   PCHReadResult ReadSourceManagerBlock();
+  PCHReadResult ReadSLocEntryRecord(unsigned ID);
   
   bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record);
   QualType ReadTypeRecord(uint64_t Offset);
@@ -380,6 +397,9 @@
     return DecodeIdentifierInfo(ID);
   }
 
+  /// \brief Read the source location entry with index ID.
+  virtual void ReadSLocEntry(unsigned ID);
+
   Selector DecodeSelector(unsigned Idx);
   
   Selector GetSelector(const RecordData &Record, unsigned &Idx) {

Modified: cfe/trunk/lib/Basic/SourceManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/SourceManager.cpp?rev=70196&r1=70195&r2=70196&view=diff

==============================================================================
--- cfe/trunk/lib/Basic/SourceManager.cpp (original)
+++ cfe/trunk/lib/Basic/SourceManager.cpp Mon Apr 27 01:38:32 2009
@@ -308,6 +308,17 @@
   return Entry;
 }
 
+void SourceManager::PreallocateSLocEntries(ExternalSLocEntrySource *Source,
+                                           unsigned NumSLocEntries,
+                                           unsigned NextOffset) {
+  ExternalSLocEntries = Source;
+  this->NextOffset = NextOffset;
+  SLocEntryLoaded.resize(NumSLocEntries + 1);
+  SLocEntryLoaded[0] = true;
+  SLocEntryTable.resize(SLocEntryTable.size() + NumSLocEntries);
+}
+
+
 //===----------------------------------------------------------------------===//
 // Methods to create new FileID's and instantiations.
 //===----------------------------------------------------------------------===//
@@ -317,7 +328,26 @@
 /// corresponds to a file or some other input source.
 FileID SourceManager::createFileID(const ContentCache *File,
                                    SourceLocation IncludePos,
-                                   SrcMgr::CharacteristicKind FileCharacter) {
+                                   SrcMgr::CharacteristicKind FileCharacter,
+                                   unsigned PreallocatedID,
+                                   unsigned Offset) {
+  SLocEntry NewEntry = SLocEntry::get(NextOffset, 
+                                      FileInfo::get(IncludePos, File,
+                                                    FileCharacter));
+  if (PreallocatedID) {
+    // If we're filling in a preallocated ID, just load in the file
+    // entry and return.
+    assert(PreallocatedID < SLocEntryLoaded.size() && 
+           "Preallocate ID out-of-range");
+    assert(!SLocEntryLoaded[PreallocatedID] && 
+           "Source location entry already loaded");
+    assert(Offset && "Preallocate source location cannot have zero offset");
+    SLocEntryTable[PreallocatedID] 
+      = SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter));
+    SLocEntryLoaded[PreallocatedID] = true;
+    return LastFileIDLookup = FileID::get(PreallocatedID);
+  }
+
   SLocEntryTable.push_back(SLocEntry::get(NextOffset, 
                                           FileInfo::get(IncludePos, File,
                                                         FileCharacter)));
@@ -336,8 +366,22 @@
 SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
                                                      SourceLocation ILocStart,
                                                      SourceLocation ILocEnd,
-                                                     unsigned TokLength) {
+                                                     unsigned TokLength,
+                                                     unsigned PreallocatedID,
+                                                     unsigned Offset) {
   InstantiationInfo II = InstantiationInfo::get(ILocStart,ILocEnd, SpellingLoc);
+  if (PreallocatedID) {
+    // If we're filling in a preallocated ID, just load in the
+    // instantiation entry and return.
+    assert(PreallocatedID < SLocEntryLoaded.size() && 
+           "Preallocate ID out-of-range");
+    assert(!SLocEntryLoaded[PreallocatedID] && 
+           "Source location entry already loaded");
+    assert(Offset && "Preallocate source location cannot have zero offset");
+    SLocEntryTable[PreallocatedID] = SLocEntry::get(Offset, II);
+    SLocEntryLoaded[PreallocatedID] = true;
+    return SourceLocation::getMacroLoc(Offset);
+  }
   SLocEntryTable.push_back(SLocEntry::get(NextOffset, II));
   assert(NextOffset+TokLength+1 > NextOffset && "Ran out of source locations!");
   NextOffset += TokLength+1;
@@ -391,6 +435,8 @@
   unsigned NumProbes = 0;
   while (1) {
     --I;
+    if (ExternalSLocEntries)
+      getSLocEntry(FileID::get(I - SLocEntryTable.begin()));
     if (I->getOffset() <= SLocOffset) {
 #if 0
       printf("lin %d -> %d [%s] %d %d\n", SLocOffset,
@@ -399,7 +445,7 @@
              LastFileIDLookup.ID,  int(SLocEntryTable.end()-I));
 #endif
       FileID Res = FileID::get(I-SLocEntryTable.begin());
-      
+
       // If this isn't an instantiation, remember it.  We have good locality
       // across FileID lookups.
       if (!I->isInstantiation())
@@ -421,7 +467,7 @@
   NumProbes = 0;
   while (1) {
     unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
-    unsigned MidOffset = SLocEntryTable[MiddleIndex].getOffset();
+    unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset();
     
     ++NumProbes;
     
@@ -865,3 +911,5 @@
   llvm::cerr << "FileID scans: " << NumLinearScans << " linear, "
              << NumBinaryProbes << " binary.\n";
 }
+
+ExternalSLocEntrySource::~ExternalSLocEntrySource() { }

Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=70196&r1=70195&r2=70196&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Mon Apr 27 01:38:32 2009
@@ -43,8 +43,8 @@
     IdentifierOffsets(0),
     MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
     TotalSelectorsInMethodPool(0), SelectorOffsets(0),
-    TotalNumSelectors(0), NumStatementsRead(0), NumMacrosRead(0),
-    NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
+    TotalNumSelectors(0), NumSLocEntriesRead(0), NumStatementsRead(0), 
+    NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
     NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
 
 PCHReader::~PCHReader() {}
@@ -423,7 +423,21 @@
 /// \brief Read the source manager block
 PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
   using namespace SrcMgr;
-  if (Stream.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID)) {
+
+  // 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;
+
+  // The stream itself is going to skip over the source manager block.
+  if (Stream.SkipBlock()) {
+    Error("Malformed block record");
+    return Failure;
+  }
+
+  // Enter the source manager block.
+  if (SLocEntryCursor.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID)) {
     Error("Malformed source manager block record");
     return Failure;
   }
@@ -432,20 +446,19 @@
   RecordData Record;
   unsigned NumHeaderInfos = 0;
   while (true) {
-    unsigned Code = Stream.ReadCode();
+    unsigned Code = SLocEntryCursor.ReadCode();
     if (Code == llvm::bitc::END_BLOCK) {
-      if (Stream.ReadBlockEnd()) {
+      if (SLocEntryCursor.ReadBlockEnd()) {
         Error("Error at end of Source Manager block");
         return Failure;
       }
-
       return Success;
     }
     
     if (Code == llvm::bitc::ENTER_SUBBLOCK) {
       // No known subblocks, always skip them.
-      Stream.ReadSubBlockID();
-      if (Stream.SkipBlock()) {
+      SLocEntryCursor.ReadSubBlockID();
+      if (SLocEntryCursor.SkipBlock()) {
         Error("Malformed block record");
         return Failure;
       }
@@ -453,7 +466,7 @@
     }
     
     if (Code == llvm::bitc::DEFINE_ABBREV) {
-      Stream.ReadAbbrevRecord();
+      SLocEntryCursor.ReadAbbrevRecord();
       continue;
     }
     
@@ -461,56 +474,10 @@
     const char *BlobStart;
     unsigned BlobLen;
     Record.clear();
-    switch (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+    switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
     default:  // Default behavior: ignore.
       break;
 
-    case pch::SM_SLOC_FILE_ENTRY: {
-      // FIXME: We would really like to delay the creation of this
-      // FileEntry until it is actually required, e.g., when producing
-      // a diagnostic with a source location in this file.
-      const FileEntry *File 
-        = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen);
-      // FIXME: Error recovery if file cannot be found.
-      FileID ID = SourceMgr.createFileID(File,
-                                SourceLocation::getFromRawEncoding(Record[1]),
-                                         (CharacteristicKind)Record[2]);
-      if (Record[3])
-        const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(ID).getFile())
-          .setHasLineDirectives();
-      break;
-    }
-
-    case pch::SM_SLOC_BUFFER_ENTRY: {
-      const char *Name = BlobStart;
-      unsigned Code = Stream.ReadCode();
-      Record.clear();
-      unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen);
-      assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
-      (void)RecCode;
-      llvm::MemoryBuffer *Buffer
-        = llvm::MemoryBuffer::getMemBuffer(BlobStart, 
-                                           BlobStart + BlobLen - 1,
-                                           Name);
-      FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer);
-
-      if (strcmp(Name, "<built-in>") == 0
-          && CheckPredefinesBuffer(BlobStart, BlobLen - 1, BufferID))
-        return IgnorePCH;
-      break;
-    }
-
-    case pch::SM_SLOC_INSTANTIATION_ENTRY: {
-      SourceLocation SpellingLoc 
-        = SourceLocation::getFromRawEncoding(Record[1]);
-      SourceMgr.createInstantiationLoc(
-                              SpellingLoc,
-                              SourceLocation::getFromRawEncoding(Record[2]),
-                              SourceLocation::getFromRawEncoding(Record[3]),
-                              Record[4]);
-      break;
-    }
-
     case pch::SM_LINE_TABLE:
       if (ParseLineTable(SourceMgr, Record))
         return Failure;
@@ -525,10 +492,98 @@
       PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
       break;
     }
+
+    case pch::SM_SLOC_FILE_ENTRY:
+    case pch::SM_SLOC_BUFFER_ENTRY:
+    case pch::SM_SLOC_INSTANTIATION_ENTRY:
+      // Once we hit one of the source location entries, we're done.
+      return Success;
     }
   }
 }
 
+/// \brief Read in the source location entry with the given ID.
+PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
+  if (ID == 0)
+    return Success;
+
+  if (ID > TotalNumSLocEntries) {
+    Error("source location entry ID out-of-range for PCH file");
+    return Failure;
+  }
+
+  ++NumSLocEntriesRead;
+  SLocEntryCursor.JumpToBit(SLocOffsets[ID - 1]);
+  unsigned Code = SLocEntryCursor.ReadCode();
+  if (Code == llvm::bitc::END_BLOCK ||
+      Code == llvm::bitc::ENTER_SUBBLOCK ||
+      Code == llvm::bitc::DEFINE_ABBREV) {
+    Error("incorrectly-formatted source location entry in PCH file");
+    return Failure;
+  }
+
+  SourceManager &SourceMgr = Context.getSourceManager();
+  RecordData Record;
+  const char *BlobStart;
+  unsigned BlobLen;
+  switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+  default:
+    Error("incorrectly-formatted source location entry in PCH file");
+    return Failure;
+
+  case pch::SM_SLOC_FILE_ENTRY: {
+    const FileEntry *File 
+      = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen);
+    // FIXME: Error recovery if file cannot be found.
+    FileID FID = SourceMgr.createFileID(File,
+                                SourceLocation::getFromRawEncoding(Record[1]),
+                                       (SrcMgr::CharacteristicKind)Record[2],
+                                        ID, Record[0]);
+    if (Record[3])
+      const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile())
+        .setHasLineDirectives();
+
+    break;
+  }
+
+  case pch::SM_SLOC_BUFFER_ENTRY: {
+    const char *Name = BlobStart;
+    unsigned Offset = Record[0];
+    unsigned Code = SLocEntryCursor.ReadCode();
+    Record.clear();
+    unsigned RecCode 
+      = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+    assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
+    (void)RecCode;
+    llvm::MemoryBuffer *Buffer
+      = llvm::MemoryBuffer::getMemBuffer(BlobStart, 
+                                         BlobStart + BlobLen - 1,
+                                         Name);
+    FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset);
+      
+    if (strcmp(Name, "<built-in>") == 0
+        && CheckPredefinesBuffer(BlobStart, BlobLen - 1, BufferID))
+      return IgnorePCH;
+
+    break;
+  }
+
+  case pch::SM_SLOC_INSTANTIATION_ENTRY: {
+    SourceLocation SpellingLoc 
+      = SourceLocation::getFromRawEncoding(Record[1]);
+    SourceMgr.createInstantiationLoc(SpellingLoc,
+                              SourceLocation::getFromRawEncoding(Record[2]),
+                              SourceLocation::getFromRawEncoding(Record[3]),
+                                     Record[4],
+                                     ID,
+                                     Record[0]);
+    break;
+  }  
+  }
+
+  return Success;
+}
+
 /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
 /// specified cursor.  Read the abbreviations that are at the top of the block
 /// and then leave the cursor pointing into the block.
@@ -807,6 +862,7 @@
       TotalLexicalDeclContexts = Record[2];
       TotalVisibleDeclContexts = Record[3];
       break;
+
     case pch::TENTATIVE_DEFINITIONS:
       if (!TentativeDefinitions.empty()) {
         Error("Duplicate TENTATIVE_DEFINITIONS record in PCH file");
@@ -844,6 +900,22 @@
       if (!Record.empty())
         PP.setCounterValue(Record[0]);
       break;
+
+    case pch::SOURCE_LOCATION_OFFSETS:
+      SLocOffsets = (const uint64_t *)BlobStart;
+      TotalNumSLocEntries = Record[0];
+      PP.getSourceManager().PreallocateSLocEntries(this, 
+                                                   TotalNumSLocEntries, 
+                                                   Record[1]);
+      break;
+
+    case pch::SOURCE_LOCATION_PRELOADS:
+      for (unsigned I = 0, N = Record.size(); I != N; ++I) {
+        PCHReadResult Result = ReadSLocEntryRecord(Record[I]);
+        if (Result != Success)
+          return Result;
+      }
+      break;
     }
   }
   Error("Premature end of bitstream");
@@ -1434,6 +1506,10 @@
                                           SelectorsLoaded.end(),
                                           Selector());
 
+  if (TotalNumSLocEntries)
+    std::fprintf(stderr, "  %u/%u source location entries read (%f%%)\n",
+                 NumSLocEntriesRead, TotalNumSLocEntries,
+                 ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100));
   if (!TypesLoaded.empty())
     std::fprintf(stderr, "  %u/%u types read (%f%%)\n",
                  NumTypesLoaded, (unsigned)TypesLoaded.size(),
@@ -1604,6 +1680,10 @@
   return IdentifiersLoaded[ID - 1];
 }
 
+void PCHReader::ReadSLocEntry(unsigned ID) {
+  ReadSLocEntryRecord(ID);
+}
+
 Selector PCHReader::DecodeSelector(unsigned ID) {
   if (ID == 0)
     return Selector();

Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=70196&r1=70195&r2=70196&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Mon Apr 27 01:38:32 2009
@@ -353,7 +353,9 @@
   RECORD(SELECTOR_OFFSETS);
   RECORD(METHOD_POOL);
   RECORD(PP_COUNTER_VALUE);
-  
+  RECORD(SOURCE_LOCATION_OFFSETS);
+  RECORD(SOURCE_LOCATION_PRELOADS);
+
   // SourceManager Block.
   BLOCK(SOURCE_MANAGER_BLOCK);
   RECORD(SM_SLOC_FILE_ENTRY);
@@ -578,22 +580,79 @@
 /// the files in the AST.
 void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
                                         const Preprocessor &PP) {
+  RecordData Record;
+
   // Enter the source manager block.
   Stream.EnterSubblock(pch::SOURCE_MANAGER_BLOCK_ID, 3);
 
   // Abbreviations for the various kinds of source-location entries.
-  int SLocFileAbbrv = -1;
-  int SLocBufferAbbrv = -1;
-  int SLocBufferBlobAbbrv = -1;
-  int SLocInstantiationAbbrv = -1;
+  int SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
+  int SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
+  int SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
+  int SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(Stream);
+
+  // Write the line table.
+  if (SourceMgr.hasLineTable()) {
+    LineTableInfo &LineTable = SourceMgr.getLineTable();
+
+    // Emit the file names
+    Record.push_back(LineTable.getNumFilenames());
+    for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
+      // Emit the file name
+      const char *Filename = LineTable.getFilename(I);
+      unsigned FilenameLen = Filename? strlen(Filename) : 0;
+      Record.push_back(FilenameLen);
+      if (FilenameLen)
+        Record.insert(Record.end(), Filename, Filename + FilenameLen);
+    }
+    
+    // Emit the line entries
+    for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
+         L != LEnd; ++L) {
+      // Emit the file ID
+      Record.push_back(L->first);
+      
+      // Emit the line entries
+      Record.push_back(L->second.size());
+      for (std::vector<LineEntry>::iterator LE = L->second.begin(), 
+                                         LEEnd = L->second.end();
+           LE != LEEnd; ++LE) {
+        Record.push_back(LE->FileOffset);
+        Record.push_back(LE->LineNo);
+        Record.push_back(LE->FilenameID);
+        Record.push_back((unsigned)LE->FileKind);
+        Record.push_back(LE->IncludeOffset);
+      }
+      Stream.EmitRecord(pch::SM_LINE_TABLE, Record);
+    }
+  }
+
+  // Write out entries for all of the header files we know about.
+  HeaderSearch &HS = PP.getHeaderSearchInfo();  
+  Record.clear();
+  for (HeaderSearch::header_file_iterator I = HS.header_file_begin(), 
+                                          E = HS.header_file_end();
+       I != E; ++I) {
+    Record.push_back(I->isImport);
+    Record.push_back(I->DirInfo);
+    Record.push_back(I->NumIncludes);
+    AddIdentifierRef(I->ControllingMacro, Record);
+    Stream.EmitRecord(pch::SM_HEADER_FILE_INFO, Record);
+    Record.clear();
+  }
 
   // Write out the source location entry table. We skip the first
   // entry, which is always the same dummy entry.
-  RecordData Record;
+  std::vector<uint64_t> SLocEntryOffsets;
+  RecordData PreloadSLocs;
+  SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1);
   for (SourceManager::sloc_entry_iterator 
          SLoc = SourceMgr.sloc_entry_begin() + 1,
          SLocEnd = SourceMgr.sloc_entry_end();
        SLoc != SLocEnd; ++SLoc) {
+    // Record the offset of this source-location entry.
+    SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
+
     // Figure out which record code to use.
     unsigned Code;
     if (SLoc->isFile()) {
@@ -603,6 +662,7 @@
         Code = pch::SM_SLOC_BUFFER_ENTRY;
     } else
       Code = pch::SM_SLOC_INSTANTIATION_ENTRY;
+    Record.clear();
     Record.push_back(Code);
 
     Record.push_back(SLoc->getOffset());
@@ -616,18 +676,17 @@
       if (Content->Entry) {
         // The source location entry is a file. The blob associated
         // with this entry is the file name.
-        if (SLocFileAbbrv == -1)
-          SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
         Stream.EmitRecordWithBlob(SLocFileAbbrv, Record,
                              Content->Entry->getName(),
                              strlen(Content->Entry->getName()));
+
+        // FIXME: For now, preload all file source locations, so that
+        // we get the appropriate File entries in the reader. This is
+        // a temporary measure.
+        PreloadSLocs.push_back(SLocEntryOffsets.size());
       } else {
         // The source location entry is a buffer. The blob associated
         // with this entry contains the contents of the buffer.
-        if (SLocBufferAbbrv == -1) {
-          SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
-          SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
-        }
 
         // We add one to the size so that we capture the trailing NULL
         // that is required by llvm::MemoryBuffer::getMemBuffer (on
@@ -640,6 +699,9 @@
         Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
                              Buffer->getBufferStart(),
                              Buffer->getBufferSize() + 1);
+
+        if (strcmp(Name, "<built-in>") == 0)
+          PreloadSLocs.push_back(SLocEntryOffsets.size());
       }
     } else {
       // The source location entry is an instantiation.
@@ -654,68 +716,36 @@
       if (++NextSLoc != SLocEnd)
         NextOffset = NextSLoc->getOffset();
       Record.push_back(NextOffset - SLoc->getOffset() - 1);
-
-      if (SLocInstantiationAbbrv == -1)
-        SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(Stream);
       Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record);
     }
-
-    Record.clear();
   }
 
-  // Write the line table.
-  if (SourceMgr.hasLineTable()) {
-    LineTableInfo &LineTable = SourceMgr.getLineTable();
-
-    // Emit the file names
-    Record.push_back(LineTable.getNumFilenames());
-    for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
-      // Emit the file name
-      const char *Filename = LineTable.getFilename(I);
-      unsigned FilenameLen = Filename? strlen(Filename) : 0;
-      Record.push_back(FilenameLen);
-      if (FilenameLen)
-        Record.insert(Record.end(), Filename, Filename + FilenameLen);
-    }
-    
-    // Emit the line entries
-    for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
-         L != LEnd; ++L) {
-      // Emit the file ID
-      Record.push_back(L->first);
-      
-      // Emit the line entries
-      Record.push_back(L->second.size());
-      for (std::vector<LineEntry>::iterator LE = L->second.begin(), 
-                                         LEEnd = L->second.end();
-           LE != LEEnd; ++LE) {
-        Record.push_back(LE->FileOffset);
-        Record.push_back(LE->LineNo);
-        Record.push_back(LE->FilenameID);
-        Record.push_back((unsigned)LE->FileKind);
-        Record.push_back(LE->IncludeOffset);
-      }
-      Stream.EmitRecord(pch::SM_LINE_TABLE, Record);
-    }
-  }
+  Stream.ExitBlock();
 
-  // Loop over all the header files.
-  HeaderSearch &HS = PP.getHeaderSearchInfo();  
-  for (HeaderSearch::header_file_iterator I = HS.header_file_begin(), 
-                                          E = HS.header_file_end();
-       I != E; ++I) {
-    Record.push_back(I->isImport);
-    Record.push_back(I->DirInfo);
-    Record.push_back(I->NumIncludes);
-    if (I->ControllingMacro)
-      AddIdentifierRef(I->ControllingMacro, Record);
-    else
-      Record.push_back(0);
-    Stream.EmitRecord(pch::SM_HEADER_FILE_INFO, Record);
-    Record.clear();
-  }
+  if (SLocEntryOffsets.empty())
+    return;
 
-  Stream.ExitBlock();
+  // Write the source-location offsets table into the PCH block. This
+  // table is used for lazily loading source-location information.
+  using namespace llvm;
+  BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+  Abbrev->Add(BitCodeAbbrevOp(pch::SOURCE_LOCATION_OFFSETS));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // next offset
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
+  unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
+  
+  Record.clear();
+  Record.push_back(pch::SOURCE_LOCATION_OFFSETS);
+  Record.push_back(SLocEntryOffsets.size());
+  Record.push_back(SourceMgr.getNextOffset());
+  Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record,
+                            (const char *)&SLocEntryOffsets.front(), 
+                            SLocEntryOffsets.size() * 8);
+
+  // Write the source location entry preloads array, telling the PCH
+  // reader which source locations entries it should load eagerly.
+  Stream.EmitRecord(pch::SOURCE_LOCATION_PRELOADS, PreloadSLocs);
 }
 
 /// \brief Writes the block containing the serialized form of the





More information about the cfe-commits mailing list