Recycle memory for GRStates that are never referenced

by ExplodedNodes.  This leads to about a 4-8%
reduction in memory footprint when analyzing
functions in sqlite3.

llvm-svn: 124214
This commit is contained in:
Ted Kremenek 2011-01-25 19:13:54 +00:00
parent bcf848f70a
commit ade45d9703
4 changed files with 58 additions and 12 deletions

View File

@ -31,6 +31,7 @@
#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Support/Casting.h" #include "llvm/Support/Casting.h"
#include "clang/Analysis/Support/BumpVector.h" #include "clang/Analysis/Support/BumpVector.h"
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
namespace clang { namespace clang {
@ -38,7 +39,6 @@ class CFG;
namespace ento { namespace ento {
class GRState;
class ExplodedGraph; class ExplodedGraph;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -115,7 +115,9 @@ class ExplodedNode : public llvm::FoldingSetNode {
public: public:
explicit ExplodedNode(const ProgramPoint& loc, const GRState* state) 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. /// getLocation - Returns the edge associated with the given node.
ProgramPoint getLocation() const { return Location; } ProgramPoint getLocation() const { return Location; }

View File

@ -18,6 +18,7 @@
#include "clang/StaticAnalyzer/PathSensitive/Environment.h" #include "clang/StaticAnalyzer/PathSensitive/Environment.h"
#include "clang/StaticAnalyzer/PathSensitive/Store.h" #include "clang/StaticAnalyzer/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Casting.h" #include "llvm/Support/Casting.h"
@ -78,7 +79,7 @@ private:
friend class GRStateManager; friend class GRStateManager;
GRStateManager *StateMgr; llvm::PointerIntPair<GRStateManager *, 1, bool> stateMgr;
Environment Env; // Maps a Stmt to its current SVal. Environment Env; // Maps a Stmt to its current SVal.
Store St; // Maps a location to its current value. Store St; // Maps a location to its current value.
GenericDataMap GDM; // Custom data stored by a client of this class. 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. /// This ctor is used when creating the first GRState object.
GRState(GRStateManager *mgr, const Environment& env, GRState(GRStateManager *mgr, const Environment& env,
Store st, GenericDataMap gdm) Store st, GenericDataMap gdm)
: StateMgr(mgr), : stateMgr(mgr, false),
Env(env), Env(env),
St(st), St(st),
GDM(gdm) {} GDM(gdm) {}
@ -101,14 +102,23 @@ public:
/// in FoldingSetNode will also get copied. /// in FoldingSetNode will also get copied.
GRState(const GRState& RHS) GRState(const GRState& RHS)
: llvm::FoldingSetNode(), : llvm::FoldingSetNode(),
StateMgr(RHS.StateMgr), stateMgr(RHS.stateMgr.getPointer(), false),
Env(RHS.Env), Env(RHS.Env),
St(RHS.St), St(RHS.St),
GDM(RHS.GDM) {} GDM(RHS.GDM) {}
/// getStateManager - Return the GRStateManager associated with this state. /// Return the GRStateManager associated with this state.
GRStateManager &getStateManager() const { 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. /// getEnvironment - Return the environment associated with this state.
@ -428,9 +438,16 @@ private:
/// Object that manages the data for all created SVals. /// Object that manages the data for all created SVals.
llvm::OwningPtr<SValBuilder> svalBuilder; llvm::OwningPtr<SValBuilder> svalBuilder;
/// Alloc - A BumpPtrAllocator to allocate states. /// A BumpPtrAllocator to allocate states.
llvm::BumpPtrAllocator &Alloc; 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: public:
GRStateManager(ASTContext& Ctx, GRStateManager(ASTContext& Ctx,
StoreManagerCreator CreateStoreManager, StoreManagerCreator CreateStoreManager,
@ -510,6 +527,10 @@ public:
const GRState* getPersistentState(GRState& Impl); 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. // Generic Data Map methods.
//==---------------------------------------------------------------------==// //==---------------------------------------------------------------------==//

View File

@ -574,6 +574,9 @@ void ExprEngine::processCFGElement(const CFGElement E,
} }
void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
// Recycle any unused states in the GRStateManager.
StateMgr.recycleUnusedStates();
currentStmt = S.getStmt(); currentStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
currentStmt->getLocStart(), currentStmt->getLocStart(),

View File

@ -285,6 +285,18 @@ const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) {
return getPersistentState(State); 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) { const GRState* GRStateManager::getPersistentState(GRState& State) {
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
@ -294,10 +306,18 @@ const GRState* GRStateManager::getPersistentState(GRState& State) {
if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
return I; return I;
GRState* I = (GRState*) Alloc.Allocate<GRState>(); GRState *newState = 0;
new (I) GRState(State); if (!freeStates.empty()) {
StateSet.InsertNode(I, InsertPos); newState = freeStates.back();
return I; 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 { const GRState* GRState::makeWithStore(Store store) const {