Convert ProgramStateRef to a smart pointer for managing the reference counts of ProgramStates. This leads to a slight memory

improvement, and a simplification of the logic for managing ProgramState objects.

llvm-svn: 149311
This commit is contained in:
Ted Kremenek 2012-01-31 00:57:20 +00:00
parent 13a4487f4d
commit b1ca33fde5
6 changed files with 51 additions and 82 deletions

View File

@ -119,14 +119,11 @@ public:
explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
bool IsSink)
: Location(loc), State(state) {
const_cast<ProgramState*>(State)->incrementReferenceCount();
if (IsSink)
Succs.setFlag();
}
~ExplodedNode() {
const_cast<ProgramState*>(State)->decrementReferenceCount();
}
~ExplodedNode() {}
/// getLocation - Returns the edge associated with the given node.
ProgramPoint getLocation() const { return Location; }
@ -156,7 +153,7 @@ public:
ProgramStateRef state,
bool IsSink) {
ID.Add(Loc);
ID.AddPointer(state);
ID.AddPointer(state.getPtr());
ID.AddBoolean(IsSink);
}

View File

@ -93,7 +93,6 @@ private:
void setStore(const StoreRef &storeRef);
public:
/// This ctor is used when creating the first ProgramState object.
ProgramState(ProgramStateManager *mgr, const Environment& env,
StoreRef st, GenericDataMap gdm);
@ -107,9 +106,6 @@ public:
/// Return the ProgramStateManager associated with this state.
ProgramStateManager &getStateManager() const { return *stateMgr; }
/// Return true if this state is referenced by a persistent ExplodedNode.
bool referencedByExplodedNode() const { return refCount > 0; }
/// getEnvironment - Return the environment associated with this state.
/// The environment is the mapping from expressions to values.
const Environment& getEnvironment() const { return Env; }
@ -127,7 +123,7 @@ public:
/// Profile - Profile the contents of a ProgramState object for use in a
/// FoldingSet. Two ProgramState objects are considered equal if they
/// have the same Environment, Store, and GenericDataMap.
static void Profile(llvm::FoldingSetNodeID& ID, ProgramStateRef V) {
static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) {
V->Env.Profile(ID);
ID.AddPointer(V->store);
V->GDM.Profile(ID);
@ -376,14 +372,8 @@ public:
void dumpTaint() const;
private:
/// Increments the number of times this state is referenced by ExplodeNodes.
void incrementReferenceCount() { ++refCount; }
/// Decrement the number of times this state is referenced by ExplodeNodes.
void decrementReferenceCount() {
assert(refCount > 0);
--refCount;
}
friend void ProgramStateRetain(const ProgramState *state);
friend void ProgramStateRelease(const ProgramState *state);
ProgramStateRef
invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
@ -392,45 +382,13 @@ private:
const CallOrObjCMessage *Call) const;
};
class ProgramStateSet {
typedef llvm::SmallPtrSet<ProgramStateRef,5> ImplTy;
ImplTy Impl;
public:
ProgramStateSet() {}
inline void Add(ProgramStateRef St) {
Impl.insert(St);
}
typedef ImplTy::const_iterator iterator;
inline unsigned size() const { return Impl.size(); }
inline bool empty() const { return Impl.empty(); }
inline iterator begin() const { return Impl.begin(); }
inline iterator end() const { return Impl.end(); }
class AutoPopulate {
ProgramStateSet &S;
unsigned StartSize;
ProgramStateRef St;
public:
AutoPopulate(ProgramStateSet &s, ProgramStateRef st)
: S(s), StartSize(S.size()), St(st) {}
~AutoPopulate() {
if (StartSize == S.size())
S.Add(St);
}
};
};
//===----------------------------------------------------------------------===//
// ProgramStateManager - Factory object for ProgramStates.
//===----------------------------------------------------------------------===//
class ProgramStateManager {
friend class ProgramState;
friend void ProgramStateRelease(const ProgramState *state);
private:
/// Eng - The SubEngine that owns this state manager.
SubEngine *Eng; /* Can be null. */
@ -453,10 +411,6 @@ private:
/// A BumpPtrAllocator to allocate states.
llvm::BumpPtrAllocator &Alloc;
/// A vector of recently allocated ProgramStates that can potentially be
/// reused.
std::vector<ProgramState *> recentlyAllocatedStates;
/// A vector of ProgramStates that we can reuse.
std::vector<ProgramState *> freeStates;
@ -563,10 +517,6 @@ public:
return S1->store == S2->store;
}
/// Periodically called by ExprEngine to recycle ProgramStates that were
/// created but never used for creating an ExplodedNode.
void recycleUnusedStates();
//==---------------------------------------------------------------------==//
// Generic Data Map methods.
//==---------------------------------------------------------------------==//

