diff options
-rw-r--r-- | clang/include/clang/Basic/SourceManager.h | 65 | ||||
-rw-r--r-- | clang/include/clang/Frontend/PCHBitCodes.h | 14 | ||||
-rw-r--r-- | clang/include/clang/Frontend/PCHReader.h | 22 | ||||
-rw-r--r-- | clang/lib/Basic/SourceManager.cpp | 56 | ||||
-rw-r--r-- | clang/lib/Frontend/PCHReader.cpp | 192 | ||||
-rw-r--r-- | clang/lib/Frontend/PCHWriter.cpp | 166 |
6 files changed, 373 insertions, 142 deletions
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h index 0b47df9ad91..9fc7587e54d 100644 --- a/clang/include/clang/Basic/SourceManager.h +++ b/clang/include/clang/Basic/SourceManager.h @@ -249,7 +249,16 @@ namespace SrcMgr { } }; } // 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 @@ class SourceManager { /// 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 @@ class SourceManager { 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 @@ public: /// 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 @@ public: 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 @@ public: /// 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 @@ public: 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 @@ private: // 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 @@ private: /// 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); diff --git a/clang/include/clang/Frontend/PCHBitCodes.h b/clang/include/clang/Frontend/PCHBitCodes.h index 5b1fc8d1835..436a265a41e 100644 --- a/clang/include/clang/Frontend/PCHBitCodes.h +++ b/clang/include/clang/Frontend/PCHBitCodes.h @@ -173,7 +173,19 @@ namespace clang { /// \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. diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index a4304461f8a..fed169354eb 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -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 SwitchCase; class PCHReader : public ExternalSemaSource, public IdentifierInfoLookup, - public ExternalIdentifierLookup { + public ExternalIdentifierLookup, + public ExternalSLocEntrySource { public: enum PCHReadResult { Success, Failure, IgnorePCH }; @@ -102,6 +104,16 @@ private: /// 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 @@ private: /// 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 @@ private: 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 @@ public: 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) { diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index 9ed21635259..50576636db3 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -308,6 +308,17 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) { 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 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) { /// 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 @@ FileID SourceManager::createFileID(const ContentCache *File, 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 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { 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 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { 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 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { 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 @@ void SourceManager::PrintStats() const { llvm::cerr << "FileID scans: " << NumLinearScans << " linear, " << NumBinaryProbes << " binary.\n"; } + +ExternalSLocEntrySource::~ExternalSLocEntrySource() { } diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 86848758ad6..ff8795ca640 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -43,8 +43,8 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext &Context) 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 @@ static bool ParseLineTable(SourceManager &SourceMgr, /// \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 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { 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 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { } if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); + SLocEntryCursor.ReadAbbrevRecord(); continue; } @@ -461,56 +474,10 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { 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 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { 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 @@ PCHReader::ReadPCHBlock() { 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 @@ PCHReader::ReadPCHBlock() { 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 @@ void PCHReader::PrintStats() { 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 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) { return IdentifiersLoaded[ID - 1]; } +void PCHReader::ReadSLocEntry(unsigned ID) { + ReadSLocEntryRecord(ID); +} + Selector PCHReader::DecodeSelector(unsigned ID) { if (ID == 0) return Selector(); diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index c8b64659994..d181013a37e 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -353,7 +353,9 @@ void PCHWriter::WriteBlockInfoBlock() { 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 @@ static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) { /// 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 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, 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 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, 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 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, 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 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, 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 |