/// \brief The block containing the definitions of all of the
/// declarations stored in the PCH file.
- DECLS_BLOCK_ID,
-
- /// \brief The block containing ObjC selectors stored in the PCH file.
- SELECTOR_BLOCK_ID
+ DECLS_BLOCK_ID
};
/// \brief Record types that occur within the PCH block itself.
/// declarations.
LOCALLY_SCOPED_EXTERNAL_DECLS = 11,
- /// \brief Record code for the Objective-C Selector Table.
- SELECTOR_TABLE = 12,
+ /// \brief Record code for the table of offsets into the
+ /// Objective-C method pool.
+ SELECTOR_OFFSETS = 12,
/// \brief Record code for the Objective-C method pool,
METHOD_POOL = 13
/// an IdentifierInfo* that has already been resolved.
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
/// PCHMethodPoolLookupTable.
///
/// associated with every selector known in the PCH file.
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
/// file.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
/// \brief The number of macros de-serialized from the PCH file.
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.
unsigned TotalNumMacros;
/// Objective-C protocols.
llvm::SmallVector<Decl *, 16> InterestingDecls;
- PCHReadResult ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
- uint64_t &SelectorBlockOffset);
+ PCHReadResult ReadPCHBlock(uint64_t &PreprocessorBlockOffset);
bool CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
FileID PCHBufferID);
PCHReadResult ReadSourceManagerBlock();
bool ReadPreprocessorBlock();
- bool ReadSelectorBlock();
bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record);
QualType ReadTypeRecord(uint64_t Offset);
explicit PCHReader(Preprocessor &PP, ASTContext &Context)
: SemaObj(0), PP(PP), Context(Context), Consumer(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) { }
~PCHReader() {}
/// \brief Map that provides the ID numbers of each Selector.
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).
llvm::SmallVector<Selector, 16> SelVector;
void WriteDeclsBlock(ASTContext &Context);
void WriteMethodPool(Sema &SemaRef);
void WriteIdentifierTable(Preprocessor &PP);
- void WriteSelectorTable();
void WriteAttributeRecord(const Attr *Attr);
public:
/// within the identifier table.
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
/// statements to emit.
///
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;
SelectorTable &SelTable = Reader.getContext().Selectors;
unsigned N = ReadUnalignedLE16(d);
}
}
-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::ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
- uint64_t &SelectorBlockOffset) {
+PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
Error("Malformed block record");
return Failure;
}
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:
switch (ReadSourceManagerBlock()) {
case Success:
LocallyScopedExternalDecls.swap(Record);
break;
+ case pch::SELECTOR_OFFSETS:
+ SelectorOffsets = (const uint32_t *)BlobStart;
+ TotalNumSelectors = Record[0];
+ SelectorsLoaded.resize(TotalNumSelectors);
+ break;
+
case pch::METHOD_POOL:
- MethodPoolLookupTable
- = PCHMethodPoolLookupTable::Create(
- (const unsigned char *)BlobStart + Record[0],
- (const unsigned char *)BlobStart,
+ MethodPoolLookupTableData = (const unsigned char *)BlobStart;
+ if (Record[0])
+ MethodPoolLookupTable
+ = PCHMethodPoolLookupTable::Create(
+ MethodPoolLookupTableData + Record[0],
+ MethodPoolLookupTableData,
PCHMethodPoolLookupTrait(*this));
+ TotalSelectorsInMethodPool = Record[1];
break;
}
}
// We expect a number of well-defined blocks, though we don't necessarily
// need to understand them all.
uint64_t PreprocessorBlockOffset = 0;
- uint64_t SelectorBlockOffset = 0;
while (!Stream.AtEndOfStream()) {
unsigned Code = Stream.ReadCode();
}
break;
case pch::PCH_BLOCK_ID:
- switch (ReadPCHBlock(PreprocessorBlockOffset, SelectorBlockOffset)) {
+ switch (ReadPCHBlock(PreprocessorBlockOffset)) {
case Success:
break;
return Failure;
}
}
- if (SelectorBlockOffset) {
- SavedStreamPosition SavedPos(Stream);
- Stream.JumpToBit(SelectorBlockOffset);
- if (ReadSelectorBlock()) {
- Error("Malformed preprocessor block");
- return Failure;
- }
- }
return Success;
}
if ((IdentifierData[I] & 0x01) == 0)
++NumIdentifiersLoaded;
}
-
- std::fprintf(stderr, " %u/%u types read (%f%%)\n",
- NumTypesLoaded, (unsigned)TypeAlreadyLoaded.size(),
- ((float)NumTypesLoaded/TypeAlreadyLoaded.size() * 100));
- std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
- NumDeclsLoaded, (unsigned)DeclAlreadyLoaded.size(),
- ((float)NumDeclsLoaded/DeclAlreadyLoaded.size() * 100));
- std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
- NumIdentifiersLoaded, (unsigned)IdentifierData.size(),
- ((float)NumIdentifiersLoaded/IdentifierData.size() * 100));
- std::fprintf(stderr, " %u/%u statements read (%f%%)\n",
- NumStatementsRead, TotalNumStatements,
- ((float)NumStatementsRead/TotalNumStatements * 100));
- std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
- NumMacrosRead, TotalNumMacros,
- ((float)NumMacrosRead/TotalNumMacros * 100));
- std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n",
- NumLexicalDeclContextsRead, TotalLexicalDeclContexts,
- ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts
- * 100));
- std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n",
- NumVisibleDeclContextsRead, TotalVisibleDeclContexts,
- ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts
- * 100));
+ 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",
+ NumTypesLoaded, (unsigned)TypeAlreadyLoaded.size(),
+ ((float)NumTypesLoaded/TypeAlreadyLoaded.size() * 100));
+ if (!DeclAlreadyLoaded.empty())
+ std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
+ NumDeclsLoaded, (unsigned)DeclAlreadyLoaded.size(),
+ ((float)NumDeclsLoaded/DeclAlreadyLoaded.size() * 100));
+ if (!IdentifierData.empty())
+ std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
+ NumIdentifiersLoaded, (unsigned)IdentifierData.size(),
+ ((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",
+ NumStatementsRead, TotalNumStatements,
+ ((float)NumStatementsRead/TotalNumStatements * 100));
+ if (TotalNumMacros)
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosRead, TotalNumMacros,
+ ((float)NumMacrosRead/TotalNumMacros * 100));
+ if (TotalLexicalDeclContexts)
+ std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n",
+ NumLexicalDeclContextsRead, TotalLexicalDeclContexts,
+ ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts
+ * 100));
+ if (TotalVisibleDeclContexts)
+ std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n",
+ NumVisibleDeclContextsRead, TotalVisibleDeclContexts,
+ ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts
+ * 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");
}
PCHMethodPoolLookupTable *PoolTable
= (PCHMethodPoolLookupTable*)MethodPoolLookupTable;
PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel);
- if (Pos == PoolTable->end())
+ if (Pos == PoolTable->end()) {
+ ++NumMethodPoolMisses;
return std::pair<ObjCMethodList, ObjCMethodList>();;
+ }
+ ++NumMethodPoolSelectorsRead;
return *Pos;
}
if (ID == 0)
return Selector();
- if (SelectorData.empty()) {
+ if (!MethodPoolLookupTableData) {
Error("No selector table in PCH file");
return Selector();
}
-
- if (ID > SelectorData.size()) {
+
+ if (ID > TotalNumSelectors) {
Error("Selector ID out of range");
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
return std::make_pair(KeyLen, DataLen);
}
- void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned KeyLen) {
- // FIXME: Keep track of the location of the key data (the
- // selector), so we can fold the selector table's storage into
- // this hash table.
- uint64_t Start = Out.tell(); (void)Start;
+ void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) {
+ uint64_t Start = Out.tell();
+ assert((Start >> 32) == 0 && "Selector key offset too large");
+ Writer.SetSelectorOffset(Sel, Start);
unsigned N = Sel.getNumArgs();
clang::io::Emit16(Out, N);
if (N == 0)
for (unsigned I = 0; I != N; ++I)
clang::io::Emit32(Out,
Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
-
- assert(Out.tell() - Start == KeyLen && "Key length is wrong");
}
void EmitData(llvm::raw_ostream& Out, key_type_ref,
// Create the on-disk hash table representation. Start by
// iterating through the instance method pool.
PCHMethodPoolTrait::key_type Key;
+ unsigned NumSelectorsInMethodPool = 0;
for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
Instance = SemaRef.InstanceMethodPool.begin(),
InstanceEnd = SemaRef.InstanceMethodPool.end();
Generator.insert(Instance->first,
std::make_pair(Instance->second, Factory->second));
+ ++NumSelectorsInMethodPool;
Empty = false;
}
llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance
= SemaRef.InstanceMethodPool.find(Factory->first);
- if (Instance == SemaRef.InstanceMethodPool.end())
+ if (Instance == SemaRef.InstanceMethodPool.end()) {
Generator.insert(Factory->first,
std::make_pair(ObjCMethodList(), Factory->second));
+ ++NumSelectorsInMethodPool;
+ }
Empty = false;
}
- if (Empty)
+ if (Empty && SelectorOffsets.empty())
return;
// Create the on-disk hash table in a buffer.
llvm::SmallVector<char, 4096> MethodPool;
uint32_t BucketOffset;
+ SelectorOffsets.resize(SelVector.size());
{
PCHMethodPoolTrait Trait(*this);
llvm::raw_svector_ostream Out(MethodPool);
// Make sure that no bucket is at offset 0
clang::io::Emit32(Out, 0);
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
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);
- // Write the identifier table
+ // Write the method pool
RecordData Record;
Record.push_back(pch::METHOD_POOL);
Record.push_back(BucketOffset);
+ Record.push_back(NumSelectorsInMethodPool);
Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record,
&MethodPool.front(),
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);
}
}
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.
void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
RecordData Record;
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)
: Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS),
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
WriteTypesBlock(Context);
WriteDeclsBlock(Context);
WriteMethodPool(SemaRef);
- WriteSelectorTable();
WriteIdentifierTable(PP);
Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);
Stream.EmitRecord(pch::DECL_OFFSET, DeclOffsets);