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
<rdar://problem/11004361>, 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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155958 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index decde81..59de8c5 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2130,12 +2130,15 @@
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 @@
/// 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/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index ba741f3..efbc1d2 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1970,12 +1970,12 @@
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 @@
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<ObjCMethodList>();
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 @@
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<Decl>(Method->getDeclContext())->isInvalidDecl())
- return;
+ return false;
if (ExternalSource)
ReadMethodPool(Method->getSelector());
@@ -2037,7 +2038,7 @@
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 @@
}
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 @@
}
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);
+ }
}
}
}