diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-04-27 06:38:32 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-04-27 06:38:32 +0000 |
commit | 7f94b0b0c6791013d2f72ced9b4bedd3b23673a6 (patch) | |
tree | 57fafa0282abdbe9266318e87966b64fac25c05c /lib/Frontend | |
parent | 63377d56de98cfef089a5758e8d4c7597a30269e (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70196 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend')
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 192 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 166 |
2 files changed, 234 insertions, 124 deletions
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 86848758ad..ff8795ca64 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/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/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index c8b6465999..d181013a37 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/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 |