From 72e93068c9f2a2f05f5932cdd917c0d2961f11d9 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 31 Jan 2012 00:57:20 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149311 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Core/PathSensitive/ExplodedGraph.h | 7 +-- .../Core/PathSensitive/ProgramState.h | 58 ++----------------- .../Core/PathSensitive/ProgramState_Fwd.h | 22 ++++++- lib/StaticAnalyzer/Core/Checker.cpp | 1 + lib/StaticAnalyzer/Core/ExprEngine.cpp | 7 +-- lib/StaticAnalyzer/Core/ProgramState.cpp | 38 +++++++----- 6 files changed, 51 insertions(+), 82 deletions(-) diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index 916babc98b..623fce1472 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -119,14 +119,11 @@ public: explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state, bool IsSink) : Location(loc), State(state) { - const_cast(State)->incrementReferenceCount(); if (IsSink) Succs.setFlag(); } - ~ExplodedNode() { - const_cast(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); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index a3e1830be3..f19520984e 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -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 Regions, @@ -392,45 +382,13 @@ private: const CallOrObjCMessage *Call) const; }; -class ProgramStateSet { - typedef llvm::SmallPtrSet 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 recentlyAllocatedStates; /// A vector of ProgramStates that we can reuse. std::vector 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. //==---------------------------------------------------------------------==// diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h index c588908804..5839ad9382 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h @@ -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 { + 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 ProgramStateRef; } } diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/Checker.cpp index f793c7fe29..07e0aac2d4 100644 --- a/lib/StaticAnalyzer/Core/Checker.cpp +++ b/lib/StaticAnalyzer/Core/Checker.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/Checker.h" using namespace clang; diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 2d047d2c46..5087ae1d33 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -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 : } ProgramStateRef state = N->getState(); - Out << "\\|StateID: " << (void*) state + Out << "\\|StateID: " << (void*) state.getPtr() << " NodeID: " << (void*) N << "\\|"; state->printDOT(Out); diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index b8b9ad94df..459bf83ce5 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -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(state)->refCount; +} + +/// Decrement the number of times this state is referenced. +void ProgramStateRelease(const ProgramState *state) { + assert(state->refCount > 0); + ProgramState *s = const_cast(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::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); } -- 2.40.0