Load the selector table lazily from the PCH file.

This results in a 10% speedup on the Cocoa-prefixed "Hello, World!",
all of which is (not surprisingly) user time. There was a tiny
reduction in the size of the PCH file for Cocoa.h, because certain
selectors aren't being written twice.

I'm using two new tricks here that I'd like to replicate elsewhere:
  (1) The selectors not used in the global method pool are packed into
  the blob after the global method pool's on-disk hash table and
  stored as keys, so that all selectors are in the same blob.
  (2) We record the offsets of each selector key when we write it into
  the global method pool (or after it, in the same blob). The offset
  table is written as a blob, so that we don't need to pack/unpack a
  SmallVector with its contents.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70055 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-04-25 17:48:32 +00:00
Родитель d3f632eda7
Коммит 83941df274
5 изменённых файлов: 171 добавлений и 165 удалений

Просмотреть файл

@ -68,10 +68,7 @@ namespace clang {
/// \brief The block containing the definitions of all of the /// \brief The block containing the definitions of all of the
/// declarations stored in the PCH file. /// declarations stored in the PCH file.
DECLS_BLOCK_ID, DECLS_BLOCK_ID
/// \brief The block containing ObjC selectors stored in the PCH file.
SELECTOR_BLOCK_ID
}; };
/// \brief Record types that occur within the PCH block itself. /// \brief Record types that occur within the PCH block itself.
@ -167,8 +164,9 @@ namespace clang {
/// declarations. /// declarations.
LOCALLY_SCOPED_EXTERNAL_DECLS = 11, LOCALLY_SCOPED_EXTERNAL_DECLS = 11,
/// \brief Record code for the Objective-C Selector Table. /// \brief Record code for the table of offsets into the
SELECTOR_TABLE = 12, /// Objective-C method pool.
SELECTOR_OFFSETS = 12,
/// \brief Record code for the Objective-C method pool, /// \brief Record code for the Objective-C method pool,
METHOD_POOL = 13 METHOD_POOL = 13

Просмотреть файл

@ -146,9 +146,6 @@ private:
/// an IdentifierInfo* that has already been resolved. /// an IdentifierInfo* that has already been resolved.
llvm::SmallVector<uint64_t, 16> IdentifierData; llvm::SmallVector<uint64_t, 16> IdentifierData;
/// \brief SelectorData, indexed by the selector ID minus one.
llvm::SmallVector<Selector, 16> SelectorData;
/// \brief A pointer to an on-disk hash table of opaque type /// \brief A pointer to an on-disk hash table of opaque type
/// PCHMethodPoolLookupTable. /// PCHMethodPoolLookupTable.
/// ///
@ -156,6 +153,29 @@ private:
/// associated with every selector known in the PCH file. /// associated with every selector known in the PCH file.
void *MethodPoolLookupTable; void *MethodPoolLookupTable;
/// \brief A pointer to the character data that comprises the method
/// pool.
///
/// The SelectorOffsets table refers into this memory.
const unsigned char *MethodPoolLookupTableData;
/// \brief The number of selectors stored in the method pool itself.
unsigned TotalSelectorsInMethodPool;
/// \brief Offsets into the method pool lookup table's data array
/// where each selector resides.
const uint32_t *SelectorOffsets;
/// \brief The total number of selectors stored in the PCH file.
unsigned TotalNumSelectors;
/// \brief A vector containing selectors that have already been loaded.
///
/// This vector is indexed by the Selector ID (-1). NULL selector
/// entries indicate that the particular selector ID has not yet
/// been loaded.
llvm::SmallVector<Selector, 16> SelectorsLoaded;
/// \brief The set of external definitions stored in the the PCH /// \brief The set of external definitions stored in the the PCH
/// file. /// file.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions; llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
@ -197,6 +217,13 @@ private:
/// \brief The number of macros de-serialized from the PCH file. /// \brief The number of macros de-serialized from the PCH file.
unsigned NumMacrosRead; unsigned NumMacrosRead;
/// \brief The number of method pool entries that have been read.
unsigned NumMethodPoolSelectorsRead;
/// \brief The number of times we have looked into the global method
/// pool and not found anything.
unsigned NumMethodPoolMisses;
/// \brief The total number of macros stored in the PCH file. /// \brief The total number of macros stored in the PCH file.
unsigned TotalNumMacros; unsigned TotalNumMacros;
@ -217,14 +244,12 @@ private:
/// Objective-C protocols. /// Objective-C protocols.
llvm::SmallVector<Decl *, 16> InterestingDecls; llvm::SmallVector<Decl *, 16> InterestingDecls;
PCHReadResult ReadPCHBlock(uint64_t &PreprocessorBlockOffset, PCHReadResult ReadPCHBlock(uint64_t &PreprocessorBlockOffset);
uint64_t &SelectorBlockOffset);
bool CheckPredefinesBuffer(const char *PCHPredef, bool CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen, unsigned PCHPredefLen,
FileID PCHBufferID); FileID PCHBufferID);
PCHReadResult ReadSourceManagerBlock(); PCHReadResult ReadSourceManagerBlock();
bool ReadPreprocessorBlock(); bool ReadPreprocessorBlock();
bool ReadSelectorBlock();
bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record); bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record);
QualType ReadTypeRecord(uint64_t Offset); QualType ReadTypeRecord(uint64_t Offset);
@ -240,7 +265,10 @@ public:
explicit PCHReader(Preprocessor &PP, ASTContext &Context) explicit PCHReader(Preprocessor &PP, ASTContext &Context)
: SemaObj(0), PP(PP), Context(Context), Consumer(0), : SemaObj(0), PP(PP), Context(Context), Consumer(0),
IdentifierTableData(0), IdentifierLookupTable(0), IdentifierTableData(0), IdentifierLookupTable(0),
MethodPoolLookupTable(0), NumStatementsRead(0), NumMacrosRead(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
TotalNumSelectors(0), NumStatementsRead(0), NumMacrosRead(0),
NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { } NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
~PCHReader() {} ~PCHReader() {}

Просмотреть файл

@ -101,6 +101,10 @@ private:
/// \brief Map that provides the ID numbers of each Selector. /// \brief Map that provides the ID numbers of each Selector.
llvm::DenseMap<Selector, pch::SelectorID> SelectorIDs; llvm::DenseMap<Selector, pch::SelectorID> SelectorIDs;
/// \brief Offset of each selector within the method pool/selector
/// table, indexed by the Selector ID (-1).
llvm::SmallVector<uint32_t, 16> SelectorOffsets;
/// \brief A vector of all Selectors (ordered by ID). /// \brief A vector of all Selectors (ordered by ID).
llvm::SmallVector<Selector, 16> SelVector; llvm::SmallVector<Selector, 16> SelVector;
@ -161,7 +165,6 @@ private:
void WriteDeclsBlock(ASTContext &Context); void WriteDeclsBlock(ASTContext &Context);
void WriteMethodPool(Sema &SemaRef); void WriteMethodPool(Sema &SemaRef);
void WriteIdentifierTable(Preprocessor &PP); void WriteIdentifierTable(Preprocessor &PP);
void WriteSelectorTable();
void WriteAttributeRecord(const Attr *Attr); void WriteAttributeRecord(const Attr *Attr);
public: public:
@ -224,6 +227,10 @@ public:
/// within the identifier table. /// within the identifier table.
void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset); void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset);
/// \brief Note that the selector Sel occurs at the given offset
/// within the method pool/selector table.
void SetSelectorOffset(Selector Sel, uint32_t Offset);
/// \brief Add the given statement or expression to the queue of /// \brief Add the given statement or expression to the queue of
/// statements to emit. /// statements to emit.
/// ///

