const llvm::APSInt& V) const = 0;
virtual const GRState* RemoveDeadBindings(const GRState* St,
- StoreManager::LiveSymbolsTy& LSymbols,
- StoreManager::DeadSymbolsTy& DSymbols) = 0;
+ SymbolReaper& SymReaper) = 0;
virtual void print(const GRState* St, std::ostream& Out,
const char* nl, const char *sep) = 0;
Environment BindExpr(const Environment& Env, Stmt* E, SVal V,
bool isBlkExpr, bool Invalidate);
- Environment RemoveDeadBindings(Environment Env, Stmt* Loc,
- const LiveVariables& Liveness,
- llvm::SmallVectorImpl<const MemRegion*>& DRoots,
- StoreManager::LiveSymbolsTy& LSymbols);
+ Environment
+ RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& DRoots);
+
};
} // end clang namespace
/// Liveness - live-variables information the ValueDecl* and block-level
/// Expr* in the CFG. Used to prune out dead state.
LiveVariables& Liveness;
-
- /// DeadSymbols - A scratch set used to record the set of symbols that
- /// were just marked dead by a call to GRStateManager::RemoveDeadBindings.
- GRStateManager::DeadSymbolsTy DeadSymbols;
-
+
/// Builder - The current GRStmtNodeBuilder which is used when building the
/// nodes for a given statement.
StmtNodeBuilder* Builder;
MemRegionManager& getRegionManager() { return StoreMgr->getRegionManager(); }
StoreManager& getStoreManager() { return *StoreMgr; }
- typedef StoreManager::DeadSymbolsTy DeadSymbolsTy;
-
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal IVal) {
// Store manager should return a persistent state.
return StoreMgr->BindDecl(St, VD, IVal);
}
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
- const LiveVariables& Liveness,
- DeadSymbolsTy& DeadSyms);
+ SymbolReaper& SymReaper);
const GRState* RemoveSubExprBindings(const GRState* St) {
GRState NewSt = *St;
GRExprEngine& Engine,
GRStmtNodeBuilder<GRState>& Builder,
ExplodedNode<GRState>* Pred,
- Stmt* S,
- const GRState* St,
- const GRStateManager::DeadSymbolsTy& Dead) {}
+ Stmt* S, const GRState* state,
+ SymbolReaper& SymReaper) {}
// Return statements.
virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
class GRState;
class GRStateManager;
-class LiveVariables;
class Stmt;
class Expr;
class ObjCIvarDecl;
class StoreManager {
-public:
- typedef llvm::SmallSet<SymbolRef, 20> LiveSymbolsTy;
- typedef llvm::DenseSet<SymbolRef> DeadSymbolsTy;
-
protected:
/// MRMgr - Manages region objects associated with this StoreManager.
MemRegionManager MRMgr;
/// lazily computed.
/// \return The value bound to the location \c loc.
virtual SVal Retrieve(const GRState* state, Loc loc,
- QualType T = QualType()) = 0;
-
-// /// Retrieves the value bound to the specified region.
-// SVal GetRegionSVal(const GRState* state, const MemRegion* R) {
-// return Retrieve(state, loc::MemRegionVal(R));
-// }
+ QualType T = QualType()) = 0;
/// Return a state with the specified value bound to the given location.
/// \param[in] state The analysis state.
virtual const MemRegion* getSelfRegion(Store store) = 0;
virtual Store
- RemoveDeadBindings(const GRState* state, Stmt* Loc, const LiveVariables& Live,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
- LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) = 0;
+ RemoveDeadBindings(const GRState* state, Stmt* Loc, SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
virtual const GRState* BindDecl(const GRState* St, const VarDecl* VD,
SVal InitVal) = 0;
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/DenseMap.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/ImmutableSet.h"
namespace llvm {
class raw_ostream;
return getSymbolData(ID).getType(*this);
}
};
+
+class SymbolReaper {
+ typedef llvm::ImmutableSet<SymbolRef> SetTy;
+ typedef SetTy::Factory FactoryTy;
+
+ FactoryTy F;
+ SetTy TheLiving;
+ SetTy TheDead;
+ LiveVariables& Liveness;
+ SymbolManager& SymMgr;
+
+public:
+ SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr)
+ : TheLiving(F.GetEmptySet()), TheDead(F.GetEmptySet()),
+ Liveness(liveness), SymMgr(symmgr) {}
+
+ bool isLive(SymbolRef sym);
+ bool isLive(const Stmt* Loc, const Stmt* ExprVal) const {
+ return Liveness.isLive(Loc, ExprVal);
+ }
+
+ bool isLive(const Stmt* Loc, const VarDecl* VD) const {
+ return Liveness.isLive(Loc, VD);
+ }
+
+ void markLive(SymbolRef sym);
+ bool maybeDead(SymbolRef sym);
+
+ typedef SetTy::iterator dead_iterator;
+ dead_iterator dead_begin() const { return TheDead.begin(); }
+ dead_iterator dead_end() const { return TheDead.end(); }
+
+ bool hasDeadSymbols() const {
+ return !TheDead.isEmpty();
+ }
+};
+
} // end clang namespace
#endif
bool isNotEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V) const;
bool isEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V) const;
- const GRState* RemoveDeadBindings(const GRState* St,
- StoreManager::LiveSymbolsTy& LSymbols,
- StoreManager::DeadSymbolsTy& DSymbols);
+ const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper);
+
void print(const GRState* St, std::ostream& Out,
const char* nl, const char *sep);
/// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols.
-const GRState* BasicConstraintManager::RemoveDeadBindings(const GRState* St,
- StoreManager::LiveSymbolsTy& LSymbols,
- StoreManager::DeadSymbolsTy& DSymbols) {
+const GRState*
+BasicConstraintManager::RemoveDeadBindings(const GRState* St,
+ SymbolReaper& SymReaper) {
+
GRStateRef state(St, StateMgr);
ConstEqTy CE = state.get<ConstEqTy>();
ConstEqTy::Factory& CEFactory = state.get_context<ConstEqTy>();
for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
- SymbolRef sym = I.getKey();
- if (!LSymbols.count(sym)) {
- DSymbols.insert(sym);
- CE = CEFactory.Remove(CE, sym);
- }
+ SymbolRef sym = I.getKey();
+ if (SymReaper.maybeDead(sym)) CE = CEFactory.Remove(CE, sym);
}
state = state.set<ConstEqTy>(CE);
for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) {
SymbolRef sym = I.getKey();
- if (!LSymbols.count(sym)) {
- DSymbols.insert(sym);
- CNE = CNEFactory.Remove(CNE, sym);
- }
+ if (SymReaper.maybeDead(sym)) CNE = CNEFactory.Remove(CNE, sym);
}
return state.set<ConstNotEqTy>(CNE);
/// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
/// It returns a new Store with these values removed, and populates LSymbols
/// and DSymbols with the known set of live and dead symbols respectively.
- Store RemoveDeadBindings(const GRState* state, Stmt* Loc,
- const LiveVariables& Live,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
- LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols);
+ Store
+ RemoveDeadBindings(const GRState* state, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
void iterBindings(Store store, BindingsHandler& f);
Store
BasicStoreManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
- const LiveVariables& Liveness,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
- LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) {
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
Store store = state->getStore();
VarBindingsTy B = GetVarBindings(store);
// Iterate over the variable bindings.
for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I)
- if (Liveness.isLive(Loc, I.getKey())) {
+ if (SymReaper.isLive(Loc, I.getKey())) {
RegionRoots.push_back(MRMgr.getVarRegion(I.getKey()));
SVal X = I.getData();
for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
- LSymbols.insert(*SI);
+ SymReaper.markLive(*SI);
}
// Scan for live variables and live symbols.
while (MR) {
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) {
- LSymbols.insert(SymR->getSymbol());
+ SymReaper.markLive(SymR->getSymbol());
break;
}
else if (const VarRegion* R = dyn_cast<VarRegion>(MR)) {
SVal X = Retrieve(state, loc::MemRegionVal(R));
// FIXME: We need to handle symbols nested in region definitions.
- for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
- LSymbols.insert(*SI);
+ for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI)
+ SymReaper.markLive(*SI);
if (!isa<loc::MemRegionVal>(X))
break;
SVal X = I.getData();
for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
- if (!LSymbols.count(*SI)) DSymbols.insert(*SI);
+ SymReaper.maybeDead(*SI);
}
}
GRExprEngine& Engine,
GRStmtNodeBuilder<GRState>& Builder,
ExplodedNode<GRState>* Pred,
- Stmt* S,
- const GRState* St,
- const GRStateManager::DeadSymbolsTy& Dead);
+ Stmt* S, const GRState* state,
+ SymbolReaper& SymReaper);
+
// Return statements.
virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
ExplodedNode<GRState>* Pred,
Stmt* S,
const GRState* St,
- const GRStateManager::DeadSymbolsTy& Dead) {
+ SymbolReaper& SymReaper) {
// FIXME: a lot of copy-and-paste from EvalEndPath. Refactor.
RefBindings B = St->get<RefBindings>();
llvm::SmallVector<std::pair<SymbolRef,bool>, 10> Leaked;
- for (GRStateManager::DeadSymbolsTy::const_iterator
- I=Dead.begin(), E=Dead.end(); I!=E; ++I) {
+ for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+ E = SymReaper.dead_end(); I != E; ++I) {
const RefVal* T = B.lookup(*I);
-
- if (!T)
- continue;
+ if (!T) continue;
bool hasLeak = false;
Environment
EnvironmentManager::RemoveDeadBindings(Environment Env, Stmt* Loc,
- const LiveVariables& Liveness,
- llvm::SmallVectorImpl<const MemRegion*>& DRoots,
- StoreManager::LiveSymbolsTy& LSymbols) {
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& DRoots) {
// Drop bindings for subexpressions.
Env = RemoveSubExprBindings(Env);
I != E; ++I) {
Stmt* BlkExpr = I.getKey();
- if (Liveness.isLive(Loc, BlkExpr)) {
+ if (SymReaper.isLive(Loc, BlkExpr)) {
SVal X = I.getData();
// If the block expr's value is a memory region, then mark that region.
if (isa<loc::MemRegionVal>(X))
DRoots.push_back(cast<loc::MemRegionVal>(X).getRegion());
-
// Mark all symbols in the block expr's value.
for (SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
- SI != SE; ++SI) {
- LSymbols.insert(*SI);
- }
+ SI != SE; ++SI)
+ SymReaper.markLive(*SI);
+
} else {
// The block expr is dead.
SVal X = I.getData();
if (BatchAuditor)
Builder->setAuditor(BatchAuditor.get());
+
// Create the cleaned state.
- if (PurgeDead)
- CleanedState = StateMgr.RemoveDeadBindings(EntryNode->getState(),
- CurrentStmt,
- Liveness, DeadSymbols);
- else
- CleanedState = EntryNode->getState();
-
+ SymbolReaper SymReaper(Liveness, SymMgr);
+ CleanedState = PurgeDead ? StateMgr.RemoveDeadBindings(EntryNode->getState(),
+ CurrentStmt, SymReaper)
+ : EntryNode->getState();
+
// Process any special transfer function for dead symbols.
NodeSet Tmp;
- if (DeadSymbols.empty())
+ if (!SymReaper.hasDeadSymbols())
Tmp.Add(EntryNode);
else {
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Builder->PurgingDeadSymbols = true;
getTF().EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S,
- CleanedState, DeadSymbols);
+ CleanedState, SymReaper);
if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
Tmp.Add(EntryNode);
const GRState*
GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
- const LiveVariables& Liveness,
- DeadSymbolsTy& DSymbols) {
-
+ SymbolReaper& SymReaper) {
+
// This code essentially performs a "mark-and-sweep" of the VariableBindings.
// The roots are any Block-level exprs and Decls that our liveness algorithm
// tells us are live. We then see what Decls they may reference, and keep
// frequency of which this method is called should be experimented with
// for optimum performance.
llvm::SmallVector<const MemRegion*, 10> RegionRoots;
- StoreManager::LiveSymbolsTy LSymbols;
GRState NewState = *state;
- NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, Liveness,
- RegionRoots, LSymbols);
+ NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, SymReaper,
+ RegionRoots);
// Clean up the store.
- DSymbols.clear();
- NewState.St = StoreMgr->RemoveDeadBindings(&NewState, Loc, Liveness,
- RegionRoots, LSymbols, DSymbols);
+ NewState.St = StoreMgr->RemoveDeadBindings(&NewState, Loc, SymReaper,
+ RegionRoots);
return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState),
- LSymbols, DSymbols);
+ SymReaper);
}
const GRState* GRStateManager::Unbind(const GRState* St, Loc LV) {
/// It returns a new Store with these values removed, and populates LSymbols
// and DSymbols with the known set of live and dead symbols respectively.
Store RemoveDeadBindings(const GRState* state, Stmt* Loc,
- const LiveVariables& Live,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
- LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols);
-
- void UpdateLiveSymbols(SVal X, LiveSymbolsTy& LSymbols);
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal InitVal);
}
-void RegionStoreManager::UpdateLiveSymbols(SVal X, LiveSymbolsTy& LSymbols) {
- for (SVal::symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI)
- LSymbols.insert(*SI);
+static void UpdateLiveSymbols(SVal X, SymbolReaper& SymReaper) {
+ for (SVal::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();SI!=SE;++SI)
+ SymReaper.markLive(*SI);
}
Store RegionStoreManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
- const LiveVariables& Live,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
- LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) {
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
Store store = state->getStore();
RegionBindingsTy B = GetRegionBindings(store);
for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion* R = I.getKey();
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
- if (Live.isLive(Loc, VR->getDecl()))
+ if (SymReaper.isLive(Loc, VR->getDecl()))
RegionRoots.push_back(VR); // This is a live "root".
}
else {
// to also mark SuperR as a root (as it may not have a value directly
// bound to it in the store).
if (const VarRegion* VR = dyn_cast<VarRegion>(SuperR)) {
- if (Live.isLive(Loc, VR->getDecl()))
+ if (SymReaper.isLive(Loc, VR->getDecl()))
RegionRoots.push_back(VR); // This is a live "root".
}
}
// Mark the symbol for any live SymbolicRegion as "live". This means we
// should continue to track that symbol.
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
- LSymbols.insert(SymR->getSymbol());
+ SymReaper.markLive(SymR->getSymbol());
// Get the data binding for R (if any).
RegionBindingsTy::data_type* Xptr = B.lookup(R);
if (Xptr) {
SVal X = *Xptr;
- UpdateLiveSymbols(X, LSymbols); // Update the set of live symbols.
+ UpdateLiveSymbols(X, SymReaper); // Update the set of live symbols.
// If X is a region, then add it the RegionRoots.
if (loc::MemRegionVal* RegionX = dyn_cast<loc::MemRegionVal>(&X))
store = Remove(store, Loc::MakeVal(R));
// Mark all non-live symbols that this region references as dead.
- if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R)) {
- SymbolRef Sym = SymR->getSymbol();
- if (!LSymbols.count(Sym)) DSymbols.insert(Sym);
- }
+ if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
+ SymReaper.maybeDead(SymR->getSymbol());
SVal X = I.getData();
SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
- for (; SI != SE; ++SI) { if (!LSymbols.count(*SI)) DSymbols.insert(*SI); }
+ for (; SI != SE; ++SI) SymReaper.maybeDead(*SI);
}
return store;
}
SymbolManager::~SymbolManager() {}
+
+void SymbolReaper::markLive(SymbolRef sym) {
+ TheLiving = F.Add(TheLiving, sym);
+ TheDead = F.Remove(TheDead, sym);
+}
+
+bool SymbolReaper::maybeDead(SymbolRef sym) {
+ if (isLive(sym))
+ return false;
+
+ TheDead = F.Add(TheDead, sym);
+ return true;
+}
+
+bool SymbolReaper::isLive(SymbolRef sym) {
+ return TheLiving.contains(sym);
+}
+