Add a callback for when region changes occur. Still somewhat of a work-in-progress, but working! Effect on clients: all changes to a store now go through GRState.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111078 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 7d01c9e..a5e87e4 100644
--- a/lib/Checker/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -52,7 +52,7 @@
   Store InvalidateRegions(Store store, const MemRegion * const *Begin,
                           const MemRegion * const *End, const Expr *E,
                           unsigned Count, InvalidatedSymbols *IS,
-                          bool invalidateGlobals);
+                          bool invalidateGlobals, InvalidatedRegions *Regions);
 
   Store scanForIvars(Stmt *B, const Decl* SelfDecl,
                      const MemRegion *SelfRegion, Store St);
@@ -521,11 +521,12 @@
 
 
 Store BasicStoreManager::InvalidateRegions(Store store,
-                                      const MemRegion * const *I,
-                                      const MemRegion * const *End,
-                                      const Expr *E, unsigned Count,
-                                      InvalidatedSymbols *IS,
-                                      bool invalidateGlobals) {
+                                           const MemRegion * const *I,
+                                           const MemRegion * const *End,
+                                           const Expr *E, unsigned Count,
+                                           InvalidatedSymbols *IS,
+                                           bool invalidateGlobals,
+                                           InvalidatedRegions *Regions) {
   if (invalidateGlobals) {
     BindingsTy B = GetBindings(store);
     for (BindingsTy::iterator I=B.begin(), End=B.end(); I != End; ++I) {
@@ -543,6 +544,8 @@
         continue;
     }
     store = InvalidateRegion(store, *I, E, Count, IS);
+    if (Regions)
+      Regions->push_back(R);
   }
 
   // FIXME: This is copy-and-paste from RegionStore.cpp.
@@ -556,6 +559,8 @@
                                   Count);
 
     store = Bind(store, loc::MemRegionVal(GS), V);
+    if (Regions)
+      Regions->push_back(GS);
   }
 
   return store;
diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp
index 64c6ed0..46e2477 100644
--- a/lib/Checker/FlatStore.cpp
+++ b/lib/Checker/FlatStore.cpp
@@ -60,7 +60,7 @@
   Store InvalidateRegions(Store store, const MemRegion * const *I,
                           const MemRegion * const *E, const Expr *Ex,
                           unsigned Count, InvalidatedSymbols *IS,
-                          bool invalidateGlobals);
+                          bool invalidateGlobals, InvalidatedRegions *Regions);
 
   void print(Store store, llvm::raw_ostream& Out, const char* nl, 
              const char *sep);
@@ -155,11 +155,12 @@
 }
 
 Store FlatStoreManager::InvalidateRegions(Store store,
-                                            const MemRegion * const *I,
-                                            const MemRegion * const *E,
-                                            const Expr *Ex, unsigned Count,
-                                            InvalidatedSymbols *IS,
-                                            bool invalidateGlobals) {
+                                          const MemRegion * const *I,
+                                          const MemRegion * const *E,
+                                          const Expr *Ex, unsigned Count,
+                                          InvalidatedSymbols *IS,
+                                          bool invalidateGlobals,
+                                          InvalidatedRegions *Regions) {
   assert(false && "Not implemented");
   return store;
 }
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index fe19c05..e306ac6 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -557,6 +557,75 @@
   return TF->EvalAssume(state, cond, assumption);
 }
 