View File

@ -10,11 +10,31 @@
#ifndef LLVM_CLANG_PROGRAMSTATE_FWD_H
#define LLVM_CLANG_PROGRAMSTATE_FWD_H
#include "llvm/ADT/IntrusiveRefCntPtr.h"
namespace clang {
namespace ento {
class ProgramState;
class ProgramStateManager;
typedef const ProgramState* ProgramStateRef;
void ProgramStateRetain(const ProgramState *state);
void ProgramStateRelease(const ProgramState *state);
}
}
namespace llvm {
template <> struct IntrusiveRefCntPtrInfo<const clang::ento::ProgramState> {
static void retain(const clang::ento::ProgramState *state) {
clang::ento::ProgramStateRetain(state);
}
static void release(const clang::ento::ProgramState *state) {
clang::ento::ProgramStateRelease(state);
}
};
}
namespace clang {
namespace ento {
typedef llvm::IntrusiveRefCntPtr<const ProgramState> ProgramStateRef;
}
}

View File

@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
using namespace clang;

View File

@ -238,13 +238,8 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
void ExprEngine::ProcessStmt(const CFGStmt S,
ExplodedNode *Pred) {
// TODO: Use RAII to remove the unnecessary, tagged nodes.
//RegisterCreatedNodes registerCreatedNodes(getGraph());
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
// Recycle any unused states in the ProgramStateManager.
StateMgr.recycleUnusedStates();
currentStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
@ -1856,7 +1851,7 @@ struct DOTGraphTraits<ExplodedNode*> :
}
ProgramStateRef state = N->getState();
Out << "\\|StateID: " << (void*) state
Out << "\\|StateID: " << (void*) state.getPtr()
<< " NodeID: " << (void*) N << "\\|";
state->printDOT(Out);

View File

@ -25,6 +25,26 @@ using namespace ento;
// FIXME: Move this elsewhere.
ConstraintManager::~ConstraintManager() {}
namespace clang { namespace ento {
/// Increments the number of times this state is referenced.
void ProgramStateRetain(const ProgramState *state) {
++const_cast<ProgramState*>(state)->refCount;
}
/// Decrement the number of times this state is referenced.
void ProgramStateRelease(const ProgramState *state) {
assert(state->refCount > 0);
ProgramState *s = const_cast<ProgramState*>(state);
if (--s->refCount == 0) {
ProgramStateManager &Mgr = s->getStateManager();
Mgr.StateSet.RemoveNode(s);
s->~ProgramState();
Mgr.freeStates.push_back(s);
}
}
}}
ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env,
StoreRef st, GenericDataMap gdm)
: stateMgr(mgr),
@ -328,23 +348,10 @@ ProgramStateRef ProgramStateManager::getInitialState(const LocationContext *Init
return getPersistentState(State);
}
void ProgramStateManager::recycleUnusedStates() {
for (std::vector<ProgramState*>::iterator i = recentlyAllocatedStates.begin(),
e = recentlyAllocatedStates.end(); i != e; ++i) {
ProgramState *state = *i;
if (state->referencedByExplodedNode())
continue;
StateSet.RemoveNode(state);
freeStates.push_back(state);
state->~ProgramState();
}
recentlyAllocatedStates.clear();
}
ProgramStateRef ProgramStateManager::getPersistentStateWithGDM(
ProgramStateRef FromState,
ProgramStateRef GDMState) {
ProgramState NewState = *FromState;
ProgramState NewState(*FromState);
NewState.GDM = GDMState->GDM;
return getPersistentState(NewState);
}
@ -368,12 +375,11 @@ ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {
}
new (newState) ProgramState(State);
StateSet.InsertNode(newState, InsertPos);
recentlyAllocatedStates.push_back(newState);
return newState;
}
ProgramStateRef ProgramState::makeWithStore(const StoreRef &store) const {
ProgramState NewSt = *this;
ProgramState NewSt(*this);
NewSt.setStore(store);
return getStateManager().getPersistentState(NewSt);
}