summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Core/CoreEngine.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp112
5 files changed, 122 insertions, 4 deletions
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index e90cf8ddd2f..6fc73738223 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -878,6 +878,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
+ Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph);
Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call);
Opts.IdempotentOps = Args.hasArg(OPT_analysis_WarnIdempotentOps);
Opts.ObjCSelfInitCheck = Args.hasArg(OPT_analysis_WarnObjCSelfInit);
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp
index a20f995639d..2b210a88047 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp
@@ -194,7 +194,8 @@ public:
Opts.PurgeDead, Opts.EagerlyAssume,
Opts.TrimGraph, Opts.InlineCall,
Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
- Opts.CFGAddInitializers));
+ Opts.CFGAddInitializers,
+ Opts.EagerlyTrimEGraph));
}
virtual void HandleTranslationUnit(ASTContext &C);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index cadbca6b3d0..e2ad17e590b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -338,6 +338,11 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
// FIXME: Eventually remove the TF object entirely.
TF->RegisterChecks(*this);
TF->RegisterPrinters(getStateManager().Printers);
+
+ if (mgr.shouldEagerlyTrimExplodedGraph()) {
+ // Enable eager node reclaimation when constructing the ExplodedGraph.
+ G.enableNodeReclamation();
+ }
}
ExprEngine::~ExprEngine() {
@@ -573,6 +578,8 @@ void ExprEngine::processCFGElement(const CFGElement E,
}
void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
+ // Reclaim any unnecessary nodes in the ExplodedGraph.
+ G.reclaimRecentlyAllocatedNodes();
// Recycle any unused states in the GRStateManager.
StateMgr.recycleUnusedStates();
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 13cca35aacf..69aa664f9c1 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -783,7 +783,8 @@ void CallEnterNodeBuilder::generateNode(const GRState *state) {
OldMgr.shouldInlineCall(),
OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(),
OldMgr.getAnalysisContextManager().getAddImplicitDtors(),
- OldMgr.getAnalysisContextManager().getAddInitializers());
+ OldMgr.getAnalysisContextManager().getAddInitializers(),
+ OldMgr.shouldEagerlyTrimExplodedGraph());
llvm::OwningPtr<TransferFuncs> TF(MakeCFRefCountTF(AMgr.getASTContext(),
/* GCEnabled */ false,
AMgr.getLangOptions()));
diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index 4c4612fab5e..9e8566056f4 100644
--- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -41,6 +41,94 @@ void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
}
//===----------------------------------------------------------------------===//
+// Cleanup.
+//===----------------------------------------------------------------------===//
+
+typedef std::vector<ExplodedNode*> NodeList;
+static inline NodeList*& getNodeList(void *&p) { return (NodeList*&) p; }
+
+ExplodedGraph::~ExplodedGraph() {
+ if (reclaimNodes) {
+ delete getNodeList(recentlyAllocatedNodes);
+ delete getNodeList(freeNodes);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Node reclamation.
+//===----------------------------------------------------------------------===//
+
+void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
+ if (!recentlyAllocatedNodes)
+ return;
+ NodeList &nl = *getNodeList(recentlyAllocatedNodes);
+
+ // Reclaimn all nodes that match *all* the following criteria:
+ //
+ // (1) 1 predecessor (that has one successor)
+ // (2) 1 successor (that has one predecessor)
+ // (3) The ProgramPoint is for a PostStmt.
+ // (4) There is no 'tag' for the ProgramPoint.
+ // (5) The 'store' is the same as the predecessor.
+ // (6) The 'GDM' is the same as the predecessor.
+ // (7) The LocationContext is the same as the predecessor.
+ // (8) The PostStmt is for a non-CFGElement expression.
+
+ for (NodeList::iterator i = nl.begin(), e = nl.end() ; i != e; ++i) {
+ ExplodedNode *node = *i;
+
+ // Conditions 1 and 2.
+ if (node->pred_size() != 1 || node->succ_size() != 1)
+ continue;
+
+ ExplodedNode *pred = *(node->pred_begin());
+ if (pred->succ_size() != 1)
+ continue;
+
+ ExplodedNode *succ = *(node->succ_begin());
+ if (succ->pred_size() != 1)
+ continue;
+
+ // Condition 3.
+ ProgramPoint progPoint = node->getLocation();
+ if (!isa<PostStmt>(progPoint))
+ continue;
+
+ // Condition 4.
+ PostStmt ps = cast<PostStmt>(progPoint);
+ if (ps.getTag() || isa<PostStmtCustom>(ps))
+ continue;
+
+ if (isa<BinaryOperator>(ps.getStmt()))
+ continue;
+
+ // Conditions 5, 6, and 7.
+ const GRState *state = node->getState();
+ const GRState *pred_state = pred->getState();
+ if (state->St != pred_state->St || state->GDM != pred_state->GDM ||
+ progPoint.getLocationContext() != pred->getLocationContext())
+ continue;
+
+ // Condition 8.
+ if (node->getCFG().isBlkExpr(ps.getStmt()))
+ continue;
+
+ // If we reach here, we can remove the node. This means:
+ // (a) changing the predecessors successor to the successor of this node
+ // (b) changing the successors predecessor to the predecessor of this node
+ // (c) Putting 'node' onto freeNodes.
+ pred->replaceSuccessor(succ);
+ succ->replacePredecessor(pred);
+ if (!freeNodes)
+ freeNodes = new NodeList();
+ getNodeList(freeNodes)->push_back(node);
+ Nodes.RemoveNode(node);
+ }
+
+ nl.clear();
+}
+
+//===----------------------------------------------------------------------===//
// ExplodedNode.
//===----------------------------------------------------------------------===//
@@ -57,6 +145,12 @@ void ExplodedNode::addPredecessor(ExplodedNode* V, ExplodedGraph &G) {
#endif
}
+void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) {
+ assert(getKind() == Size1);
+ P = reinterpret_cast<uintptr_t>(node);
+ assert(getKind() == Size1);
+}
+
void ExplodedNode::NodeGroup::addNode(ExplodedNode* N, ExplodedGraph &G) {
assert((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
assert(!getFlag());
@@ -129,10 +223,24 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint& L,
NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
if (!V) {
- // Allocate a new node.
- V = (NodeTy*) getAllocator().Allocate<NodeTy>();
+ if (freeNodes && !getNodeList(freeNodes)->empty()) {
+ NodeList *nl = getNodeList(freeNodes);
+ V = nl->back();
+ nl->pop_back();
+ }
+ else {
+ // Allocate a new node.
+ V = (NodeTy*) getAllocator().Allocate<NodeTy>();
+ }
+
new (V) NodeTy(L, State);
+ if (reclaimNodes) {
+ if (!recentlyAllocatedNodes)
+ recentlyAllocatedNodes = new NodeList();
+ getNodeList(recentlyAllocatedNodes)->push_back(V);
+ }
+
// Insert the node into the node set and return it.
Nodes.InsertNode(V, InsertPos);
OpenPOWER on IntegriCloud