Просмотреть файл

@ -1141,7 +1141,7 @@ public:
return std::make_pair(KeyLen, DataLen); return std::make_pair(KeyLen, DataLen);
} }
internal_key_type ReadKey(const unsigned char* d, unsigned n) { internal_key_type ReadKey(const unsigned char* d, unsigned) {
using namespace clang::io; using namespace clang::io;
SelectorTable &SelTable = Reader.getContext().Selectors; SelectorTable &SelTable = Reader.getContext().Selectors;
unsigned N = ReadUnalignedLE16(d); unsigned N = ReadUnalignedLE16(d);
@ -1725,70 +1725,8 @@ bool PCHReader::ReadPreprocessorBlock() {
} }
} }
bool PCHReader::ReadSelectorBlock() {
if (Stream.EnterSubBlock(pch::SELECTOR_BLOCK_ID))
return Error("Malformed selector block record");
RecordData Record;
while (true) {
unsigned Code = Stream.ReadCode();
switch (Code) {
case llvm::bitc::END_BLOCK:
if (Stream.ReadBlockEnd())
return Error("Error at end of preprocessor block");
return false;
case llvm::bitc::ENTER_SUBBLOCK:
// No known subblocks, always skip them.
Stream.ReadSubBlockID();
if (Stream.SkipBlock())
return Error("Malformed block record");
continue;
case llvm::bitc::DEFINE_ABBREV:
Stream.ReadAbbrevRecord();
continue;
default: break;
}
// Read a record.
Record.clear();
pch::PCHRecordTypes RecType =
(pch::PCHRecordTypes)Stream.ReadRecord(Code, Record);
switch (RecType) {
default: // Default behavior: ignore unknown records.
break;
case pch::SELECTOR_TABLE:
unsigned Idx = 1; // Record[0] == pch::SELECTOR_TABLE.
unsigned NumSels = Record[Idx++];
llvm::SmallVector<IdentifierInfo *, 8> KeyIdents;
for (unsigned SelIdx = 0; SelIdx < NumSels; SelIdx++) {
unsigned NumArgs = Record[Idx++];
KeyIdents.clear();
if (NumArgs == 0) {
// If the number of arguments is 0, we must have an Identifier.
IdentifierInfo *II = DecodeIdentifierInfo(Record[Idx++]);
assert(II && "DecodeIdentifierInfo returned 0");
KeyIdents.push_back(II);
} else {
// For keyword selectors, the Identifier is optional (::: is legal!).
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
IdentifierInfo *II = DecodeIdentifierInfo(Record[Idx++]);
KeyIdents.push_back(II);
}
}
Selector Sel = PP.getSelectorTable().getSelector(NumArgs,&KeyIdents[0]);
SelectorData.push_back(Sel);
}
}
}
return false;
}
PCHReader::PCHReadResult PCHReader::PCHReadResult
PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset, PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
uint64_t &SelectorBlockOffset) {
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
Error("Malformed block record"); Error("Malformed block record");
return Failure; return Failure;
@ -1832,20 +1770,6 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
} }
break; break;
case pch::SELECTOR_BLOCK_ID:
// Skip the selector block for now, but remember where it is. We
// want to read it in after the identifier table.
if (SelectorBlockOffset) {
Error("Multiple selector blocks found.");
return Failure;
}
SelectorBlockOffset = Stream.GetCurrentBitNo();
if (Stream.SkipBlock()) {
Error("Malformed block record");
return Failure;
}
break;
case pch::SOURCE_MANAGER_BLOCK_ID: case pch::SOURCE_MANAGER_BLOCK_ID:
switch (ReadSourceManagerBlock()) { switch (ReadSourceManagerBlock()) {
case Success: case Success:
@ -1971,12 +1895,21 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
LocallyScopedExternalDecls.swap(Record); LocallyScopedExternalDecls.swap(Record);
break; break;
case pch::SELECTOR_OFFSETS:
SelectorOffsets = (const uint32_t *)BlobStart;
TotalNumSelectors = Record[0];
SelectorsLoaded.resize(TotalNumSelectors);
break;
case pch::METHOD_POOL: case pch::METHOD_POOL:
MethodPoolLookupTableData = (const unsigned char *)BlobStart;
if (Record[0])
MethodPoolLookupTable MethodPoolLookupTable
= PCHMethodPoolLookupTable::Create( = PCHMethodPoolLookupTable::Create(
(const unsigned char *)BlobStart + Record[0], MethodPoolLookupTableData + Record[0],
(const unsigned char *)BlobStart, MethodPoolLookupTableData,
PCHMethodPoolLookupTrait(*this)); PCHMethodPoolLookupTrait(*this));
TotalSelectorsInMethodPool = Record[1];
break; break;
} }
} }
@ -2012,7 +1945,6 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
// We expect a number of well-defined blocks, though we don't necessarily // We expect a number of well-defined blocks, though we don't necessarily
// need to understand them all. // need to understand them all.
uint64_t PreprocessorBlockOffset = 0; uint64_t PreprocessorBlockOffset = 0;
uint64_t SelectorBlockOffset = 0;
while (!Stream.AtEndOfStream()) { while (!Stream.AtEndOfStream()) {
unsigned Code = Stream.ReadCode(); unsigned Code = Stream.ReadCode();
@ -2033,7 +1965,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
} }
break; break;
case pch::PCH_BLOCK_ID: case pch::PCH_BLOCK_ID:
switch (ReadPCHBlock(PreprocessorBlockOffset, SelectorBlockOffset)) { switch (ReadPCHBlock(PreprocessorBlockOffset)) {
case Success: case Success:
break; break;
@ -2117,14 +2049,6 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
return Failure; return Failure;
} }
} }
if (SelectorBlockOffset) {
SavedStreamPosition SavedPos(Stream);
Stream.JumpToBit(SelectorBlockOffset);
if (ReadSelectorBlock()) {
Error("Malformed preprocessor block");
return Failure;
}
}
return Success; return Success;
} }
@ -2799,30 +2723,53 @@ void PCHReader::PrintStats() {
if ((IdentifierData[I] & 0x01) == 0) if ((IdentifierData[I] & 0x01) == 0)
++NumIdentifiersLoaded; ++NumIdentifiersLoaded;
} }
unsigned NumSelectorsLoaded = 0;
for (unsigned I = 0; I < SelectorsLoaded.size(); ++I) {
if (SelectorsLoaded[I].getAsOpaquePtr())
++NumSelectorsLoaded;
}
if (!TypeAlreadyLoaded.empty())
std::fprintf(stderr, " %u/%u types read (%f%%)\n", std::fprintf(stderr, " %u/%u types read (%f%%)\n",
NumTypesLoaded, (unsigned)TypeAlreadyLoaded.size(), NumTypesLoaded, (unsigned)TypeAlreadyLoaded.size(),
((float)NumTypesLoaded/TypeAlreadyLoaded.size() * 100)); ((float)NumTypesLoaded/TypeAlreadyLoaded.size() * 100));
if (!DeclAlreadyLoaded.empty())
std::fprintf(stderr, " %u/%u declarations read (%f%%)\n", std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
NumDeclsLoaded, (unsigned)DeclAlreadyLoaded.size(), NumDeclsLoaded, (unsigned)DeclAlreadyLoaded.size(),
((float)NumDeclsLoaded/DeclAlreadyLoaded.size() * 100)); ((float)NumDeclsLoaded/DeclAlreadyLoaded.size() * 100));
if (!IdentifierData.empty())
std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n", std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
NumIdentifiersLoaded, (unsigned)IdentifierData.size(), NumIdentifiersLoaded, (unsigned)IdentifierData.size(),
((float)NumIdentifiersLoaded/IdentifierData.size() * 100)); ((float)NumIdentifiersLoaded/IdentifierData.size() * 100));
if (TotalNumSelectors)
std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
NumSelectorsLoaded, TotalNumSelectors,
((float)NumSelectorsLoaded/TotalNumSelectors * 100));
if (TotalNumStatements)
std::fprintf(stderr, " %u/%u statements read (%f%%)\n", std::fprintf(stderr, " %u/%u statements read (%f%%)\n",
NumStatementsRead, TotalNumStatements, NumStatementsRead, TotalNumStatements,
((float)NumStatementsRead/TotalNumStatements * 100)); ((float)NumStatementsRead/TotalNumStatements * 100));
if (TotalNumMacros)
std::fprintf(stderr, " %u/%u macros read (%f%%)\n", std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
NumMacrosRead, TotalNumMacros, NumMacrosRead, TotalNumMacros,
((float)NumMacrosRead/TotalNumMacros * 100)); ((float)NumMacrosRead/TotalNumMacros * 100));
if (TotalLexicalDeclContexts)
std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n", std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n",
NumLexicalDeclContextsRead, TotalLexicalDeclContexts, NumLexicalDeclContextsRead, TotalLexicalDeclContexts,
((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts
* 100)); * 100));
if (TotalVisibleDeclContexts)
std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n", std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n",
NumVisibleDeclContextsRead, TotalVisibleDeclContexts, NumVisibleDeclContextsRead, TotalVisibleDeclContexts,
((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts
* 100)); * 100));
if (TotalSelectorsInMethodPool) {
std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n",
NumMethodPoolSelectorsRead, TotalSelectorsInMethodPool,
((float)NumMethodPoolSelectorsRead/TotalSelectorsInMethodPool
* 100));
std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
}
std::fprintf(stderr, "\n"); std::fprintf(stderr, "\n");
} }
@ -2878,9 +2825,12 @@ PCHReader::ReadMethodPool(Selector Sel) {
PCHMethodPoolLookupTable *PoolTable PCHMethodPoolLookupTable *PoolTable
= (PCHMethodPoolLookupTable*)MethodPoolLookupTable; = (PCHMethodPoolLookupTable*)MethodPoolLookupTable;
PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel); PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel);
if (Pos == PoolTable->end()) if (Pos == PoolTable->end()) {
++NumMethodPoolMisses;
return std::pair<ObjCMethodList, ObjCMethodList>();; return std::pair<ObjCMethodList, ObjCMethodList>();;
}
++NumMethodPoolSelectorsRead;
return *Pos; return *Pos;
} }
@ -2911,16 +2861,26 @@ Selector PCHReader::DecodeSelector(unsigned ID) {
if (ID == 0) if (ID == 0)
return Selector(); return Selector();
if (SelectorData.empty()) { if (!MethodPoolLookupTableData) {
Error("No selector table in PCH file"); Error("No selector table in PCH file");
return Selector(); return Selector();
} }
if (ID > SelectorData.size()) { if (ID > TotalNumSelectors) {
Error("Selector ID out of range"); Error("Selector ID out of range");
return Selector(); return Selector();
} }
return SelectorData[ID-1];
unsigned Index = ID - 1;
if (SelectorsLoaded[Index].getAsOpaquePtr() == 0) {
// Load this selector from the selector table.
// FIXME: endianness portability issues with SelectorOffsets table
PCHMethodPoolLookupTrait Trait(*this);
SelectorsLoaded[Index]
= Trait.ReadKey(MethodPoolLookupTableData + SelectorOffsets[Index], 0);
}
return SelectorsLoaded[Index];
} }
DeclarationName DeclarationName

