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/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; }

View 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.

View 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(),

View 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 {