|
@@ -835,7 +835,35 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
|
|
|
// 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
|