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:
parent
bcf848f70a
commit
ade45d9703
|
|
@ -31,6 +31,7 @@
|
||||||
#include "llvm/ADT/DepthFirstIterator.h"
|
#include "llvm/ADT/DepthFirstIterator.h"
|
||||||
#include "llvm/Support/Casting.h"
|
#include "llvm/Support/Casting.h"
|
||||||
#include "clang/Analysis/Support/BumpVector.h"
|
#include "clang/Analysis/Support/BumpVector.h"
|
||||||
|
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
|
|
@ -38,7 +39,6 @@ class CFG;
|
||||||
|
|
||||||
namespace ento {
|
namespace ento {
|
||||||
|
|
||||||
class GRState;
|
|
||||||
class ExplodedGraph;
|
class ExplodedGraph;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
@ -115,7 +115,9 @@ class ExplodedNode : public llvm::FoldingSetNode {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit ExplodedNode(const ProgramPoint& loc, const GRState* state)
|
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.
|
/// getLocation - Returns the edge associated with the given node.
|
||||||
ProgramPoint getLocation() const { return Location; }
|
ProgramPoint getLocation() const { return Location; }
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include "clang/StaticAnalyzer/PathSensitive/Environment.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Environment.h"
|
||||||
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
|
#include "clang/StaticAnalyzer/PathSensitive/Store.h"
|
||||||
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
|
#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
|
||||||
|
#include "llvm/ADT/PointerIntPair.h"
|
||||||
#include "llvm/ADT/FoldingSet.h"
|
#include "llvm/ADT/FoldingSet.h"
|
||||||
#include "llvm/ADT/ImmutableMap.h"
|
#include "llvm/ADT/ImmutableMap.h"
|
||||||
#include "llvm/Support/Casting.h"
|
#include "llvm/Support/Casting.h"
|
||||||
|
|
@ -78,7 +79,7 @@ private:
|
||||||
|
|
||||||
friend class GRStateManager;
|
friend class GRStateManager;
|
||||||
|
|
||||||
GRStateManager *StateMgr;
|
llvm::PointerIntPair<GRStateManager *, 1, bool> stateMgr;
|
||||||
Environment Env; // Maps a Stmt to its current SVal.
|
Environment Env; // Maps a Stmt to its current SVal.
|
||||||
Store St; // Maps a location to its current value.
|
Store St; // Maps a location to its current value.
|
||||||
GenericDataMap GDM; // Custom data stored by a client of this class.
|
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.
|
/// This ctor is used when creating the first GRState object.
|
||||||
GRState(GRStateManager *mgr, const Environment& env,
|
GRState(GRStateManager *mgr, const Environment& env,
|
||||||
Store st, GenericDataMap gdm)
|
Store st, GenericDataMap gdm)
|
||||||
: StateMgr(mgr),
|
: stateMgr(mgr, false),
|
||||||
Env(env),
|
Env(env),
|
||||||
St(st),
|
St(st),
|
||||||
GDM(gdm) {}
|
GDM(gdm) {}
|
||||||
|
|
@ -101,14 +102,23 @@ public:
|
||||||
/// in FoldingSetNode will also get copied.
|
/// in FoldingSetNode will also get copied.
|
||||||
GRState(const GRState& RHS)
|
GRState(const GRState& RHS)
|
||||||
: llvm::FoldingSetNode(),
|
: llvm::FoldingSetNode(),
|
||||||
StateMgr(RHS.StateMgr),
|
stateMgr(RHS.stateMgr.getPointer(), false),
|
||||||
Env(RHS.Env),
|
Env(RHS.Env),
|
||||||
St(RHS.St),
|
St(RHS.St),
|
||||||
GDM(RHS.GDM) {}
|
GDM(RHS.GDM) {}
|
||||||
|
|
||||||
/// getStateManager - Return the GRStateManager associated with this state.
|
/// Return the GRStateManager associated with this state.
|
||||||
GRStateManager &getStateManager() const {
|
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.
|
/// getEnvironment - Return the environment associated with this state.
|
||||||
|
|
@ -428,9 +438,16 @@ private:
|
||||||
/// Object that manages the data for all created SVals.
|
/// Object that manages the data for all created SVals.
|
||||||
llvm::OwningPtr<SValBuilder> svalBuilder;
|
llvm::OwningPtr<SValBuilder> svalBuilder;
|
||||||
|
|
||||||
/// Alloc - A BumpPtrAllocator to allocate states.
|
/// A BumpPtrAllocator to allocate states.
|
||||||
llvm::BumpPtrAllocator &Alloc;
|
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:
|
public:
|
||||||
GRStateManager(ASTContext& Ctx,
|
GRStateManager(ASTContext& Ctx,
|
||||||
StoreManagerCreator CreateStoreManager,
|
StoreManagerCreator CreateStoreManager,
|
||||||
|
|
@ -509,6 +526,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
const GRState* getPersistentState(GRState& Impl);
|
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.
|
// Generic Data Map methods.
|
||||||
|
|
|
||||||
|
|
@ -574,6 +574,9 @@ void ExprEngine::processCFGElement(const CFGElement E,
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
|
void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
|
||||||
|
// Recycle any unused states in the GRStateManager.
|
||||||
|
StateMgr.recycleUnusedStates();
|
||||||
|
|
||||||
currentStmt = S.getStmt();
|
currentStmt = S.getStmt();
|
||||||
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
|
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
|
||||||
currentStmt->getLocStart(),
|
currentStmt->getLocStart(),
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,18 @@ const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) {
|
||||||
return getPersistentState(State);
|
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) {
|
const GRState* GRStateManager::getPersistentState(GRState& State) {
|
||||||
|
|
||||||
llvm::FoldingSetNodeID ID;
|
llvm::FoldingSetNodeID ID;
|
||||||
|
|
@ -294,10 +306,18 @@ const GRState* GRStateManager::getPersistentState(GRState& State) {
|
||||||
if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
|
if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
|
||||||
return I;
|
return I;
|
||||||
|
|
||||||
GRState* I = (GRState*) Alloc.Allocate<GRState>();
|
GRState *newState = 0;
|
||||||
new (I) GRState(State);
|
if (!freeStates.empty()) {
|
||||||
StateSet.InsertNode(I, InsertPos);
|
newState = freeStates.back();
|
||||||
return I;
|
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 {
|
const GRState* GRState::makeWithStore(Store store) const {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue