]> granicus.if.org Git - clang/commitdiff
Recycle memory for GRStates that are never referenced
authorTed Kremenek <kremenek@apple.com>
Tue, 25 Jan 2011 19:13:54 +0000 (19:13 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 25 Jan 2011 19:13:54 +0000 (19:13 +0000)
by ExplodedNodes.  This leads to about a 4-8%
reduction in memory footprint when analyzing
functions in sqlite3.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124214 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h
include/clang/StaticAnalyzer/PathSensitive/GRState.h
lib/StaticAnalyzer/Checkers/ExprEngine.cpp
lib/StaticAnalyzer/GRState.cpp

index 853d3c5ec7cc5dc81f8e140b7f1ff48a01c6fc04..0d6044b5d2bfbdd4487b8c653566edd8d21586cb 100644 (file)
@@ -31,6 +31,7 @@
 #include "llvm/ADT/DepthFirstIterator.h"
 #include "llvm/Support/Casting.h"
 #include "clang/Analysis/Support/BumpVector.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 
 namespace clang {
 
@@ -38,7 +39,6 @@ class CFG;
 
 namespace ento {
 
-class GRState;
 class ExplodedGraph;
 
 //===----------------------------------------------------------------------===//
@@ -115,7 +115,9 @@ class ExplodedNode : public llvm::FoldingSetNode {
 public:
 
   explicit ExplodedNode(const ProgramPoint& loc, const GRState* state)
-    : Location(loc), State(state) {}
+    : Location(loc), State(state) {
+    const_cast<GRState*>(State)->setReferencedByExplodedNode();
+  }
 
   /// getLocation - Returns the edge associated with the given node.
   ProgramPoint getLocation() const { return Location; }
index 48cc7a7fd55340d0fa82b9b25a2dcce313db6700..5a87cb4fb701de71728e6e975fbc89364e2d957f 100644 (file)
@@ -18,6 +18,7 @@
 #include "clang/StaticAnalyzer/PathSensitive/Environment.h"
 #include "clang/StaticAnalyzer/PathSensitive/Store.h"
 #include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
+#include "llvm/ADT/PointerIntPair.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableMap.h"
 #include "llvm/Support/Casting.h"
@@ -78,7 +79,7 @@ private:
 
   friend class GRStateManager;
 
-  GRStateManager *StateMgr;
+  llvm::PointerIntPair<GRStateManager *, 1, bool> stateMgr;
   Environment Env;           // Maps a Stmt to its current SVal.
   Store St;                  // Maps a location to its current value.
   GenericDataMap   GDM;      // Custom data stored by a client of this class.
@@ -92,7 +93,7 @@ public:
   /// This ctor is used when creating the first GRState object.
   GRState(GRStateManager *mgr, const Environment& env,
           Store st, GenericDataMap gdm)
-    : StateMgr(mgr),
+    : stateMgr(mgr, false),
       Env(env),
       St(st),
       GDM(gdm) {}
@@ -101,14 +102,23 @@ public:
   ///  in FoldingSetNode will also get copied.
   GRState(const GRState& RHS)
     : llvm::FoldingSetNode(),
-      StateMgr(RHS.StateMgr),
+      stateMgr(RHS.stateMgr.getPointer(), false),
       Env(RHS.Env),
       St(RHS.St),
       GDM(RHS.GDM) {}
 
-  /// getStateManager - Return the GRStateManager associated with this state.
+  /// Return the GRStateManager associated with this state.
   GRStateManager &getStateManager() const {
-    return *StateMgr;
+    return *stateMgr.getPointer();
+  }
+
+  /// Return true if this state is referenced by a persistent ExplodedNode.
+  bool referencedByExplodedNode() const {
+    return stateMgr.getInt();
+  }
+  
+  void setReferencedByExplodedNode() {
+    stateMgr.setInt(true);
   }
 
   /// getEnvironment - Return the environment associated with this state.
@@ -428,9 +438,16 @@ private:
   /// Object that manages the data for all created SVals.
   llvm::OwningPtr<SValBuilder> svalBuilder;
 
-  /// Alloc - A BumpPtrAllocator to allocate states.
+  /// A BumpPtrAllocator to allocate states.
   llvm::BumpPtrAllocator &Alloc;
 
+  /// A vector of recently allocated GRStates that can potentially be
+  /// reused.
+  std::vector<GRState *> recentlyAllocatedStates;
+  
+  /// A vector of GRStates that we can reuse.
+  std::vector<GRState *> freeStates;
+
 public:
   GRStateManager(ASTContext& Ctx,
                  StoreManagerCreator CreateStoreManager,
@@ -509,6 +526,10 @@ public:
   }
 
   const GRState* getPersistentState(GRState& Impl);
+  
+  /// Periodically called by ExprEngine to recycle GRStates that were
+  /// created but never used for creating an ExplodedNode.
+  void recycleUnusedStates();
 
   //==---------------------------------------------------------------------==//
   // Generic Data Map methods.
index 53931dc607a883d92e8cd6dc6a2af72cebad3302..f311bea87787b2bf65873bcbb902f1de28a2f774 100644 (file)
@@ -574,6 +574,9 @@ void ExprEngine::processCFGElement(const CFGElement E,
 }
 
 void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
+  // Recycle any unused states in the GRStateManager.
+  StateMgr.recycleUnusedStates();
+  
   currentStmt = S.getStmt();
   PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
                                 currentStmt->getLocStart(),
index 60832e8f7913d96c387d1c754f5df5f42bb1f8d6..18995b2ce773a8ddf6109bc0cc79de52be351bfd 100644 (file)
@@ -285,6 +285,18 @@ const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) {
   return getPersistentState(State);
 }
 
+void GRStateManager::recycleUnusedStates() {
+  for (std::vector<GRState*>::iterator i = recentlyAllocatedStates.begin(),
+       e = recentlyAllocatedStates.end(); i != e; ++i) {
+    GRState *state = *i;
+    if (state->referencedByExplodedNode())
+      continue;
+    StateSet.RemoveNode(state);
+    freeStates.push_back(state);
+  }
+  recentlyAllocatedStates.clear();
+}
+
 const GRState* GRStateManager::getPersistentState(GRState& State) {
 
   llvm::FoldingSetNodeID ID;
@@ -294,10 +306,18 @@ const GRState* GRStateManager::getPersistentState(GRState& State) {
   if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
     return I;
 
-  GRState* I = (GRState*) Alloc.Allocate<GRState>();
-  new (I) GRState(State);
-  StateSet.InsertNode(I, InsertPos);
-  return I;
+  GRState *newState = 0;
+  if (!freeStates.empty()) {
+    newState = freeStates.back();
+    freeStates.pop_back();    
+  }
+  else {
+    newState = (GRState*) Alloc.Allocate<GRState>();
+  }
+  new (newState) GRState(State);
+  StateSet.InsertNode(newState, InsertPos);
+  recentlyAllocatedStates.push_back(newState);
+  return newState;
 }
 
 const GRState* GRState::makeWithStore(Store store) const {