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.

llvm-svn: 155958
This commit is contained in:
Douglas Gregor 2012-05-01 23:07:34 +00:00
parent cd2353402d
commit f73e2604b1
2 changed files with 30 additions and 20 deletions

View File

@ -2130,12 +2130,15 @@ public:
void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP);
/// \brief Add the given method to the list of globally-known methods. /// \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: private:
/// AddMethodToGlobalPool - Add an instance or factory method to the global /// AddMethodToGlobalPool - Add an instance or factory method to the global
/// pool. See descriptoin of AddInstanceMethodToGlobalPool. /// 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 /// LookupMethodInGlobalPool - Returns the instance or factory method and
/// optionally warns if there are multiple signatures. /// 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 /// unit are added to a global pool. This allows us to efficiently associate
/// a selector with a method declaraation for purposes of typechecking /// a selector with a method declaraation for purposes of typechecking
/// messages sent to "id" (where the class of the object is unknown). /// 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. /// 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 /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global

View File

@ -1970,12 +1970,12 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
return true; 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 the list is empty, make it a singleton list.
if (List->Method == 0) { if (List->Method == 0) {
List->Method = Method; List->Method = Method;
List->Next = 0; List->Next = 0;
return; return true;
} }
// We've seen a method with this name, see if we have already seen this type // 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; List->Method = Method;
} }
return; return false;
} }
// We have a new signature for an existing method - add it. // We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded". // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
Previous->Next = new (Mem) ObjCMethodList(Method, 0); Previous->Next = new (Mem) ObjCMethodList(Method, 0);
return false;
} }
/// \brief Read the contents of the method pool for a given selector from /// \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); ExternalSource->ReadMethodPool(Sel);
} }
void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
bool instance) { bool instance) {
// Ignore methods of invalid containers. // Ignore methods of invalid containers.
if (cast<Decl>(Method->getDeclContext())->isInvalidDecl()) if (cast<Decl>(Method->getDeclContext())->isInvalidDecl())
return; return false;
if (ExternalSource) if (ExternalSource)
ReadMethodPool(Method->getSelector()); ReadMethodPool(Method->getSelector());
@ -2037,7 +2038,7 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
Method->setDefined(impl); Method->setDefined(impl);
ObjCMethodList &Entry = instance ? Pos->second.first : Pos->second.second; 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 /// 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; InsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "id". /// The following allows us to typecheck messages to "id".
AddInstanceMethodToGlobalPool(Method); if (!AddInstanceMethodToGlobalPool(Method)) {
// verify that the instance method conforms to the same definition of // verify that the instance method conforms to the same definition of
// parent methods if it shadows one. // parent methods if it shadows one.
CompareMethodParamsInBaseAndSuper(ClassDecl, Method, true); CompareMethodParamsInBaseAndSuper(ClassDecl, Method, true);
}
} }
} else { } else {
/// Check for class method of the same name with incompatible types /// 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; ClsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "Class". /// The following allows us to typecheck messages to "Class".
AddFactoryMethodToGlobalPool(Method); if (!AddFactoryMethodToGlobalPool(Method)) {
// verify that the class method conforms to the same definition of // verify that the class method conforms to the same definition of
// parent methods if it shadows one. // parent methods if it shadows one.
CompareMethodParamsInBaseAndSuper(ClassDecl, Method, false); CompareMethodParamsInBaseAndSuper(ClassDecl, Method, false);
}
} }
} }
} }