Просмотреть файл

@ -1832,11 +1832,10 @@ public:
return std::make_pair(KeyLen, DataLen); return std::make_pair(KeyLen, DataLen);
} }
void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned KeyLen) { void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) {
// FIXME: Keep track of the location of the key data (the uint64_t Start = Out.tell();
// selector), so we can fold the selector table's storage into assert((Start >> 32) == 0 && "Selector key offset too large");
// this hash table. Writer.SetSelectorOffset(Sel, Start);
uint64_t Start = Out.tell(); (void)Start;
unsigned N = Sel.getNumArgs(); unsigned N = Sel.getNumArgs();
clang::io::Emit16(Out, N); clang::io::Emit16(Out, N);
if (N == 0) if (N == 0)
@ -1844,8 +1843,6 @@ public:
for (unsigned I = 0; I != N; ++I) for (unsigned I = 0; I != N; ++I)
clang::io::Emit32(Out, clang::io::Emit32(Out,
Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
assert(Out.tell() - Start == KeyLen && "Key length is wrong");
} }
void EmitData(llvm::raw_ostream& Out, key_type_ref, void EmitData(llvm::raw_ostream& Out, key_type_ref,
@ -1895,6 +1892,7 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
// Create the on-disk hash table representation. Start by // Create the on-disk hash table representation. Start by
// iterating through the instance method pool. // iterating through the instance method pool.
PCHMethodPoolTrait::key_type Key; PCHMethodPoolTrait::key_type Key;
unsigned NumSelectorsInMethodPool = 0;
for (llvm::DenseMap<Selector, ObjCMethodList>::iterator for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
Instance = SemaRef.InstanceMethodPool.begin(), Instance = SemaRef.InstanceMethodPool.begin(),
InstanceEnd = SemaRef.InstanceMethodPool.end(); InstanceEnd = SemaRef.InstanceMethodPool.end();
@ -1912,6 +1910,7 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
Generator.insert(Instance->first, Generator.insert(Instance->first,
std::make_pair(Instance->second, Factory->second)); std::make_pair(Instance->second, Factory->second));
++NumSelectorsInMethodPool;
Empty = false; Empty = false;
} }
@ -1926,41 +1925,68 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance
= SemaRef.InstanceMethodPool.find(Factory->first); = SemaRef.InstanceMethodPool.find(Factory->first);
if (Instance == SemaRef.InstanceMethodPool.end()) if (Instance == SemaRef.InstanceMethodPool.end()) {
Generator.insert(Factory->first, Generator.insert(Factory->first,
std::make_pair(ObjCMethodList(), Factory->second)); std::make_pair(ObjCMethodList(), Factory->second));
++NumSelectorsInMethodPool;
}
Empty = false; Empty = false;
} }
if (Empty) if (Empty && SelectorOffsets.empty())
return; return;
// Create the on-disk hash table in a buffer. // Create the on-disk hash table in a buffer.
llvm::SmallVector<char, 4096> MethodPool; llvm::SmallVector<char, 4096> MethodPool;
uint32_t BucketOffset; uint32_t BucketOffset;
SelectorOffsets.resize(SelVector.size());
{ {
PCHMethodPoolTrait Trait(*this); PCHMethodPoolTrait Trait(*this);
llvm::raw_svector_ostream Out(MethodPool); llvm::raw_svector_ostream Out(MethodPool);
// Make sure that no bucket is at offset 0 // Make sure that no bucket is at offset 0
clang::io::Emit32(Out, 0); clang::io::Emit32(Out, 0);
BucketOffset = Generator.Emit(Out, Trait); BucketOffset = Generator.Emit(Out, Trait);
// For every selector that we have seen but which was not
// written into the hash table, write the selector itself and
// record it's offset.
for (unsigned I = 0, N = SelVector.size(); I != N; ++I)
if (SelectorOffsets[I] == 0)
Trait.EmitKey(Out, SelVector[I], 0);
} }
// Create a blob abbreviation // Create a blob abbreviation
BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL)); Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev); unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);
// Write the identifier table // Write the method pool
RecordData Record; RecordData Record;
Record.push_back(pch::METHOD_POOL); Record.push_back(pch::METHOD_POOL);
Record.push_back(BucketOffset); Record.push_back(BucketOffset);
Record.push_back(NumSelectorsInMethodPool);
Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record,
&MethodPool.front(), &MethodPool.front(),
MethodPool.size()); MethodPool.size());
// Create a blob abbreviation for the selector table offsets.
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(pch::SELECTOR_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
// Write the selector offsets table.
Record.clear();
Record.push_back(pch::SELECTOR_OFFSETS);
Record.push_back(SelectorOffsets.size());
Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
(const char *)&SelectorOffsets.front(),
SelectorOffsets.size() * 4);
} }
} }
@ -2096,26 +2122,6 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
Stream.EmitRecord(pch::IDENTIFIER_OFFSET, IdentifierOffsets); Stream.EmitRecord(pch::IDENTIFIER_OFFSET, IdentifierOffsets);
} }
void PCHWriter::WriteSelectorTable() {
Stream.EnterSubblock(pch::SELECTOR_BLOCK_ID, 2);
RecordData Record;
Record.push_back(pch::SELECTOR_TABLE);
Record.push_back(SelectorIDs.size());
// Create the on-disk representation.
for (unsigned selIdx = 0; selIdx < SelVector.size(); selIdx++) {
assert(SelVector[selIdx].getAsOpaquePtr() && "NULL Selector found");
Record.push_back(SelVector[selIdx].getNumArgs());
if (SelVector[selIdx].getNumArgs())
for (unsigned i = 0; i < SelVector[selIdx].getNumArgs(); i++)
AddIdentifierRef(SelVector[selIdx].getIdentifierInfoForSlot(i), Record);
else
AddIdentifierRef(SelVector[selIdx].getIdentifierInfoForSlot(0), Record);
}
Stream.EmitRecord(pch::SELECTOR_TABLE, Record);
Stream.ExitBlock();
}
/// \brief Write a record containing the given attributes. /// \brief Write a record containing the given attributes.
void PCHWriter::WriteAttributeRecord(const Attr *Attr) { void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
RecordData Record; RecordData Record;
@ -2250,6 +2256,14 @@ void PCHWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) {
IdentifierOffsets[IdentifierIDs[II] - 1] = (Offset << 1) | 0x01; IdentifierOffsets[IdentifierIDs[II] - 1] = (Offset << 1) | 0x01;
} }
/// \brief Note that the selector Sel occurs at the given offset
/// within the method pool/selector table.
void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
unsigned ID = SelectorIDs[Sel];
assert(ID && "Unknown selector");
SelectorOffsets[ID - 1] = Offset;
}
PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream) PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream)
: Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS), : Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS),
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
@ -2309,7 +2323,6 @@ void PCHWriter::WritePCH(Sema &SemaRef) {
WriteTypesBlock(Context); WriteTypesBlock(Context);
WriteDeclsBlock(Context); WriteDeclsBlock(Context);
WriteMethodPool(SemaRef); WriteMethodPool(SemaRef);
WriteSelectorTable();
WriteIdentifierTable(PP); WriteIdentifierTable(PP);
Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets); Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);
Stream.EmitRecord(pch::DECL_OFFSET, DeclOffsets); Stream.EmitRecord(pch::DECL_OFFSET, DeclOffsets);