+bool GRExprEngine::WantsRegionChangeUpdate(const GRState* state) {
+  CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
+  CheckersOrdered *CO = COCache[K];
+
+  if (!CO)
+    CO = &Checkers;
+
+  for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
+    Checker *C = I->second;
+    if (C->WantsRegionChangeUpdate(state))
+      return true;
+  }
+
+  return false;
+}
+
+const GRState *
+GRExprEngine::ProcessRegionChanges(const GRState *state,
+                                   const MemRegion * const *Begin,
+                                   const MemRegion * const *End) {
+  // FIXME: Most of this method is copy-pasted from ProcessAssume.
+
+  // Determine if we already have a cached 'CheckersOrdered' vector
+  // specifically tailored for processing region changes.  This
+  // can reduce the number of checkers actually called.
+  CheckersOrdered *CO = &Checkers;
+  llvm::OwningPtr<CheckersOrdered> NewCO;
+
+  CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
+  CheckersOrdered *& CO_Ref = COCache[K];
+
+  if (!CO_Ref) {
+    // If we have no previously cached CheckersOrdered vector for this
+    // callback, then create one.
+    NewCO.reset(new CheckersOrdered);
+  }
+  else {
+    // Use the already cached set.
+    CO = CO_Ref;
+  }
+
+  // If there are no checkers, just return the state as is.
+  if (CO->empty())
+    return state;
+
+  for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
+    // If any checker declares the state infeasible (or if it starts that way),
+    // bail out.
+    if (!state)
+      return NULL;
+
+    Checker *C = I->second;
+    bool respondsToCallback = true;
+
+    state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback);
+
+    // See if we're building a cache of checkers that care about region changes.
+    if (NewCO.get() && respondsToCallback)
+      NewCO->push_back(*I);
+  }
+
+  // If we got through all the checkers, and we built a list of those that
+  // care about region changes, save it.
+  if (NewCO.get())
+    CO_Ref = NewCO.take();
+
+  return state;
+}
+
 void GRExprEngine::ProcessEndWorklist(bool hasWorkRemaining) {
   for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
        I != E; ++I) {
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index 221406e..16aefbf 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -231,7 +231,8 @@
                           const MemRegion * const *End,
                           const Expr *E, unsigned Count,
                           InvalidatedSymbols *IS,
-                          bool invalidateGlobals);
+                          bool invalidateGlobals,
+                          InvalidatedRegions *Regions);
 
 public:   // Made public for helper classes.
 
@@ -572,14 +573,16 @@
   const Expr *Ex;
   unsigned Count;
   StoreManager::InvalidatedSymbols *IS;
+  StoreManager::InvalidatedRegions *Regions;
 public:
   InvalidateRegionsWorker(RegionStoreManager &rm,
                           GRStateManager &stateMgr,
                           RegionBindings b,
                           const Expr *ex, unsigned count,
-                          StoreManager::InvalidatedSymbols *is)
+                          StoreManager::InvalidatedSymbols *is,
+                          StoreManager::InvalidatedRegions *r)
     : ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b),
-      Ex(ex), Count(count), IS(is) {}
+      Ex(ex), Count(count), IS(is), Regions(r) {}
 
   void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
   void VisitBaseRegion(const MemRegion *baseR);
@@ -650,6 +653,10 @@
     return;
   }
 
+  // Otherwise, we have a normal data region. Record that we touched the region.
+  if (Regions)
+    Regions->push_back(baseR);
+
   if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
     // Invalidate the region by setting its default value to
     // conjured symbol. The type of the symbol is irrelavant.
@@ -700,10 +707,11 @@
                                             const MemRegion * const *E,
                                             const Expr *Ex, unsigned Count,
                                             InvalidatedSymbols *IS,
-                                            bool invalidateGlobals) {
+                                            bool invalidateGlobals,
+                                            InvalidatedRegions *Regions) {
   InvalidateRegionsWorker W(*this, StateMgr,
                             RegionStoreManager::GetRegionBindings(store),
-                            Ex, Count, IS);
+                            Ex, Count, IS, Regions);
 
   // Scan the bindings and generate the clusters.
   W.GenerateClusters(invalidateGlobals);
@@ -726,6 +734,11 @@
                                   /* symbol type, doesn't matter */ Ctx.IntTy,
                                   Count);
     B = Add(B, BindingKey::Make(GS, BindingKey::Default), V);
+
+    // Even if there are no bindings in the global scope, we still need to
+    // record that we touched it.
+    if (Regions)
+      Regions->push_back(GS);
   }
 
   return B.getRoot();