From: Argyrios Kyrtzidis Date: Tue, 31 Jan 2012 02:14:24 +0000 (+0000) Subject: Revert r149311 which failed to compile. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b9b0f6fb6e113b5e6be3ed9754c4bf01186a17bf;p=clang Revert r149311 which failed to compile. Original log: 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@149336 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index 89fe7ddf75..bed1bffd36 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -119,11 +119,14 @@ public: explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state, bool IsSink) : Location(loc), State(state) { + const_cast(State)->incrementReferenceCount(); if (IsSink) Succs.setFlag(); } - ~ExplodedNode() {} + ~ExplodedNode() { + const_cast(State)->decrementReferenceCount(); + } /// getLocation - Returns the edge associated with the given node. ProgramPoint getLocation() const { return Location; } @@ -153,7 +156,7 @@ public: ProgramStateRef state, bool IsSink) { ID.Add(Loc); - ID.AddPointer(state.getPtr()); + ID.AddPointer(state); ID.AddBoolean(IsSink); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index f19520984e..a3e1830be3 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -93,6 +93,7 @@ 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); @@ -106,6 +107,9 @@ 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; } @@ -123,7 +127,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, const ProgramState *V) { + static void Profile(llvm::FoldingSetNodeID& ID, ProgramStateRef V) { V->Env.Profile(ID); ID.AddPointer(V->store); V->GDM.Profile(ID); @@ -372,8 +376,14 @@ public: void dumpTaint() const; private: - friend void ProgramStateRetain(const ProgramState *state); - friend void ProgramStateRelease(const ProgramState *state); + /// 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; + } ProgramStateRef invalidateRegionsImpl(ArrayRef Regions, @@ -382,13 +392,45 @@ 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. */ @@ -411,6 +453,10 @@ 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; @@ -517,6 +563,10 @@ 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 5839ad9382..c588908804 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h @@ -10,31 +10,11 @@ #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; - 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; + typedef const ProgramState* ProgramStateRef; } } diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/Checker.cpp index 07e0aac2d4..f793c7fe29 100644 --- a/lib/StaticAnalyzer/Core/Checker.cpp +++ b/lib/StaticAnalyzer/Core/Checker.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#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 5087ae1d33..2d047d2c46 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -238,8 +238,13 @@ 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(), @@ -1851,7 +1856,7 @@ struct DOTGraphTraits : } ProgramStateRef state = N->getState(); - Out << "\\|StateID: " << (void*) state.getPtr() + Out << "\\|StateID: " << (void*) state << " NodeID: " << (void*) N << "\\|"; state->printDOT(Out); diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 459bf83ce5..b8b9ad94df 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -25,26 +25,6 @@ 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), @@ -348,10 +328,23 @@ 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); } @@ -375,11 +368,12 @@ 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); }