Add PCH read/write support for Objective-C Selectors.

Note: This support is non-lazy. Once we get "Cocoa.h" humming, we can optimize this.
llvm-svn: 69884
This commit is contained in:
Steve Naroff 2009-04-23 10:39:46 +00:00
parent 5058f240d9
commit 2ddea05bca
8 changed files with 184 additions and 15 deletions

View File

@ -370,7 +370,6 @@ class Selector {
InfoPtr = reinterpret_cast<uintptr_t>(SI);
assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
}
Selector(uintptr_t V) : InfoPtr(V) {}
IdentifierInfo *getAsIdentifierInfo() const {
if (getIdentifierInfoFlag())
@ -388,6 +387,7 @@ public:
/// The default ctor should only be used when creating data structures that
/// will contain selectors.
Selector() : InfoPtr(0) {}
Selector(uintptr_t V) : InfoPtr(V) {}
/// operator==/!= - Indicate whether the specified selectors are identical.
bool operator==(Selector RHS) const {

View File

@ -45,6 +45,8 @@ namespace clang {
/// file.
typedef uint32_t IdentID;
typedef uint32_t SelectorID;
/// \brief Describes the various kinds of blocks that occur within
/// a PCH file.
enum BlockIDs {
@ -66,7 +68,10 @@ namespace clang {
/// \brief The block containing the definitions of all of the
/// 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.
@ -160,7 +165,10 @@ namespace clang {
/// \brief Record code for the array of locally-scoped external
/// declarations.
LOCALLY_SCOPED_EXTERNAL_DECLS = 11
LOCALLY_SCOPED_EXTERNAL_DECLS = 11,
/// \brief Record code for the Objective-C Selector Table.
SELECTOR_TABLE = 12
};
/// \brief Record types used within a source manager block.

View File

@ -145,6 +145,9 @@ private:
/// 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 The set of external definitions stored in the the PCH
/// file.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
@ -198,13 +201,15 @@ private:
/// \brief FIXME: document!
llvm::SmallVector<uint64_t, 4> SpecialTypes;
PCHReadResult ReadPCHBlock(uint64_t &PreprocessorBlockOffset);
PCHReadResult ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
uint64_t &SelectorBlockOffset);
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);
void LoadedDecl(unsigned Index, Decl *D);
@ -313,6 +318,12 @@ public:
IdentifierInfo *GetIdentifierInfo(const RecordData &Record, unsigned &Idx) {
return DecodeIdentifierInfo(Record[Idx++]);
}
Selector DecodeSelector(unsigned Idx);
Selector GetSelector(const RecordData &Record, unsigned &Idx) {
return DecodeSelector(Record[Idx++]);
}
DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx);
/// \brief Read an integral value

View File

@ -93,11 +93,17 @@ private:
/// discovery), starting at 1. An ID of zero refers to a NULL
/// IdentifierInfo.
llvm::DenseMap<const IdentifierInfo *, pch::IdentID> IdentifierIDs;
/// \brief Offsets of each of the identifier IDs into the identifier
/// table, shifted left by one bit with the low bit set.
llvm::SmallVector<uint64_t, 16> IdentifierOffsets;
/// \brief Map that provides the ID numbers of each Selector.
llvm::DenseMap<Selector, pch::SelectorID> SelectorIDs;
/// \brief A vector of all Selectors (ordered by ID).
llvm::SmallVector<Selector, 16> SelVector;
/// \brief Offsets of each of the macro identifiers into the
/// bitstream.
///
@ -154,6 +160,7 @@ private:
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
void WriteDeclsBlock(ASTContext &Context);
void WriteIdentifierTable(Preprocessor &PP);
void WriteSelectorTable();
void WriteAttributeRecord(const Attr *Attr);
public:
@ -179,6 +186,9 @@ public:
/// \brief Emit a reference to an identifier
void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record);
/// \brief Emit a Selector (which is a smart pointer reference)
void AddSelectorRef(const Selector, RecordData &Record);
/// \brief Get the unique number used to refer to the given
/// identifier.
pch::IdentID getIdentifierRef(const IdentifierInfo *II);

View File

@ -1063,7 +1063,7 @@ unsigned PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
unsigned PCHStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
VisitExpr(E);
// FIXME: Selectors.
E->setSelector(Reader.GetSelector(Record, Idx));
E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 0;
@ -1586,8 +1586,69 @@ 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 <= 1) {
IdentifierInfo *II = DecodeIdentifierInfo(Record[Idx++]);
assert(II && "DecodeIdentifierInfo returned 0");
KeyIdents.push_back(II);
} else {
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
IdentifierInfo *II = DecodeIdentifierInfo(Record[Idx++]);
assert(II && "DecodeIdentifierInfo returned 0");
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) {
PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
uint64_t &SelectorBlockOffset) {
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
Error("Malformed block record");
return Failure;
@ -1630,6 +1691,20 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
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()) {
@ -1740,7 +1815,6 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
TotalLexicalDeclContexts = Record[2];
TotalVisibleDeclContexts = Record[3];
break;
case pch::TENTATIVE_DEFINITIONS:
if (!TentativeDefinitions.empty()) {
Error("Duplicate TENTATIVE_DEFINITIONS record in PCH file");
@ -1758,7 +1832,6 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
break;
}
}
Error("Premature end of bitstream");
return Failure;
}
@ -1791,6 +1864,8 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
// 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();
@ -1810,7 +1885,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
}
break;
case pch::PCH_BLOCK_ID:
switch (ReadPCHBlock(PreprocessorBlockOffset)) {
switch (ReadPCHBlock(PreprocessorBlockOffset, SelectorBlockOffset)) {
case Success:
break;
@ -1882,6 +1957,14 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
return Failure;
}
}
if (SelectorBlockOffset) {
SavedStreamPosition SavedPos(Stream);
Stream.JumpToBit(SelectorBlockOffset);
if (ReadSelectorBlock()) {
Error("Malformed preprocessor block");
return Failure;
}
}
return Success;
}
@ -2633,6 +2716,22 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
return reinterpret_cast<IdentifierInfo *>(IdentifierData[ID - 1]);
}
Selector PCHReader::DecodeSelector(unsigned ID) {
if (ID == 0)
return Selector();
if (SelectorData.empty()) {
Error("No selector table in PCH file");
return Selector();
}
if (ID > SelectorData.size()) {
Error("Selector ID out of range");
return Selector();
}
return SelectorData[ID-1];
}
DeclarationName
PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];

