aboutsummaryrefslogtreecommitdiff
path: root/lib/Checker/GRExprEngine.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-06-25 20:59:31 +0000
committerTed Kremenek <kremenek@apple.com>2010-06-25 20:59:31 +0000
commit9e9595b12e9b55586c4d50d370f429c7a3c92a90 (patch)
tree2afb34a0633e097dbf33ab744e835b97d6740a6d /lib/Checker/GRExprEngine.cpp
parentc4a1437c15da43eb8d2601cdce13161ef41a4389 (diff)
Add "checker caching" to GRExprEngine::CheckerVisit to progressively build
a winowed list of checkers that actually do something for a given StmtClass. As the number of checkers grows, this may potentially significantly reduce the number of checkers called at any one time. My own measurements show that for the ~20 registered Checker objects, only ~5 of them respond at any one time to a give statement. While this isn't a net performance win right now (there is a minor slowdown on sqlite.3) this improvement does greatly improve debugging when stepping through the checkers used to evaluate a given statement. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106884 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Checker/GRExprEngine.cpp')
-rw-r--r--lib/Checker/GRExprEngine.cpp54
1 files changed, 51 insertions, 3 deletions
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index b7b3502ccc..4c2512dfa4 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -172,13 +172,37 @@ public:
void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
ExplodedNodeSet &Src, bool isPrevisit) {
- if (Checkers.empty()) {
+ // Determine if we already have a cached 'CheckersOrdered' vector
+ // specifically tailored for the provided <Stmt kind, isPrevisit>. This
+ // can reduce the number of checkers actually called.
+ CheckersOrdered *CO = &Checkers;
+ llvm::OwningPtr<CheckersOrdered> NewCO;
+
+ const std::pair<unsigned, unsigned> &K =
+ std::make_pair((unsigned)S->getStmtClass(), isPrevisit ? 1U : 0U);
+
+ CheckersOrdered *& CO_Ref = COCache[K];
+
+ if (!CO_Ref) {
+ // If we have no previously cached CheckersOrdered vector for this
+ // statement kind, then create one.
+ NewCO.reset(new CheckersOrdered);
+ }
+ else {
+ // Use the already cached set.
+ CO = CO_Ref;
+ }
+
+ if (CO->empty()) {
+ // If there are no checkers, return early without doing any
+ // more work.
Dst.insert(Src);
return;
}
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
+ unsigned checkersEvaluated = 0;
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
ExplodedNodeSet *CurrSet = 0;
@@ -190,12 +214,30 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
}
void *tag = I->first;
Checker *checker = I->second;
+ bool respondsToCallback = true;
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI)
- checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
+ NI != NE; ++NI) {
+
+ checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit,
+ respondsToCallback);
+
+ }
+
PrevSet = CurrSet;
+
+ if (NewCO.get()) {
+ ++checkersEvaluated;
+ if (respondsToCallback)
+ NewCO->push_back(*I);
+ }
}
+
+ // If we built NewCO, check if we called all the checkers. This is important
+ // so that we know that we accurately determined the entire set of checkers
+ // that responds to this callback.
+ if (NewCO.get() && checkersEvaluated == Checkers.size())
+ CO_Ref = NewCO.take();
// Don't autotransition. The CheckerContext objects should do this
// automatically.
@@ -361,8 +403,14 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
GRExprEngine::~GRExprEngine() {
BR.FlushReports();
delete [] NSExceptionInstanceRaiseSelectors;
+
+ // Delete the set of checkers.
for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
delete I->second;
+
+ for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end();
+ I!=E;++I)
+ delete I->second;
}
//===----------------------------------------------------------------------===//