diff options
-rw-r--r-- | include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h | 6 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/PathSensitive/GRState.h | 33 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/ExprEngine.cpp | 3 | ||||
-rw-r--r-- | lib/StaticAnalyzer/GRState.cpp | 28 |
4 files changed, 58 insertions, 12 deletions
diff --git a/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h index 853d3c5ec7..0d6044b5d2 100644 --- a/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h @@ -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; } diff --git a/include/clang/StaticAnalyzer/PathSensitive/GRState.h b/include/clang/StaticAnalyzer/PathSensitive/GRState.h index 48cc7a7fd5..5a87cb4fb7 100644 --- a/include/clang/StaticAnalyzer/PathSensitive/GRState.h +++ b/include/clang/StaticAnalyzer/PathSensitive/GRState.h @@ -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. diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 53931dc607..f311bea877 100644 --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -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(), diff --git a/lib/StaticAnalyzer/GRState.cpp b/lib/StaticAnalyzer/GRState.cpp index 60832e8f79..18995b2ce7 100644 --- a/lib/StaticAnalyzer/GRState.cpp +++ b/lib/StaticAnalyzer/GRState.cpp @@ -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 { |