From bcfb06ac6da1aa3c74ac1ef7a49c2807522366e7 Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Fri, 28 Sep 2007 22:22:11 +0000 Subject: [PATCH] Yesterday I discovered that 78% of all selectors in "Cocoa.h" take 0/1 argument. This motivated implementing a devious clattner inspired solution:-) This approach uses a small value "Selector" class to point to an IdentifierInfo for the 0/1 case. For multi-keyword selectors, we instantiate a MultiKeywordSelector object (previously known as SelectorInfo). Now, the incremental cost for selectors is only 24,800 for Cocoa.h! This saves 156,592 bytes, or 86%!! The size reduction is also the result of getting rid of the AST slot, which was not strictly necessary (we will associate a selector with it's method using another table...most likely in Sema). This change was critical to make now, before we have too many clients. I still need to add some comments to the Selector class...will likely add later today/tomorrow. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42452 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/Expr.cpp | 27 ++----- Lex/IdentifierTable.cpp | 42 +++++----- Parse/ParseObjc.cpp | 77 +++++++----------- Sema/Sema.h | 6 +- Sema/SemaDecl.cpp | 34 ++++---- Sema/SemaExpr.cpp | 4 +- clang.xcodeproj/project.pbxproj | 1 - include/clang/AST/ASTContext.h | 4 +- include/clang/AST/Decl.h | 11 ++- include/clang/AST/Expr.h | 26 +++--- include/clang/Lex/IdentifierTable.h | 120 ++++++++++++++++++++++------ include/clang/Lex/Preprocessor.h | 4 +- include/clang/Parse/Action.h | 10 +-- include/clang/Parse/Parser.h | 3 + 14 files changed, 210 insertions(+), 159 deletions(-) diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 312d209e2d..40a95c0276 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -869,11 +869,11 @@ unsigned OCUVectorElementExpr::getEncodedElementAccess() const { } // constructor for instance messages. -ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, SelectorInfo *selInfo, +ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, QualType retType, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs) - : Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(0) { - unsigned numArgs = selInfo->getNumArgs(); + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), ClassName(0) { + unsigned numArgs = selInfo.getNumArgs(); SubExprs = new Expr*[numArgs+1]; SubExprs[RECEIVER] = receiver; if (numArgs) { @@ -886,11 +886,11 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, SelectorInfo *selInfo, // constructor for class messages. // FIXME: clsName should be typed to ObjCInterfaceType -ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo *selInfo, +ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, QualType retType, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs) - : Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(clsName) { - unsigned numArgs = selInfo->getNumArgs(); + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), ClassName(clsName) { + unsigned numArgs = selInfo.getNumArgs(); SubExprs = new Expr*[numArgs+1]; SubExprs[RECEIVER] = 0; if (numArgs) { @@ -901,21 +901,6 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo *selInfo, RBracloc = RBrac; } -// The following 3 methods are defined here (instead of Epxr.h) to avoid -// importing "IdentifierTable.h" into the header. -unsigned ObjCMessageExpr::getNumArgs() const { return Selector->getNumArgs(); } - -/// getArg - Return the specified argument. -Expr *ObjCMessageExpr::getArg(unsigned Arg) { - assert(Arg < Selector->getNumArgs() && "Arg access out of range!"); - return SubExprs[Arg+ARGS_START]; -} -const Expr *ObjCMessageExpr::getArg(unsigned Arg) const { - assert(Arg < Selector->getNumArgs() && "Arg access out of range!"); - return SubExprs[Arg+ARGS_START]; -} - - //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// diff --git a/Lex/IdentifierTable.cpp b/Lex/IdentifierTable.cpp index de68435549..9a03d3f72d 100644 --- a/Lex/IdentifierTable.cpp +++ b/Lex/IdentifierTable.cpp @@ -33,27 +33,33 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const { return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword; } -char *SelectorInfo::getName(llvm::SmallVectorImpl &methodName) { - int len=0; +char *MultiKeywordSelector::getName(llvm::SmallVectorImpl &methodName) { methodName[0] = '\0'; - if (NumArgs) { - keyword_iterator KeyIter = keyword_begin(); - for (unsigned int i = 0; i < NumArgs; i++) { - if (KeyIter[i]) { - unsigned KeyLen = strlen(KeyIter[i]->getName()); - methodName.append(KeyIter[i]->getName(), KeyIter[i]->getName()+KeyLen); - len += KeyLen; - } - methodName.push_back(':'); - len++; + keyword_iterator KeyIter = keyword_begin(); + for (unsigned int i = 0; i < NumArgs; i++) { + if (KeyIter[i]) { + unsigned KeyLen = strlen(KeyIter[i]->getName()); + methodName.append(KeyIter[i]->getName(), KeyIter[i]->getName()+KeyLen); } - } else { - IdentifierInfo **UnaryInfo = reinterpret_cast(this+1); - unsigned NameLen = strlen(UnaryInfo[0]->getName()); - methodName.append(UnaryInfo[0]->getName(), UnaryInfo[0]->getName()+NameLen); - len += NameLen; + 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 = strlen(II->getName()); + 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); } - methodName[len] = '\0'; return &methodName[0]; } diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index ba29edec4b..3317b88da3 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -502,50 +502,35 @@ Parser::TypeTy *Parser::ParseObjCTypeName() { return Ty; } -static SelectorInfo *ObjcGetUnarySelectorInfo( - IdentifierInfo *unarySel, - llvm::FoldingSet &SelTab) +Selector Parser::ObjcGetUnarySelector(IdentifierInfo *unarySel) { - // Unique selector, to guarantee there is one per name. - llvm::SmallVector IIV; - llvm::FoldingSetNodeID ID; - - IIV.push_back(unarySel); - SelectorInfo::Profile(ID, &IIV[0], 0); - - void *InsertPos = 0; - if (SelectorInfo *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) - return SI; - - // SelectorInfo objects are not allocated with new because they have a - // variable size array (for parameter types) at the end of them. - SelectorInfo *SI = - (SelectorInfo*)malloc(sizeof(SelectorInfo) + sizeof(IdentifierInfo *)); - new (SI) SelectorInfo(IIV[0]); - SelTab.InsertNode(SI, InsertPos); - return SI; + return Selector(unarySel, 0); } -static SelectorInfo *ObjcGetKeywordSelectorInfo( - llvm::SmallVectorImpl &IIV, - llvm::FoldingSet &SelTab) -{ +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; - SelectorInfo::Profile(ID, &IIV[0], IIV.size()); + MultiKeywordSelector::Profile(ID, &IIV[0], IIV.size()); void *InsertPos = 0; - if (SelectorInfo *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) - return SI; - - // SelectorInfo objects are not allocated with new because they have a + 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. - SelectorInfo *SI = - (SelectorInfo*)malloc(sizeof(SelectorInfo) + - IIV.size()*sizeof(IdentifierInfo *)); - new (SI) SelectorInfo(IIV.size(), &IIV[0]); + MultiKeywordSelector *SI = + (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + + IIV.size()*sizeof(IdentifierInfo *)); + new (SI) MultiKeywordSelector(IIV.size(), &IIV[0]); SelTab.InsertNode(SI, InsertPos); - return SI; + return Selector(SI); } /// objc-method-decl: @@ -646,9 +631,8 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) methodAttrs = ParseAttributes(); - SelectorInfo *SI = ObjcGetKeywordSelectorInfo(KeyIdents, - PP.getSelectorTable()); - return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, SI, + Selector Sel = ObjcGetKeywordSelector(KeyIdents); + return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, Sel, &KeyTypes[0], &ArgNames[0], methodAttrs, MethodImplKind); } else if (!selIdent) { @@ -658,8 +642,8 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) methodAttrs = ParseAttributes(); - SelectorInfo *SI = ObjcGetUnarySelectorInfo(selIdent, PP.getSelectorTable()); - return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, SI, + Selector Sel = ObjcGetUnarySelector(selIdent); + return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, Sel, 0, 0, methodAttrs, MethodImplKind); } @@ -1255,21 +1239,20 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { SourceLocation RBracloc = ConsumeBracket(); // consume ']' if (KeyIdents.size()) { - SelectorInfo *SI = ObjcGetKeywordSelectorInfo(KeyIdents, - PP.getSelectorTable()); + Selector sel = ObjcGetKeywordSelector(KeyIdents); // We've just parsed a keyword message. if (ReceiverName) - return Actions.ActOnClassMessage(ReceiverName, SI, LBracloc, RBracloc, + return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc, &KeyExprs[0]); - return Actions.ActOnInstanceMessage(ReceiverExpr, SI, LBracloc, RBracloc, + return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc, &KeyExprs[0]); } - SelectorInfo *SI = ObjcGetUnarySelectorInfo(selIdent, PP.getSelectorTable()); + Selector sel = ObjcGetUnarySelector(selIdent); // We've just parsed a unary message (a message with no arguments). if (ReceiverName) - return Actions.ActOnClassMessage(ReceiverName, SI, LBracloc, RBracloc, 0); - return Actions.ActOnInstanceMessage(ReceiverExpr, SI, 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/Sema/Sema.h b/Sema/Sema.h index a486d4fa73..d9a1cc4fe2 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -391,7 +391,7 @@ public: DeclTy **Fields, unsigned NumFields); virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel, + tok::TokenKind MethodType, TypeTy *ReturnType, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). TypeTy **ArgTypes, IdentifierInfo **ArgNames, @@ -401,14 +401,14 @@ public: // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). virtual ExprResult ActOnClassMessage( - IdentifierInfo *receivingClassName, SelectorInfo *Sel, + IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs); // ActOnInstanceMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). virtual ExprResult ActOnInstanceMessage( - ExprTy *receiver, SelectorInfo *Sel, + ExprTy *receiver, Selector Sel, SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs); private: // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 45762acd37..28682cc0e5 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -1178,23 +1178,23 @@ void Sema::ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl, /// Declared in protocol, and those referenced by it. /// static void CheckProtocolMethodDefs(Sema* objSema, ObjcProtocolDecl *PDecl, - const llvm::DenseMap& InsMap, - const llvm::DenseMap& ClsMap) { + const llvm::DenseMap& InsMap, + const llvm::DenseMap& ClsMap) { // check unimplemented instance methods. ObjcMethodDecl** methods = PDecl->getInsMethods(); for (int j = 0; j < PDecl->getNumInsMethods(); j++) - if (!InsMap.count(methods[j]->getSelector())) { + if (!InsMap.count(methods[j]->getSelector().getAsOpaquePtr())) { llvm::SmallString<128> buf; objSema->Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector()->getName(buf)); + methods[j]->getSelector().getName(buf)); } // check unimplemented class methods methods = PDecl->getClsMethods(); for (int j = 0; j < PDecl->getNumClsMethods(); j++) - if (!ClsMap.count(methods[j]->getSelector())) { + if (!ClsMap.count(methods[j]->getSelector().getAsOpaquePtr())) { llvm::SmallString<128> buf; objSema->Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector()->getName(buf)); + methods[j]->getSelector().getName(buf)); } // Check on this protocols's referenced protocols, recursively @@ -1206,35 +1206,35 @@ static void CheckProtocolMethodDefs(Sema* objSema, ObjcProtocolDecl *PDecl, static void ImplMethodsVsClassMethods(Sema* objSema, ObjcImplementationDecl* IMPDecl, ObjcInterfaceDecl* IDecl) { - llvm::DenseMap InsMap; + llvm::DenseMap InsMap; // Check and see if instance methods in class interface have been // implemented in the implementation class. ObjcMethodDecl **methods = IMPDecl->getInsMethods(); for (int i=0; i < IMPDecl->getNumInsMethods(); i++) { - InsMap[methods[i]->getSelector()] = 'a'; + InsMap[methods[i]->getSelector().getAsOpaquePtr()] = 'a'; } methods = IDecl->getInsMethods(); for (int j = 0; j < IDecl->getNumInsMethods(); j++) - if (!InsMap.count(methods[j]->getSelector())) { + if (!InsMap.count(methods[j]->getSelector().getAsOpaquePtr())) { llvm::SmallString<128> buf; objSema->Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector()->getName(buf)); + methods[j]->getSelector().getName(buf)); } - llvm::DenseMap ClsMap; + llvm::DenseMap ClsMap; // Check and see if class methods in class interface have been // implemented in the implementation class. methods = IMPDecl->getClsMethods(); for (int i=0; i < IMPDecl->getNumClsMethods(); i++) { - ClsMap[methods[i]->getSelector()] = 'a'; + ClsMap[methods[i]->getSelector().getAsOpaquePtr()] = 'a'; } methods = IDecl->getClsMethods(); for (int j = 0; j < IDecl->getNumClsMethods(); j++) - if (!ClsMap.count(methods[j]->getSelector())) { + if (!ClsMap.count(methods[j]->getSelector().getAsOpaquePtr())) { llvm::SmallString<128> buf; objSema->Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector()->getName(buf)); + methods[j]->getSelector().getName(buf)); } // Check the protocol list for unimplemented methods in the @implementation @@ -1650,14 +1650,14 @@ void Sema::ObjcAddMethodsToClass(DeclTy *ClassDecl, } Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel, + tok::TokenKind MethodType, TypeTy *ReturnType, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). TypeTy **ArgTypes, IdentifierInfo **ArgNames, AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind) { llvm::SmallVector Params; - for (unsigned i = 0; i < Sel->getNumArgs(); i++) { + for (unsigned i = 0; i < Sel.getNumArgs(); i++) { // FIXME: arg->AttrList must be stored too! ParmVarDecl* Param = new ParmVarDecl(SourceLocation(/*FIXME*/), ArgNames[i], QualType::getFromOpaquePtr(ArgTypes[i]), @@ -1668,7 +1668,7 @@ Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc, ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, Sel, resultDeclType, 0, -1, AttrList, MethodType == tok::minus); - ObjcMethod->setMethodParams(&Params[0], Sel->getNumArgs()); + ObjcMethod->setMethodParams(&Params[0], Sel.getNumArgs()); if (MethodDeclKind == tok::objc_optional) ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional); else diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 67aa04de99..0041805dfb 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1875,7 +1875,7 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). Sema::ExprResult Sema::ActOnClassMessage( - IdentifierInfo *receivingClassName, SelectorInfo *Sel, + IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args) { assert(receivingClassName && "missing receiver class name"); @@ -1889,7 +1889,7 @@ Sema::ExprResult Sema::ActOnClassMessage( // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). Sema::ExprResult Sema::ActOnInstanceMessage( - ExprTy *receiver, SelectorInfo *Sel, + ExprTy *receiver, Selector Sel, SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args) { assert(receiver && "missing receiver expression"); diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index fca0464b47..04dad73923 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -733,7 +733,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 f06f702dfd..86051eaa3c 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -48,7 +48,7 @@ public: SourceManager &SourceMgr; TargetInfo &Target; IdentifierTable &Idents; - llvm::FoldingSet &Selectors; + llvm::FoldingSet &Selectors; Builtin::Context BuiltinInfo; // Builtin Types. @@ -62,7 +62,7 @@ public: QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents, - llvm::FoldingSet &sels) : + llvm::FoldingSet &sels) : CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t), Idents(idents), Selectors(sels) { InitBuiltinTypes(); diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index dddd273962..2133d7a053 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -17,10 +17,9 @@ #include "clang/Basic/SourceLocation.h" #include "clang/AST/Type.h" #include "llvm/ADT/APSInt.h" +#include "clang/Lex/IdentifierTable.h" // FIXME: should be in Basic, not Lex. namespace clang { -class IdentifierInfo; -class SelectorInfo; class Expr; class Stmt; class FunctionDecl; @@ -676,7 +675,7 @@ public: enum ImplementationControl { None, Required, Optional }; private: // A unigue name for this method. - SelectorInfo *Selector; + Selector SelName; // Type of this method. QualType MethodDeclType; @@ -697,11 +696,11 @@ private: ImplementationControl DeclImplementation : 2; public: - ObjcMethodDecl(SourceLocation L, SelectorInfo *SelInfo, QualType T, + ObjcMethodDecl(SourceLocation L, Selector SelInfo, QualType T, ParmVarDecl **paramInfo = 0, int numParams=-1, AttributeList *M = 0, bool isInstance = true, Decl *PrevDecl = 0) - : Decl(ObjcMethod), Selector(SelInfo), MethodDeclType(T), + : Decl(ObjcMethod), SelName(SelInfo), MethodDeclType(T), ParamInfo(paramInfo), NumMethodParams(numParams), MethodAttrs(M), Loc(L), IsInstance(isInstance) {} #if 0 @@ -714,7 +713,7 @@ public: MethodAttrs(M), IsInstance(isInstance) {} #endif virtual ~ObjcMethodDecl(); - SelectorInfo *getSelector() const { return Selector; } + Selector getSelector() const { return SelName; } QualType getMethodType() const { return MethodDeclType; } unsigned getNumMethodParams() const { return NumMethodParams; } ParmVarDecl *getMethodParamDecl(unsigned i) { diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 046c73a44c..0a0e685f80 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -19,10 +19,11 @@ #include "clang/AST/Decl.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/APFloat.h" +#include "clang/Lex/IdentifierTable.h" // FIXME: should be in Basic, not Lex. namespace clang { class IdentifierInfo; - class SelectorInfo; + class Selector; class Decl; class ASTContext; @@ -1077,7 +1078,7 @@ class ObjCMessageExpr : public Expr { Expr **SubExprs; // A unigue name for this message. - SelectorInfo *Selector; + Selector SelName; IdentifierInfo *ClassName; // optional - 0 for instance messages. @@ -1085,11 +1086,11 @@ class ObjCMessageExpr : public Expr { public: // constructor for class messages. // FIXME: clsName should be typed to ObjCInterfaceType - ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo *selInfo, + ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, QualType retType, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs); // constructor for instance messages. - ObjCMessageExpr(Expr *receiver, SelectorInfo *selInfo, + ObjCMessageExpr(Expr *receiver, Selector selInfo, QualType retType, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs); ~ObjCMessageExpr() { @@ -1100,12 +1101,17 @@ public: Expr *getReceiver() { return SubExprs[RECEIVER]; } /// getNumArgs - Return the number of actual arguments to this call. - /// - unsigned getNumArgs() const; - - /// getArg - Return the specified argument. - Expr *getArg(unsigned Arg); - const Expr *getArg(unsigned Arg) const; + unsigned getNumArgs() const { return SelName.getNumArgs(); } + +/// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < SelName.getNumArgs() && "Arg access out of range!"); + return SubExprs[Arg+ARGS_START]; + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < SelName.getNumArgs() && "Arg access out of range!"); + return SubExprs[Arg+ARGS_START]; + } SourceRange getSourceRange() const { return SourceRange(LBracloc, RBracloc); } diff --git a/include/clang/Lex/IdentifierTable.h b/include/clang/Lex/IdentifierTable.h index f676cd991e..100f940e0e 100644 --- a/include/clang/Lex/IdentifierTable.h +++ b/include/clang/Lex/IdentifierTable.h @@ -170,28 +170,24 @@ private: void AddKeywords(const LangOptions &LangOpts); }; -/// SelectorInfo - One of these variable length records is kept for each parsed -/// selector (similar in spirit to IdentifierInfo). We use a folding set to -/// unique aggregate names (keyword selectors in ObjC parlance). -class SelectorInfo : public llvm::FoldingSetNode { +/// MultiKeywordSelector - One of these variable length records is kept for each +/// parsed selector (similar in spirit to IdentifierInfo). We use a folding set +/// to unique aggregate names (keyword selectors in ObjC parlance). +class MultiKeywordSelector : public llvm::FoldingSetNode { + friend class Selector; // Only Selector can access me. + friend class Parser; // Only Parser can instantiate me. + unsigned NumArgs; - void *ActionInfo; // Managed by the ObjC actions module. -public: + // Constructor for keyword selectors. - SelectorInfo(unsigned nKeys, IdentifierInfo **IIV) { - assert(nKeys && "SelectorInfo(): not a keyword selector"); + 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]; } - // Constructor for unary selectors (no colons/arguments). - SelectorInfo(IdentifierInfo *unarySelector) { - NumArgs = 0; - IdentifierInfo **UnaryInfo = reinterpret_cast(this+1); - UnaryInfo[0] = unarySelector; - } // 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); @@ -199,23 +195,18 @@ public: unsigned getNumArgs() const { return NumArgs; } - // Predicates to identify the selector type. - bool isKeywordSelector() const { return NumArgs > 0; } - bool isUnarySelector() const { return NumArgs == 0; } - - /// getActionInfo/setActionInfo - The actions module is allowed to - /// associate arbitrary metadata with this selector. - template - T *getActionInfo() const { return static_cast(ActionInfo); } - void setActionInfo(void *T) { ActionInfo = T; } - - typedef const IdentifierInfo *const *keyword_iterator; + 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]; + } +public: static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys, unsigned NumArgs) { ID.AddInteger(NumArgs); @@ -230,6 +221,85 @@ public: } }; +class Selector { + enum IdentifierInfoFlag { + ZeroArg = 0x1, + OneArg = 0x2, + ArgFlags = ZeroArg|OneArg + }; + uintptr_t InfoPtr; // a pointer to the MultiKeywordSelector or IdentifierInfo. + + Selector(IdentifierInfo *II, unsigned nArgs) { + InfoPtr = reinterpret_cast(II); + if (nArgs == 0) + InfoPtr |= ZeroArg; + else if (nArgs == 1) + InfoPtr |= OneArg; + else + assert(1 && "nArgs not equal to 0/1"); + } + Selector(MultiKeywordSelector *SI) { + InfoPtr = reinterpret_cast(SI); + } + friend class Parser; // only the Parser can create these. + + IdentifierInfo *getAsIdentifierInfo() const { + if (InfoPtr & ArgFlags) + return reinterpret_cast(InfoPtr & ~ArgFlags); + return 0; + } + MultiKeywordSelector *getAsMultiKeywordSelector() const { + if (InfoPtr & ArgFlags) + return 0; + return reinterpret_cast(InfoPtr); + } +public: + unsigned getIdentifierInfoFlag() const { + return InfoPtr & ArgFlags; + } + /// operator==/!= - Indicate whether the specified selectors are identical. + bool operator==(const Selector &RHS) const { + return InfoPtr == RHS.InfoPtr; + } + bool operator!=(const Selector &RHS) const { + return InfoPtr != RHS.InfoPtr; + } + void *getAsOpaquePtr() const { + return reinterpret_cast(InfoPtr); + } + // Predicates to identify the selector type. + bool isKeywordSelector() const { + return getIdentifierInfoFlag() != ZeroArg; + } + bool isUnarySelector() const { + return getIdentifierInfoFlag() == ZeroArg; + } + unsigned 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 *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); + } + // 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); +}; + } // end namespace clang #endif diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index b3008375d8..02f26f1161 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -81,7 +81,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; + llvm::FoldingSet Selectors; /// PragmaHandlers - This tracks all of the pragmas that the client registered /// with this preprocessor. @@ -142,7 +142,7 @@ public: HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } IdentifierTable &getIdentifierTable() { return Identifiers; } - llvm::FoldingSet &getSelectorTable() { return Selectors; } + llvm::FoldingSet &getSelectorTable() { return Selectors; } /// SetCommentRetentionState - Control whether or not the preprocessor retains /// comments in output. diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 3e9a687ef4..9ef27de47d 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -16,6 +16,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TokenKinds.h" +#include "clang/Lex/IdentifierTable.h" // FIXME: should be in Basic, not Lex. namespace clang { // Semantic. @@ -25,9 +26,8 @@ namespace clang { // Parse. class Scope; class Action; - class SelectorInfo; + class Selector; // Lex. - class IdentifierInfo; // FIXME: should be in Basic, not Lex. class Token; /// Action - As the parser reads the input file and recognizes the productions @@ -471,7 +471,7 @@ public: return 0; } virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel, + tok::TokenKind MethodType, TypeTy *ReturnType, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). TypeTy **ArgTypes, IdentifierInfo **ArgNames, @@ -482,7 +482,7 @@ public: // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). virtual ExprResult ActOnClassMessage( - IdentifierInfo *receivingClassName, SelectorInfo *Sel, + IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs) { return 0; } @@ -490,7 +490,7 @@ public: // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). virtual ExprResult ActOnInstanceMessage( - ExprTy *receiver, SelectorInfo *Sel, + ExprTy *receiver, Selector Sel, SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs) { return 0; } diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 3982028ff2..db83443442 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -302,6 +302,9 @@ private: void ParseObjCInstanceMethodDefinition(); void ParseObjCClassMethodDefinition(); + + Selector ObjcGetUnarySelector(IdentifierInfo *unarySel); + Selector ObjcGetKeywordSelector(llvm::SmallVectorImpl &IIV); //===--------------------------------------------------------------------===// // C99 6.5: Expressions. -- 2.40.0