From f73e2604b10e001c0b4c4fcc885275d1c9eaa624 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 1 May 2012 23:07:34 +0000 Subject: [PATCH] The semantic checking that verifies whether an Objective-C method declared in a subclass has consistent parameter types with a method having the same selector in a superclass performs a significant number of lookups into the class hierarchy. In the example in , we spend 4.7% of -fsyntax-only time in these lookups. Optimize away most of the calls to this routine (Sema::CompareMethodParamsInBaseAndSuper) by first checking whether we have ever seen *any* method with that selector (using the global selector table). Since most selectors are unique, we can avoid the cost of this name lookup in many cases, for a 3.3% speedup. llvm-svn: 155958 --- clang/include/clang/Sema/Sema.h | 19 +++++++++++++------ clang/lib/Sema/SemaDeclObjC.cpp | 31 +++++++++++++++++-------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index decde814eb51..59de8c5519bf 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2130,12 +2130,15 @@ public: void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); /// \brief Add the given method to the list of globally-known methods. - void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); + /// + /// \returns true if this is the first method in the list with the given + /// selector. + bool addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); private: /// AddMethodToGlobalPool - Add an instance or factory method to the global /// pool. See descriptoin of AddInstanceMethodToGlobalPool. - void AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); + bool AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); /// LookupMethodInGlobalPool - Returns the instance or factory method and /// optionally warns if there are multiple signatures. @@ -2148,13 +2151,17 @@ public: /// unit are added to a global pool. This allows us to efficiently associate /// a selector with a method declaraation for purposes of typechecking /// messages sent to "id" (where the class of the object is unknown). - void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { - AddMethodToGlobalPool(Method, impl, /*instance*/true); + /// + /// Returns true if the method was added, false if a method was already there. + bool AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { + return AddMethodToGlobalPool(Method, impl, /*instance*/true); } /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. - void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { - AddMethodToGlobalPool(Method, impl, /*instance*/false); + /// + /// Returns true if the method was added, false if a method was already there. + bool AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { + return AddMethodToGlobalPool(Method, impl, /*instance*/false); } /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index ba741f379811..efbc1d224e53 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1970,12 +1970,12 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, return true; } -void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { +bool Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { // If the list is empty, make it a singleton list. if (List->Method == 0) { List->Method = Method; List->Next = 0; - return; + return true; } // We've seen a method with this name, see if we have already seen this type @@ -2004,13 +2004,14 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { List->Method = Method; } - return; + return false; } // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". ObjCMethodList *Mem = BumpAlloc.Allocate(); Previous->Next = new (Mem) ObjCMethodList(Method, 0); + return false; } /// \brief Read the contents of the method pool for a given selector from @@ -2020,11 +2021,11 @@ void Sema::ReadMethodPool(Selector Sel) { ExternalSource->ReadMethodPool(Sel); } -void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, +bool Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance) { // Ignore methods of invalid containers. if (cast(Method->getDeclContext())->isInvalidDecl()) - return; + return false; if (ExternalSource) ReadMethodPool(Method->getSelector()); @@ -2037,7 +2038,7 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, Method->setDefined(impl); ObjCMethodList &Entry = instance ? Pos->second.first : Pos->second.second; - addMethodToGlobalList(&Entry, Method); + return addMethodToGlobalList(&Entry, Method); } /// Determines if this is an "acceptable" loose mismatch in the global @@ -2272,10 +2273,11 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, } InsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "id". - AddInstanceMethodToGlobalPool(Method); - // verify that the instance method conforms to the same definition of - // parent methods if it shadows one. - CompareMethodParamsInBaseAndSuper(ClassDecl, Method, true); + if (!AddInstanceMethodToGlobalPool(Method)) { + // verify that the instance method conforms to the same definition of + // parent methods if it shadows one. + CompareMethodParamsInBaseAndSuper(ClassDecl, Method, true); + } } } else { /// Check for class method of the same name with incompatible types @@ -2299,10 +2301,11 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, } ClsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "Class". - AddFactoryMethodToGlobalPool(Method); - // verify that the class method conforms to the same definition of - // parent methods if it shadows one. - CompareMethodParamsInBaseAndSuper(ClassDecl, Method, false); + if (!AddFactoryMethodToGlobalPool(Method)) { + // verify that the class method conforms to the same definition of + // parent methods if it shadows one. + CompareMethodParamsInBaseAndSuper(ClassDecl, Method, false); + } } } }