diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/CallEvent.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 57f2f3355d..60b4d988d6 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -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 |