[cfe-commits] r106884 - in /cfe/trunk: include/clang/Checker/PathSensitive/Checker.h include/clang/Checker/PathSensitive/CheckerVisitor.h include/clang/Checker/PathSensitive/GRExprEngine.h lib/Checker/GRExprEngine.cpp

Ted Kremenek kremenek at apple.com
Fri Jun 25 13:59:31 PDT 2010


Author: kremenek
Date: Fri Jun 25 15:59:31 2010
New Revision: 106884

URL: http://llvm.org/viewvc/llvm-project?rev=106884&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/Checker/PathSensitive/Checker.h
    cfe/trunk/include/clang/Checker/PathSensitive/CheckerVisitor.h
    cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h
    cfe/trunk/lib/Checker/GRExprEngine.cpp

Modified: cfe/trunk/include/clang/Checker/PathSensitive/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/Checker.h?rev=106884&r1=106883&r2=106884&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/Checker.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Fri Jun 25 15:59:31 2010
@@ -38,16 +38,20 @@
   const unsigned size;
   bool DoneEvaluating; // FIXME: This is not a permanent API change.
 public:
+  bool *respondsToCallback;
+public:
   CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder,
                  GRExprEngine &eng, ExplodedNode *pred,
                  const void *tag, ProgramPoint::Kind K,
+                 bool *respondsToCB = 0,
                  const Stmt *stmt = 0, const GRState *st = 0)
     : Dst(dst), B(builder), Eng(eng), Pred(pred),
       OldSink(B.BuildSinks),
       OldTag(B.Tag, tag),
       OldPointKind(B.PointKind, K),
       OldHasGen(B.HasGeneratedNode),
-      ST(st), statement(stmt), size(Dst.size()) {}
+      ST(st), statement(stmt), size(Dst.size()),
+      respondsToCallback(respondsToCB) {}
 
   ~CheckerContext();
 
@@ -189,10 +193,11 @@
                 GRStmtNodeBuilder &Builder,
                 GRExprEngine &Eng,
                 const Stmt *S,
-                ExplodedNode *Pred, void *tag, bool isPrevisit) {
+                ExplodedNode *Pred, void *tag, bool isPrevisit,
+                bool& respondsToCallback) {
     CheckerContext C(Dst, Builder, Eng, Pred, tag,
                      isPrevisit ? ProgramPoint::PreStmtKind :
-                     ProgramPoint::PostStmtKind, S);
+                     ProgramPoint::PostStmtKind, &respondsToCallback, S);
     if (isPrevisit)
       _PreVisit(C, S);
     else
@@ -203,7 +208,7 @@
                           GRExprEngine &Eng, const ObjCMessageExpr *ME,
                           ExplodedNode *Pred, const GRState *state, void *tag) {
     CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
-                     ME, state);
+                     0, ME, state);
     return EvalNilReceiver(C, ME);
   }
 
@@ -211,7 +216,7 @@
                        GRExprEngine &Eng, const CallExpr *CE,
                        ExplodedNode *Pred, void *tag) {
     CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
-                     CE);
+                     0, CE);
     return EvalCallExpr(C, CE);
   }
 
@@ -224,7 +229,7 @@
                     bool isPrevisit) {
     CheckerContext C(Dst, Builder, Eng, Pred, tag,
                      isPrevisit ? ProgramPoint::PreStmtKind :
-                     ProgramPoint::PostStmtKind, StoreE);
+                     ProgramPoint::PostStmtKind, 0, StoreE);
     assert(isPrevisit && "Only previsit supported for now.");
     PreVisitBind(C, AssignE, StoreE, location, val);
   }
@@ -239,7 +244,7 @@
                         void *tag, bool isLoad) {
     CheckerContext C(Dst, Builder, Eng, Pred, tag,
                      isLoad ? ProgramPoint::PreLoadKind :
-                     ProgramPoint::PreStoreKind, S, state);
+                     ProgramPoint::PreStoreKind, 0, S, state);
     VisitLocation(C, S, location);
   }
 
@@ -247,7 +252,7 @@
                           GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred,
                           SymbolReaper &SymReaper, void *tag) {
     CheckerContext C(Dst, Builder, Eng, Pred, tag, 
-                     ProgramPoint::PostPurgeDeadSymbolsKind, S);
+                     ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
     EvalDeadSymbols(C, S, SymReaper);
   }
 

Modified: cfe/trunk/include/clang/Checker/PathSensitive/CheckerVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/CheckerVisitor.h?rev=106884&r1=106883&r2=106884&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/CheckerVisitor.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/CheckerVisitor.h Fri Jun 25 15:59:31 2010
@@ -79,8 +79,13 @@
     }
   }
 
-  void PreVisitStmt(CheckerContext &C, const Stmt *S) {}
-  void PostVisitStmt(CheckerContext &C, const Stmt *S) {}
+  void PreVisitStmt(CheckerContext &C, const Stmt *S) {
+    *C.respondsToCallback = false;
+  }
+
+  void PostVisitStmt(CheckerContext &C, const Stmt *S) {
+    *C.respondsToCallback = false;
+  }
 
   void PreVisitCastExpr(CheckerContext &C, const CastExpr *E) {
     static_cast<ImplClass*>(this)->PreVisitStmt(C, E);

Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h?rev=106884&r1=106883&r2=106884&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h Fri Jun 25 15:59:31 2010
@@ -75,14 +75,25 @@
   llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor;
 
   typedef llvm::DenseMap<void *, unsigned> CheckerMap;
-  CheckerMap CheckerM;
-  
   typedef std::vector<std::pair<void *, Checker*> > CheckersOrdered;
+  typedef llvm::DenseMap<std::pair<unsigned, unsigned>, CheckersOrdered *>
+          CheckersOrderedCache;
+  
+  /// A registration map from checker tag to the index into the
+  ///  ordered checkers vector.
+  CheckerMap CheckerM;
+
+  /// An ordered vector of checkers that are called when evaluating
+  ///  various expressions and statements.
   CheckersOrdered Checkers;
 
-  /// BR - The BugReporter associated with this engine.  It is important that
-  //   this object be placed at the very end of member variables so that its
-  //   destructor is called before the rest of the GRExprEngine is destroyed.
+  /// A map used for caching the checkers that respond to the callback for
+  ///  a particular statement and visitation order.
+  CheckersOrderedCache COCache;
+
+  /// The BugReporter associated with this engine.  It is important that
+  ///  this object be placed at the very end of member variables so that its
+  ///  destructor is called before the rest of the GRExprEngine is destroyed.
   GRBugReporter BR;
   
   llvm::OwningPtr<GRTransferFuncs> TF;

Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=106884&r1=106883&r2=106884&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Checker/GRExprEngine.cpp Fri Jun 25 15:59:31 2010
@@ -172,13 +172,37 @@
 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 *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() {
   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;
 }
 
 //===----------------------------------------------------------------------===//





More information about the cfe-commits mailing list