ExplodedGraph.cpp revision 43b82b823a6113fdbee54243b280db9c55ef72cb
1e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- C++ -*------=//
2e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//
3e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//                     The LLVM Compiler Infrastructure
4e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//
5e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad// This file is distributed under the University of Illinois Open Source
6e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad// License. See LICENSE.TXT for details.
7e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//
8e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//===----------------------------------------------------------------------===//
9e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//
10e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//  This file defines the template classes ExplodedNode and ExplodedGraph,
11e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//  which represent a path-sensitive, intra-procedural "exploded graph."
12e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//
13e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//===----------------------------------------------------------------------===//
14e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
15e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
16e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#include "clang/AST/ParentMap.h"
17ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn#include "clang/AST/Stmt.h"
18e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19b95f169a74a18470cbf619264243015052285e9bGabriel Peal#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
20e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#include "llvm/ADT/DenseMap.h"
21e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#include "llvm/ADT/DenseSet.h"
22e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#include "llvm/ADT/SmallVector.h"
23e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#include "llvm/ADT/Statistic.h"
24e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#include <vector>
25e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
26229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shraunerusing namespace clang;
27e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awadusing namespace ento;
28e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
29e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//===----------------------------------------------------------------------===//
30b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad// Node auditing.
31b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad//===----------------------------------------------------------------------===//
32e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
33b95f169a74a18470cbf619264243015052285e9bGabriel Peal// An out of line virtual method to provide a home for the class vtable.
34e63fadb109ce52f9c357520074379aca0e3cb11dIhab AwadExplodedNode::Auditor::~Auditor() {}
35e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
36e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#ifndef NDEBUG
37e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awadstatic ExplodedNode::Auditor* NodeAuditor = 0;
38e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#endif
39e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
40e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awadvoid ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
41b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad#ifndef NDEBUG
42e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  NodeAuditor = A;
43b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad#endif
44e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
45e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
46e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//===----------------------------------------------------------------------===//
47e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad// Cleanup.
48e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//===----------------------------------------------------------------------===//
49e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
50e63fadb109ce52f9c357520074379aca0e3cb11dIhab AwadExplodedGraph::ExplodedGraph()
51e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  : NumNodes(0), ReclaimNodeInterval(0) {}
52e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
53e63fadb109ce52f9c357520074379aca0e3cb11dIhab AwadExplodedGraph::~ExplodedGraph() {}
54e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
55e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//===----------------------------------------------------------------------===//
56e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad// Node reclamation.
57e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad//===----------------------------------------------------------------------===//
58e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
59e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awadbool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
60e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Reclaim all nodes that match *all* the following criteria:
61e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  //
62e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (1) 1 predecessor (that has one successor)
63e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (2) 1 successor (that has one predecessor)
64e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (3) The ProgramPoint is for a PostStmt, but not a PostStore.
65e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (4) There is no 'tag' for the ProgramPoint.
66e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (5) The 'store' is the same as the predecessor.
67e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (6) The 'GDM' is the same as the predecessor.
68e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (7) The LocationContext is the same as the predecessor.
69e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (8) Expressions that are *not* lvalue expressions.
70e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (9) The PostStmt isn't for a non-consumed Stmt or Expr.
71e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (10) The successor is not a CallExpr StmtPoint (so that we would
72e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  //      be able to find it when retrying a call with no inlining).
73e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well.
74e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
75e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Conditions 1 and 2.
76e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (node->pred_size() != 1 || node->succ_size() != 1)
776c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    return false;
786c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
796c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon  const ExplodedNode *pred = *(node->pred_begin());
806c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon  if (pred->succ_size() != 1)
816c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    return false;
826c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
836c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon  const ExplodedNode *succ = *(node->succ_begin());
846c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon  if (succ->pred_size() != 1)
856c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    return false;
866c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
87e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Condition 3.
88e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  ProgramPoint progPoint = node->getLocation();
89ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn  if (!progPoint.getAs<PostStmt>() || progPoint.getAs<PostStore>())
90ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn    return false;
91e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
92e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Condition 4.
93e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  PostStmt ps = progPoint.castAs<PostStmt>();
94f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon  if (ps.getTag())
95e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return false;
96e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
97e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Conditions 5, 6, and 7.
98e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  ProgramStateRef state = node->getState();
99e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  ProgramStateRef pred_state = pred->getState();
100e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
101b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad      progPoint.getLocationContext() != pred->getLocationContext())
102e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return false;
103229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner
104e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Condition 8.
1056c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon  // Do not collect nodes for lvalue expressions since they are
1066c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon  // used extensively for generating path diagnostics.
107e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  const Expr *Ex = dyn_cast<Expr>(ps.getStmt());
108e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (!Ex || Ex->isLValue())
109e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return false;
110e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
111e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Condition 9.
112e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Do not collect nodes for non-consumed Stmt or Expr to ensure precise
11388b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon  // diagnostic generation; specifically, so that we could anchor arrows
11488b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon  // pointing to the beginning of statements (as written in code).
115ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn  ParentMap &PM = progPoint.getLocationContext()->getParentMap();
116e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (!PM.isConsumedExpr(Ex))
11788b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon    return false;
118ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn
119e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Condition 10.
120e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  const ProgramPoint SuccLoc = succ->getLocation();
121e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (Optional<StmtPoint> SP = SuccLoc.getAs<StmtPoint>())
122e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    if (CallEvent::isCallStmt(SP->getStmt()))
123e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad      return false;
124ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn
125e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  return true;
126e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
127e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
128e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awadvoid ExplodedGraph::collectNode(ExplodedNode *node) {
129e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Removing a node means:
13088b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon  // (a) changing the predecessors successor to the successor of this node
131ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn  // (b) changing the successors predecessor to the predecessor of this node
132e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // (c) Putting 'node' onto freeNodes.
13388b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon  assert(node->pred_size() == 1 || node->succ_size() == 1);
134ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn  ExplodedNode *pred = *(node->pred_begin());
135e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  ExplodedNode *succ = *(node->succ_begin());
136e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  pred->replaceSuccessor(succ);
137e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  succ->replacePredecessor(pred);
138e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  FreeNodes.push_back(node);
139ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn  Nodes.RemoveNode(node);
140ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn  --NumNodes;
141e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  node->~ExplodedNode();
142e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
143e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
144e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awadvoid ExplodedGraph::reclaimRecentlyAllocatedNodes() {
145e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (ChangedNodes.empty())
146e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return;
147b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad
148b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad  // Only periodically reclaim nodes so that we can build up a set of
149b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad  // nodes that meet the reclamation criteria.  Freshly created nodes
150b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad  // by definition have no successor, and thus cannot be reclaimed (see below).
151e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  assert(ReclaimCounter > 0);
152e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (--ReclaimCounter != 0)
153e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return;
154e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  ReclaimCounter = ReclaimNodeInterval;
155ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn
156ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn  for (NodeVector::iterator it = ChangedNodes.begin(), et = ChangedNodes.end();
157e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad       it != et; ++it) {
158e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    ExplodedNode *node = *it;
159e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    if (shouldCollect(node))
160e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad      collectNode(node);
161e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  }
162e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  ChangedNodes.clear();
163e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
1646c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
1656c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon//===----------------------------------------------------------------------===//
1666c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon// ExplodedNode.
1676c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon//===----------------------------------------------------------------------===//
1686c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
1696c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon// An NodeGroup's storage type is actually very much like a TinyPtrVector:
1706c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon// it can be either a pointer to a single ExplodedNode, or a pointer to a
1716c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon// BumpVector allocated with the ExplodedGraph's allocator. This allows the
172e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad// common case of single-node NodeGroups to be implemented with no extra memory.
173f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon//
174f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon// Consequently, each of the NodeGroup methods have up to four cases to handle:
175f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon// 1. The flag is set and this group does not actually contain any nodes.
176f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon// 2. The group is empty, in which case the storage value is null.
177f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon// 3. The group contains a single node.
178f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon// 4. The group contains more than one node.
179f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordontypedef BumpVector<ExplodedNode *> ExplodedNodeVector;
180f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordontypedef llvm::PointerUnion<ExplodedNode *, ExplodedNodeVector *> GroupStorage;
181f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon
182f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordonvoid ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) {
183f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon  assert (!V->isSink());
184f30d7e9a8e8fa7e10068139decb0e7665381a686Santos Cordon  Preds.addNode(V, G);
185e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  V->Succs.addNode(this, G);
186e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#ifndef NDEBUG
187e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (NodeAuditor) NodeAuditor->AddEdge(V, this);
188e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad#endif
189e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
190e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
191e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awadvoid ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) {
192e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  assert(!getFlag());
193e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
194e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P);
195e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  assert(Storage.is<ExplodedNode *>());
196e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  Storage = node;
197e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  assert(Storage.is<ExplodedNode *>());
198e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
199229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner
200229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shraunervoid ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) {
201229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner  assert(!getFlag());
202e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
203e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P);
204e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (Storage.isNull()) {
205e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    Storage = N;
206e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    assert(Storage.is<ExplodedNode *>());
207e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return;
208e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  }
209e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
210e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>();
211e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
212e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (!V) {
213e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    // Switch from single-node to multi-node representation.
2146c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    ExplodedNode *Old = Storage.get<ExplodedNode *>();
2156c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
2166c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    BumpVectorContext &Ctx = G.getNodeAllocator();
2176c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    V = G.getAllocator().Allocate<ExplodedNodeVector>();
2186c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    new (V) ExplodedNodeVector(Ctx, 4);
2196c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    V->push_back(Old, Ctx);
2206c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
2216c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    Storage = V;
2226c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    assert(!getFlag());
223e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    assert(Storage.is<ExplodedNodeVector *>());
224e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  }
225e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
226e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  V->push_back(N, G.getNodeAllocator());
227e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
228e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
229e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awadunsigned ExplodedNode::NodeGroup::size() const {
230e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (getFlag())
231e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return 0;
232e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
233e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
234e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (Storage.isNull())
235e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return 0;
236e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
237e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    return V->size();
238e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  return 1;
239e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
240e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
241e63fadb109ce52f9c357520074379aca0e3cb11dIhab AwadExplodedNode * const *ExplodedNode::NodeGroup::begin() const {
242e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  if (getFlag())
2430d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee    return 0;
2440d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee
2450d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
2460d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  if (Storage.isNull())
2470d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee    return 0;
2480d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
2490d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee    return V->begin();
2500d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  return Storage.getAddrOfPtr1();
2510d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee}
2520d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee
2530d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke LeeExplodedNode * const *ExplodedNode::NodeGroup::end() const {
2540d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  if (getFlag())
2550d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee    return 0;
2560d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee
2570d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
2580d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  if (Storage.isNull())
2590d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee    return 0;
2600d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
2610d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee    return V->end();
2620d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee  return Storage.getAddrOfPtr1() + 1;
2630d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee}
2640d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke Lee
2650d6ea71bcfe44ada319ac9387d9ce1b3761eea58Yorke LeeExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
266e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad                                     ProgramStateRef State,
267e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad                                     bool IsSink,
268e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad                                     bool* IsNew) {
269e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  // Profile 'State' to determine if we already have an existing node.
270b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad  llvm::FoldingSetNodeID profile;
271e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  void *InsertPos = 0;
272e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
273e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  NodeTy::Profile(profile, L, State, IsSink);
274e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
275229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner
276229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner  if (!V) {
277e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    if (!FreeNodes.empty()) {
278e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad      V = FreeNodes.back();
279e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad      FreeNodes.pop_back();
280e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    }
281229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner    else {
282229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner      // Allocate a new node.
283e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad      V = (NodeTy*) getAllocator().Allocate<NodeTy>();
284e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    }
285e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
286b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad    new (V) NodeTy(L, State, IsSink);
287229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner
288229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner    if (ReclaimNodeInterval)
289e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad      ChangedNodes.push_back(V);
290e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
291e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    // Insert the node into the node set and return it.
292e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    Nodes.InsertNode(V, InsertPos);
293229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner    ++NumNodes;
294229e3820dce98f64fd4834d5f421faec9a9d7026Jay Shrauner
295e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad    if (IsNew) *IsNew = true;
296e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  }
297e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  else
2986c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon    if (IsNew) *IsNew = false;
2996c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
3006c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon  return V;
3016c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon}
3026c912b7d056c67b41fd46f31de168795e97c2336Santos Cordon
3036c912b7d056c67b41fd46f31de168795e97c2336Santos Cordonstd::pair<ExplodedGraph*, InterExplodedGraphMap*>
30488b771d8cd3f1e5748078c02f3ab571831ace72fSantos CordonExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
30588b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon               llvm::DenseMap<const void*, const void*> *InverseMap) const {
306ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn
30788b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon  if (NBeg == NEnd)
30888b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon    return std::make_pair((ExplodedGraph*) 0,
309e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad                          (InterExplodedGraphMap*) 0);
31088b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon
31188b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon  assert (NBeg < NEnd);
312ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn
31388b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon  OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap());
31488b771d8cd3f1e5748078c02f3ab571831ace72fSantos Cordon
315e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap);
316e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
317e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad  return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
318e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad}
319e63fadb109ce52f9c357520074379aca0e3cb11dIhab Awad
320ExplodedGraph*
321ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
322                            const ExplodedNode* const* EndSources,
323                            InterExplodedGraphMap* M,
324                   llvm::DenseMap<const void*, const void*> *InverseMap) const {
325
326  typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
327  Pass1Ty Pass1;
328
329  typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty;
330  Pass2Ty& Pass2 = M->M;
331
332  SmallVector<const ExplodedNode*, 10> WL1, WL2;
333
334  // ===- Pass 1 (reverse DFS) -===
335  for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) {
336    if (*I)
337      WL1.push_back(*I);
338  }
339
340  // Process the first worklist until it is empty.  Because it is a std::list
341  // it acts like a FIFO queue.
342  while (!WL1.empty()) {
343    const ExplodedNode *N = WL1.back();
344    WL1.pop_back();
345
346    // Have we already visited this node?  If so, continue to the next one.
347    if (Pass1.count(N))
348      continue;
349
350    // Otherwise, mark this node as visited.
351    Pass1.insert(N);
352
353    // If this is a root enqueue it to the second worklist.
354    if (N->Preds.empty()) {
355      WL2.push_back(N);
356      continue;
357    }
358
359    // Visit our predecessors and enqueue them.
360    for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
361         I != E; ++I)
362      WL1.push_back(*I);
363  }
364
365  // We didn't hit a root? Return with a null pointer for the new graph.
366  if (WL2.empty())
367    return 0;
368
369  // Create an empty graph.
370  ExplodedGraph* G = MakeEmptyGraph();
371
372  // ===- Pass 2 (forward DFS to construct the new graph) -===
373  while (!WL2.empty()) {
374    const ExplodedNode *N = WL2.back();
375    WL2.pop_back();
376
377    // Skip this node if we have already processed it.
378    if (Pass2.find(N) != Pass2.end())
379      continue;
380
381    // Create the corresponding node in the new graph and record the mapping
382    // from the old node to the new node.
383    ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(), 0);
384    Pass2[N] = NewN;
385
386    // Also record the reverse mapping from the new node to the old node.
387    if (InverseMap) (*InverseMap)[NewN] = N;
388
389    // If this node is a root, designate it as such in the graph.
390    if (N->Preds.empty())
391      G->addRoot(NewN);
392
393    // In the case that some of the intended predecessors of NewN have already
394    // been created, we should hook them up as predecessors.
395
396    // Walk through the predecessors of 'N' and hook up their corresponding
397    // nodes in the new graph (if any) to the freshly created node.
398    for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
399         I != E; ++I) {
400      Pass2Ty::iterator PI = Pass2.find(*I);
401      if (PI == Pass2.end())
402        continue;
403
404      NewN->addPredecessor(PI->second, *G);
405    }
406
407    // In the case that some of the intended successors of NewN have already
408    // been created, we should hook them up as successors.  Otherwise, enqueue
409    // the new nodes from the original graph that should have nodes created
410    // in the new graph.
411    for (ExplodedNode::succ_iterator I = N->Succs.begin(), E = N->Succs.end();
412         I != E; ++I) {
413      Pass2Ty::iterator PI = Pass2.find(*I);
414      if (PI != Pass2.end()) {
415        PI->second->addPredecessor(NewN, *G);
416        continue;
417      }
418
419      // Enqueue nodes to the worklist that were marked during pass 1.
420      if (Pass1.count(*I))
421        WL2.push_back(*I);
422    }
423  }
424
425  return G;
426}
427
428void InterExplodedGraphMap::anchor() { }
429
430ExplodedNode*
431InterExplodedGraphMap::getMappedNode(const ExplodedNode *N) const {
432  llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
433    M.find(N);
434
435  return I == M.end() ? 0 : I->second;
436}
437
438