From: Steve Naroff Date: Thu, 23 Apr 2009 10:39:46 +0000 (+0000) Subject: Add PCH read/write support for Objective-C Selectors. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=90cd1bb1baac2a0221f3642de0cbea3244b116e5;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69884 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 0553a98022..235c19081c 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -370,7 +370,6 @@ class Selector { InfoPtr = reinterpret_cast(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 { diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 2afcce3388..998b1109b4 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -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. diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 107779aa1d..05e3ac6a12 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -145,6 +145,9 @@ private: /// an IdentifierInfo* that has already been resolved. llvm::SmallVector IdentifierData; + /// \brief SelectorData, indexed by the selector ID minus one. + llvm::SmallVector SelectorData; + /// \brief The set of external definitions stored in the the PCH /// file. llvm::SmallVector ExternalDefinitions; @@ -198,13 +201,15 @@ private: /// \brief FIXME: document! llvm::SmallVector 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 &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 diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index e3d0603e08..d1fe1d4f44 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -93,11 +93,17 @@ private: /// discovery), starting at 1. An ID of zero refers to a NULL /// IdentifierInfo. llvm::DenseMap 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 IdentifierOffsets; + /// \brief Map that provides the ID numbers of each Selector. + llvm::DenseMap SelectorIDs; + + /// \brief A vector of all Selectors (ordered by ID). + llvm::SmallVector 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); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 851eebc355..0e2d06eaf3 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -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 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(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++]; diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index dd8d95a56d..62e129919b 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -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: diff --git a/test/PCH/objc_exprs.h b/test/PCH/objc_exprs.h index 4d58c1fc68..b811430c2e 100644 --- a/test/PCH/objc_exprs.h +++ b/test/PCH/objc_exprs.h @@ -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. diff --git a/test/PCH/objc_exprs.m b/test/PCH/objc_exprs.m index 5b631b4ba2..eb1ae434a7 100644 --- a/test/PCH/objc_exprs.m +++ b/test/PCH/objc_exprs.m @@ -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 *'}} +objc_selector_noArgs s1; +objc_selector_oneArg s2; +objc_selector_twoArg s3; + +