From: Steve Naroff Date: Fri, 5 Oct 2007 18:42:47 +0000 (+0000) Subject: Layering refinements for selectors (suggested by Chris). Specifics... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=29238a0bf7cbf5b396efb451a0adb5fe4aa037ca;p=clang Layering refinements for selectors (suggested by Chris). Specifics... - Add SelectorTable, which enables us to remove MultiKeywordSelector from the public header. - Remove FoldingSet from IdentifierInfo.h and Preprocessor.h. - Remove Parser::ObjcGetUnarySelector and Parser::ObjcGetKeywordSelector, they are subsumed by SelectorTable. - Add MultiKeywordSelector to IdentifierInfo.cpp. - Move a bunch of selector related methods from ParseObjC.cpp to IdentifierInfo.cpp. - Added some comments. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42643 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Lex/IdentifierTable.cpp b/Lex/IdentifierTable.cpp index a5ba4d412a..2ca1225b17 100644 --- a/Lex/IdentifierTable.cpp +++ b/Lex/IdentifierTable.cpp @@ -15,6 +15,7 @@ #include "clang/Lex/IdentifierTable.h" #include "clang/Lex/MacroInfo.h" #include "clang/Basic/LangOptions.h" +#include "llvm/ADT/FoldingSet.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -210,3 +211,150 @@ void IdentifierTable::PrintStats() const { HashTable.getAllocator().PrintStats(); } +//===----------------------------------------------------------------------===// +// SelectorTable Implementation +//===----------------------------------------------------------------------===// + +/// MultiKeywordSelector - One of these variable length records is kept for each +/// selector containing more than one keyword. We use a folding set +/// to unique aggregate names (keyword selectors in ObjC parlance). Access to +/// this class is provided strictly through Selector. +class MultiKeywordSelector : public llvm::FoldingSetNode { +public: + unsigned NumArgs; + + // Constructor for keyword selectors. + MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { + assert((nKeys > 1) && "not a multi-keyword selector"); + NumArgs = nKeys; + // Fill in the trailing keyword array. + IdentifierInfo **KeyInfo = reinterpret_cast(this+1); + for (unsigned i = 0; i != nKeys; ++i) + KeyInfo[i] = IIV[i]; + } + // Derive the full selector name, placing the result into methodBuffer. + // As a convenience, a pointer to the first character is returned. + // Example usage: llvm::SmallString<128> mbuf; Selector->getName(mbuf); + char *getName(llvm::SmallVectorImpl &methodBuffer); + + unsigned getNumArgs() const { return NumArgs; } + + typedef IdentifierInfo *const *keyword_iterator; + keyword_iterator keyword_begin() const { + return reinterpret_cast(this+1); + } + keyword_iterator keyword_end() const { + return keyword_begin()+NumArgs; + } + IdentifierInfo *getIdentifierInfoForSlot(unsigned i) { + assert((i < NumArgs) && "getIdentifierInfoForSlot(): illegal index"); + return keyword_begin()[i]; + } + static void Profile(llvm::FoldingSetNodeID &ID, + keyword_iterator ArgTys, unsigned NumArgs) { + ID.AddInteger(NumArgs); + if (NumArgs) { // handle keyword selector. + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i]); + } else // handle unary selector. + ID.AddPointer(ArgTys[0]); + } + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, keyword_begin(), NumArgs); + } +}; + +unsigned Selector::getNumArgs() const { + unsigned IIF = getIdentifierInfoFlag(); + if (IIF == ZeroArg) + return 0; + if (IIF == OneArg) + return 1; + // We point to a MultiKeywordSelector (pointer doesn't contain any flags). + MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); + return SI->getNumArgs(); +} + +IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) { + IdentifierInfo *II = getAsIdentifierInfo(); + if (II) { + assert(((argIndex == 0) || (argIndex == 1)) && "illegal keyword index"); + return II; + } + // We point to a MultiKeywordSelector (pointer doesn't contain any flags). + MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); + return SI->getIdentifierInfoForSlot(argIndex); +} + +char *MultiKeywordSelector::getName(llvm::SmallVectorImpl &methodName) { + methodName[0] = '\0'; + keyword_iterator KeyIter = keyword_begin(); + for (unsigned int i = 0; i < NumArgs; i++) { + if (KeyIter[i]) { + unsigned KeyLen = KeyIter[i]->getLength(); + methodName.append(KeyIter[i]->getName(), KeyIter[i]->getName()+KeyLen); + } + methodName.push_back(':'); + } + methodName.push_back('\0'); + return &methodName[0]; +} + +char *Selector::getName(llvm::SmallVectorImpl &methodName) { + methodName[0] = '\0'; + IdentifierInfo *II = getAsIdentifierInfo(); + if (II) { + unsigned NameLen = II->getLength(); + methodName.append(II->getName(), II->getName()+NameLen); + if (getNumArgs() == 1) + methodName.push_back(':'); + methodName.push_back('\0'); + } else { // We have a multiple keyword selector (no embedded flags). + MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); + SI->getName(methodName); + } + return &methodName[0]; +} + + +Selector SelectorTable::getKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) +{ + llvm::FoldingSet *SelTab; + + SelTab = static_cast *>(Impl); + + // Unique selector, to guarantee there is one per name. + llvm::FoldingSetNodeID ID; + MultiKeywordSelector::Profile(ID, IIV, nKeys); + + void *InsertPos = 0; + if (MultiKeywordSelector *SI = SelTab->FindNodeOrInsertPos(ID, InsertPos)) { + return Selector(SI); + } + // MultiKeywordSelector objects are not allocated with new because they have a + // variable size array (for parameter types) at the end of them. + MultiKeywordSelector *SI = + (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + + nKeys*sizeof(IdentifierInfo *)); + new (SI) MultiKeywordSelector(nKeys, IIV); + SelTab->InsertNode(SI, InsertPos); + return Selector(SI); +} + +Selector SelectorTable::getUnarySelector(IdentifierInfo *ID) { + return Selector(ID, 1); +} + +Selector SelectorTable::getNullarySelector(IdentifierInfo *ID) { + return Selector(ID, 0); +} + +SelectorTable::SelectorTable() { + Impl = new llvm::FoldingSet; +} + +SelectorTable::~SelectorTable() { + delete static_cast *>(Impl); +} + + diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index dff6e0c9e6..0ae11b7e46 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -500,89 +500,6 @@ Parser::TypeTy *Parser::ParseObjCTypeName() { return Ty; } -unsigned Selector::getNumArgs() const { - unsigned IIF = getIdentifierInfoFlag(); - if (IIF == ZeroArg) - return 0; - if (IIF == OneArg) - return 1; - // We point to a MultiKeywordSelector (pointer doesn't contain any flags). - MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); - return SI->getNumArgs(); -} - -IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) { - IdentifierInfo *II = getAsIdentifierInfo(); - if (II) { - assert(((argIndex == 0) || (argIndex == 1)) && "illegal keyword index"); - return II; - } - // We point to a MultiKeywordSelector (pointer doesn't contain any flags). - MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); - return SI->getIdentifierInfoForSlot(argIndex); -} - -char *MultiKeywordSelector::getName(llvm::SmallVectorImpl &methodName) { - methodName[0] = '\0'; - keyword_iterator KeyIter = keyword_begin(); - for (unsigned int i = 0; i < NumArgs; i++) { - if (KeyIter[i]) { - unsigned KeyLen = KeyIter[i]->getLength(); - methodName.append(KeyIter[i]->getName(), KeyIter[i]->getName()+KeyLen); - } - methodName.push_back(':'); - } - methodName.push_back('\0'); - return &methodName[0]; -} - -char *Selector::getName(llvm::SmallVectorImpl &methodName) { - methodName[0] = '\0'; - IdentifierInfo *II = getAsIdentifierInfo(); - if (II) { - unsigned NameLen = II->getLength(); - methodName.append(II->getName(), II->getName()+NameLen); - if (getNumArgs() == 1) - methodName.push_back(':'); - methodName.push_back('\0'); - } else { // We have a multiple keyword selector (no embedded flags). - MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); - SI->getName(methodName); - } - return &methodName[0]; -} - -Selector Parser::ObjcGetUnarySelector(IdentifierInfo *unarySel) -{ - return Selector(unarySel, 0); -} - -Selector Parser::ObjcGetKeywordSelector( - llvm::SmallVectorImpl &IIV) -{ - if (IIV.size() == 1) - return Selector(IIV[0], 1); - - llvm::FoldingSet &SelTab = PP.getSelectorTable(); - - // Unique selector, to guarantee there is one per name. - llvm::FoldingSetNodeID ID; - MultiKeywordSelector::Profile(ID, &IIV[0], IIV.size()); - - void *InsertPos = 0; - if (MultiKeywordSelector *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) { - return Selector(SI); - } - // MultiKeywordSelector objects are not allocated with new because they have a - // variable size array (for parameter types) at the end of them. - MultiKeywordSelector *SI = - (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + - IIV.size()*sizeof(IdentifierInfo *)); - new (SI) MultiKeywordSelector(IIV.size(), &IIV[0]); - SelTab.InsertNode(SI, InsertPos); - return Selector(SI); -} - /// objc-method-decl: /// objc-selector /// objc-keyword-selector objc-parmlist[opt] @@ -680,8 +597,11 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, // If attributes exist after the method, parse them. if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) methodAttrs = ParseAttributes(); - - Selector Sel = ObjcGetKeywordSelector(KeyIdents); + + unsigned nKeys = KeyIdents.size(); + Selector Sel = (nKeys == 1) ? + PP.getSelectorTable().getUnarySelector(KeyIdents[0]) : + PP.getSelectorTable().getKeywordSelector(nKeys, &KeyIdents[0]); return Actions.ActOnMethodDeclaration(mLoc, mType, ReturnType, Sel, &KeyTypes[0], &ArgNames[0], methodAttrs, MethodImplKind); @@ -692,7 +612,7 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) methodAttrs = ParseAttributes(); - Selector Sel = ObjcGetUnarySelector(selIdent); + Selector Sel = PP.getSelectorTable().getNullarySelector(selIdent); return Actions.ActOnMethodDeclaration(mLoc, mType, ReturnType, Sel, 0, 0, methodAttrs, MethodImplKind); } @@ -1290,21 +1210,24 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { } SourceLocation RBracloc = ConsumeBracket(); // consume ']' - if (KeyIdents.size()) { - Selector sel = ObjcGetKeywordSelector(KeyIdents); + unsigned nKeys = KeyIdents.size(); + if (nKeys) { + Selector Sel = (nKeys == 1) ? + PP.getSelectorTable().getUnarySelector(KeyIdents[0]) : + PP.getSelectorTable().getKeywordSelector(nKeys, &KeyIdents[0]); // We've just parsed a keyword message. if (ReceiverName) - return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc, + return Actions.ActOnClassMessage(ReceiverName, Sel, LBracloc, RBracloc, &KeyExprs[0]); - return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc, + return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracloc, RBracloc, &KeyExprs[0]); } - Selector sel = ObjcGetUnarySelector(selIdent); + Selector Sel = PP.getSelectorTable().getNullarySelector(selIdent); // We've just parsed a unary message (a message with no arguments). if (ReceiverName) - return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc, 0); - return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc, 0); + return Actions.ActOnClassMessage(ReceiverName, Sel, LBracloc, RBracloc, 0); + return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracloc, RBracloc, 0); } Parser::ExprResult Parser::ParseObjCStringLiteral() { diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index eda2c6bf3e..e36c144220 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -737,7 +737,6 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; - compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* clang */; projectDirPath = ""; diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 83065e7a82..8be7fd1801 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -47,7 +47,7 @@ public: SourceManager &SourceMgr; TargetInfo &Target; IdentifierTable &Idents; - llvm::FoldingSet &Selectors; + SelectorTable &Selectors; Builtin::Context BuiltinInfo; // Builtin Types. @@ -61,7 +61,7 @@ public: QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents, - llvm::FoldingSet &sels) : + SelectorTable &sels) : CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t), Idents(idents), Selectors(sels) { InitBuiltinTypes(); diff --git a/include/clang/Lex/IdentifierTable.h b/include/clang/Lex/IdentifierTable.h index 9f6234c049..c820e86fa7 100644 --- a/include/clang/Lex/IdentifierTable.h +++ b/include/clang/Lex/IdentifierTable.h @@ -18,11 +18,12 @@ // this data is long-lived. #include "clang/Basic/TokenKinds.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallString.h" #include #include +class MultiKeywordSelector; // a private class used by Selector. + namespace clang { class MacroInfo; struct LangOptions; @@ -135,8 +136,6 @@ public: void setFETokenInfo(void *T) { FETokenInfo = T; } }; - - /// IdentifierTable - This table implements an efficient mapping from strings to /// IdentifierInfo nodes. It has no other purpose, but this is an /// extremely performance-critical piece of the code, as each occurrance of @@ -179,59 +178,11 @@ private: void AddKeywords(const LangOptions &LangOpts); }; -/// MultiKeywordSelector - One of these variable length records is kept for each -/// selector containing more than one keyword. We use a folding set -/// to unique aggregate names (keyword selectors in ObjC parlance). Access to -/// this class is provided strictly through Selector. All methods are private. -/// The only reason it appears in this header is FoldingSet needs to see it:-( -class MultiKeywordSelector : public llvm::FoldingSetNode { - friend class Selector; // Only Selector can access me. - friend class Parser; // Only Parser can instantiate me. - - unsigned NumArgs; - - // Constructor for keyword selectors. - MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { - assert((nKeys > 1) && "not a multi-keyword selector"); - NumArgs = nKeys; - // Fill in the trailing keyword array. - IdentifierInfo **KeyInfo = reinterpret_cast(this+1); - for (unsigned i = 0; i != nKeys; ++i) - KeyInfo[i] = IIV[i]; - } - // Derive the full selector name, placing the result into methodBuffer. - // As a convenience, a pointer to the first character is returned. - // Example usage: llvm::SmallString<128> mbuf; Selector->getName(mbuf); - char *getName(llvm::SmallVectorImpl &methodBuffer); - - unsigned getNumArgs() const { return NumArgs; } - - typedef IdentifierInfo *const *keyword_iterator; - keyword_iterator keyword_begin() const { - return reinterpret_cast(this+1); - } - keyword_iterator keyword_end() const { - return keyword_begin()+NumArgs; - } - IdentifierInfo *getIdentifierInfoForSlot(unsigned i) { - assert((i < NumArgs) && "getIdentifierInfoForSlot(): illegal index"); - return keyword_begin()[i]; - } - friend class llvm::FoldingSet; - static void Profile(llvm::FoldingSetNodeID &ID, - keyword_iterator ArgTys, unsigned NumArgs) { - ID.AddInteger(NumArgs); - if (NumArgs) { // handle keyword selector. - for (unsigned i = 0; i != NumArgs; ++i) - ID.AddPointer(ArgTys[i]); - } else // handle unary selector. - ID.AddPointer(ArgTys[0]); - } - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, keyword_begin(), NumArgs); - } -}; - +/// Selector - This smart pointer class efficiently represents Objective-C +/// method names. This class will either point to an IdentifierInfo or a +/// MultiKeywordSelector (which is private). This enables us to optimize +/// selectors that no arguments and selectors that take 1 argument, which +/// accounts for 78% of all selectors in Cocoa.h. class Selector { enum IdentifierInfoFlag { // MultiKeywordSelector = 0. @@ -251,14 +202,14 @@ class Selector { InfoPtr = reinterpret_cast(SI); assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); } - friend class Parser; // only the Parser can create these. +public: + friend class SelectorTable; // only the SelectorTable can create these. IdentifierInfo *getAsIdentifierInfo() const { if (getIdentifierInfoFlag()) return reinterpret_cast(InfoPtr & ~ArgFlags); return 0; } -public: unsigned getIdentifierInfoFlag() const { return InfoPtr & ArgFlags; } @@ -288,6 +239,21 @@ public: char *getName(llvm::SmallVectorImpl &methodBuffer); }; +/// SelectorTable - This table allows us to fully hide how we implement +/// multi-keyword caching. +class SelectorTable { + void *Impl; // Actually a FoldingSet* + SelectorTable(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT + void operator=(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT +public: + SelectorTable(); + ~SelectorTable(); + + Selector getKeywordSelector(unsigned nKeys, IdentifierInfo **IIV); + Selector getUnarySelector(IdentifierInfo *ID); + Selector getNullarySelector(IdentifierInfo *ID); +}; + } // end namespace clang #endif diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 02f26f1161..15d1234fcf 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -18,7 +18,6 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/MacroExpander.h" #include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/FoldingSet.h" namespace clang { @@ -81,7 +80,7 @@ class Preprocessor { /// flow (in clang::ParseAST()), make it convenient to put here. /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to /// the lifetime fo the preprocessor. - llvm::FoldingSet Selectors; + SelectorTable Selectors; /// PragmaHandlers - This tracks all of the pragmas that the client registered /// with this preprocessor. @@ -142,7 +141,7 @@ public: HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } IdentifierTable &getIdentifierTable() { return Identifiers; } - llvm::FoldingSet &getSelectorTable() { return Selectors; } + SelectorTable &getSelectorTable() { return Selectors; } /// SetCommentRetentionState - Control whether or not the preprocessor retains /// comments in output. diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index ce98d9d7e5..2a1f0f6196 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -303,9 +303,6 @@ private: void ParseObjCInstanceMethodDefinition(); void ParseObjCClassMethodDefinition(); - Selector ObjcGetUnarySelector(IdentifierInfo *unarySel); - Selector ObjcGetKeywordSelector(llvm::SmallVectorImpl &IIV); - //===--------------------------------------------------------------------===// // C99 6.5: Expressions.