// Lookup the method implementation.
if (ReceiverT)
if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) {
- const ObjCMethodDecl *MD = IDecl->lookupPrivateMethod(Sel);
+ // Repeatedly calling lookupPrivateMethod() is expensive, especially
+ // when in many cases it returns null. We cache the results so
+ // that repeated queries on the same ObjCIntefaceDecl and Selector
+ // don't incur the same cost. On some test cases, we can see the
+ // same query being issued thousands of times.
+ //
+ // NOTE: This cache is essentially a "global" variable, but it
+ // only gets lazily created when we get here. The value of the
+ // cache probably comes from it being global across ExprEngines,
+ // where the same queries may get issued. If we are worried about
+ // concurrency, or possibly loading/unloading ASTs, etc., we may
+ // need to revisit this someday. In terms of memory, this table
+ // stays around until clang quits, which also may be bad if we
+ // need to release memory.
+ typedef std::pair<const ObjCInterfaceDecl*, Selector>
+ PrivateMethodKey;
+ typedef llvm::DenseMap<PrivateMethodKey,
+ llvm::Optional<const ObjCMethodDecl *> >
+ PrivateMethodCache;
+
+ static PrivateMethodCache PMC;
+ llvm::Optional<const ObjCMethodDecl *> &Val =
+ PMC[std::make_pair(IDecl, Sel)];
+
+ // Query lookupPrivateMethod() if the cache does not hit.
+ if (!Val.hasValue())
+ Val = IDecl->lookupPrivateMethod(Sel);
+
+ const ObjCMethodDecl *MD = Val.getValue();
if (CanBeSubClassed)
return RuntimeDefinition(MD, Receiver);
else