View File

@ -1182,9 +1182,7 @@ void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
void PCHStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
VisitExpr(E);
assert(0 && "Can't write a selector yet!");
// FIXME! Write selectors.
//Writer.WriteSubStmt(E->getSelector());
Writer.AddSelectorRef(E->getSelector(), Record);
Writer.AddSourceLocation(E->getAtLoc(), Record);
Writer.AddSourceLocation(E->getRParenLoc(), Record);
Code = pch::EXPR_OBJC_SELECTOR_EXPR;
@ -1888,6 +1886,26 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
Stream.EmitRecord(pch::IDENTIFIER_OFFSET, IdentifierOffsets);
}
void PCHWriter::WriteSelectorTable() {
Stream.EnterSubblock(pch::SELECTOR_BLOCK_ID, 3);
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;
@ -2078,6 +2096,7 @@ void PCHWriter::WritePCH(Sema &SemaRef) {
WritePreprocessor(PP);
WriteTypesBlock(Context);
WriteDeclsBlock(Context);
WriteSelectorTable();
WriteIdentifierTable(PP);
Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);
Stream.EmitRecord(pch::DECL_OFFSET, DeclOffsets);
@ -2145,6 +2164,20 @@ pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
if (SelRef.getAsOpaquePtr() == 0) {
Record.push_back(0);
return;
}
pch::SelectorID &SID = SelectorIDs[SelRef];
if (SID == 0) {
SID = SelectorIDs.size();
SelVector.push_back(SelRef);
}
Record.push_back(SID);
}
void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
if (T.isNull()) {
Record.push_back(pch::PREDEF_TYPE_NULL_ID);
@ -2223,7 +2256,7 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
assert(false && "Serialization of Objective-C selectors unavailable");
AddSelectorRef(Name.getObjCSelector(), Record);
break;
case DeclarationName::CXXConstructorName:

View File

@ -6,6 +6,9 @@
typedef typeof(@"foo" "bar") objc_string;
typedef typeof(@encode(int)) objc_encode;
typedef typeof(@protocol(foo)) objc_protocol;
typedef typeof(@selector(noArgs)) objc_selector_noArgs;
typedef typeof(@selector(oneArg:)) objc_selector_oneArg;
typedef typeof(@selector(foo:bar:)) objc_selector_twoArg;
// Types.

View File

@ -21,3 +21,8 @@ int *T0 = (objc_id_protocol_ty)0; // expected-error {{not a compile-time constan
int *T1 = (objc_interface_ty)0; // expected-warning {{aka 'itf *'}}
int *T2 = (objc_qual_interface_ty)0; // expected-warning {{aka 'itf<foo> *'}}
objc_selector_noArgs s1;
objc_selector_oneArg s2;
objc_selector_twoArg s3;