summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/SourceManager.h65
-rw-r--r--clang/include/clang/Frontend/PCHBitCodes.h14
-rw-r--r--clang/include/clang/Frontend/PCHReader.h22
-rw-r--r--clang/lib/Basic/SourceManager.cpp56
-rw-r--r--clang/lib/Frontend/PCHReader.cpp192
-rw-r--r--clang/lib/Frontend/PCHWriter.cpp166
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
OpenPOWER on IntegriCloud