/******************************************************************************* * Copyright (c) 2002 - 2006 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package com.ibm.wala.ipa.callgraph.propagation; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import com.ibm.wala.fixedpoint.impl.GeneralStatement; import com.ibm.wala.fixpoint.AbstractOperator; import com.ibm.wala.fixpoint.AbstractStatement; import com.ibm.wala.fixpoint.IFixedPointStatement; import com.ibm.wala.fixpoint.IFixedPointSystem; import com.ibm.wala.fixpoint.IVariable; import com.ibm.wala.fixpoint.UnaryOperator; import com.ibm.wala.fixpoint.UnaryStatement; import com.ibm.wala.util.collections.CompoundIterator; import com.ibm.wala.util.collections.EmptyIterator; import com.ibm.wala.util.Predicate; import com.ibm.wala.util.collections.FilterIterator; import com.ibm.wala.util.collections.HashSetFactory; import com.ibm.wala.util.collections.SmallMap; import com.ibm.wala.util.debug.Assertions; import com.ibm.wala.util.debug.UnimplementedError; import com.ibm.wala.util.graph.AbstractNumberedGraph; import com.ibm.wala.util.graph.Graph; import com.ibm.wala.util.graph.INodeWithNumber; import com.ibm.wala.util.graph.NumberedEdgeManager; import com.ibm.wala.util.graph.NumberedGraph; import com.ibm.wala.util.graph.NumberedNodeManager; import com.ibm.wala.util.graph.impl.DelegatingNumberedNodeManager; import com.ibm.wala.util.graph.impl.SparseNumberedEdgeManager; import com.ibm.wala.util.graph.traverse.Topological; import com.ibm.wala.util.heapTrace.HeapTracer; import com.ibm.wala.util.intset.BasicNaturalRelation; import com.ibm.wala.util.intset.IBinaryNaturalRelation; import com.ibm.wala.util.intset.IntIterator; import com.ibm.wala.util.intset.IntPair; import com.ibm.wala.util.intset.IntSet; /** * A dataflow graph implementation specialized for propagation-based pointer analysis */ public class PropagationGraph implements IFixedPointSystem<PointsToSetVariable> { private final static boolean DEBUG = false; private final static boolean VERBOSE = false; /** * Track nodes (PointsToSet Variables and AbstractEquations) */ private final NumberedNodeManager<INodeWithNumber> nodeManager = new DelegatingNumberedNodeManager<INodeWithNumber>(); /** * Track edges (equations) that are not represented implicitly */ private final NumberedEdgeManager<INodeWithNumber> edgeManager = new SparseNumberedEdgeManager<INodeWithNumber>(nodeManager, 2, BasicNaturalRelation.SIMPLE); private final DelegateGraph delegateGraph = new DelegateGraph(); private final HashSet<AbstractStatement> delegateStatements = HashSetFactory.make(); /** * special representation for implicitly represented unary equations. This is a map from UnaryOperator -> * IBinaryNonNegativeIntRelation. * * for UnaryOperator op, let R be implicitMap.get(op) then (i,j) \in R implies i op j is an equation in the graph * */ private final SmallMap<UnaryOperator<PointsToSetVariable>, IBinaryNaturalRelation> implicitUnaryMap = new SmallMap<UnaryOperator<PointsToSetVariable>, IBinaryNaturalRelation>(); /** * The inverse of relations in the implicit map * * for UnaryOperator op, let R be invImplicitMap.get(op) then (i,j) \in R implies j op i is an equation in the graph */ private final SmallMap<UnaryOperator<PointsToSetVariable>, IBinaryNaturalRelation> invImplicitUnaryMap = new SmallMap<UnaryOperator<PointsToSetVariable>, IBinaryNaturalRelation>(); /** * Number of implicit unary equations registered */ private int implicitUnaryCount = 0; /** * @return a relation in map m corresponding to a key */ private IBinaryNaturalRelation findOrCreateRelation(Map<UnaryOperator<PointsToSetVariable>, IBinaryNaturalRelation> m, UnaryOperator<PointsToSetVariable> key) { IBinaryNaturalRelation result = m.get(key); if (result == null) { result = makeRelation(key); m.put(key, result); } return result; } /** * @return a Relation object to track implicit equations using the operator */ private IBinaryNaturalRelation makeRelation(AbstractOperator op) { byte[] implementation = null; if (op instanceof AssignOperator) { // lots of assignments. implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY, BasicNaturalRelation.SIMPLE_SPACE_STINGY }; } else { // assume sparse assignments with any other operator. implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }; } return new BasicNaturalRelation(implementation, BasicNaturalRelation.SIMPLE); } /** * @author sfink * * A graph which tracks explicit equations. * * use this with care ... */ private class DelegateGraph extends AbstractNumberedGraph<INodeWithNumber> { private int equationCount = 0; private int varCount = 0; @Override public void addNode(INodeWithNumber o) { Assertions.UNREACHABLE("Don't call me"); } public void addEquation(AbstractStatement<PointsToSetVariable, ?> eq) { assert !containsStatement(eq); equationCount++; super.addNode(eq); } public void addVariable(PointsToSetVariable v) { if (!containsVariable(v)) { varCount++; super.addNode(v); } } /* * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() */ @Override protected NumberedNodeManager<INodeWithNumber> getNodeManager() { return nodeManager; } /* * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() */ @Override protected NumberedEdgeManager<INodeWithNumber> getEdgeManager() { return edgeManager; } protected int getEquationCount() { return equationCount; } protected int getVarCount() { return varCount; } } /** * @throws IllegalArgumentException if eq is null */ public void addStatement(GeneralStatement<PointsToSetVariable> eq) { if (eq == null) { throw new IllegalArgumentException("eq is null"); } PointsToSetVariable lhs = eq.getLHS(); delegateGraph.addEquation(eq); delegateStatements.add(eq); if (lhs != null) { delegateGraph.addVariable(lhs); delegateGraph.addEdge(eq, lhs); } for (int i = 0; i < eq.getRHS().length; i++) { PointsToSetVariable v = eq.getRHS()[i]; if (v != null) { delegateGraph.addVariable(v); delegateGraph.addEdge(v, eq); } } } public void addStatement(UnaryStatement<PointsToSetVariable> eq) throws IllegalArgumentException { if (eq == null) { throw new IllegalArgumentException("eq == null"); } if (useImplicitRepresentation(eq)) { addImplicitStatement(eq); } else { PointsToSetVariable lhs = eq.getLHS(); PointsToSetVariable rhs = eq.getRightHandSide(); delegateGraph.addEquation(eq); delegateStatements.add(eq); if (lhs != null) { delegateGraph.addVariable(lhs); delegateGraph.addEdge(eq, lhs); } delegateGraph.addVariable(rhs); delegateGraph.addEdge(rhs, eq); } } /** * @return true iff this equation should be represented implicitly in this data structure */ private boolean useImplicitRepresentation(IFixedPointStatement s) { AbstractStatement eq = (AbstractStatement) s; AbstractOperator op = eq.getOperator(); return (op instanceof AssignOperator || op instanceof PropagationCallGraphBuilder.FilterOperator); } public void removeVariable(PointsToSetVariable p) { assert getNumberOfStatementsThatDef(p) == 0; assert getNumberOfStatementsThatUse(p) == 0; delegateGraph.removeNode(p); } private void addImplicitStatement(UnaryStatement<PointsToSetVariable> eq) { if (DEBUG) { System.err.println(("addImplicitStatement " + eq)); } delegateGraph.addVariable(eq.getLHS()); delegateGraph.addVariable(eq.getRightHandSide()); int lhs = eq.getLHS().getGraphNodeId(); int rhs = eq.getRightHandSide().getGraphNodeId(); if (DEBUG) { System.err.println(("lhs rhs " + lhs + " " + rhs)); } IBinaryNaturalRelation R = findOrCreateRelation(implicitUnaryMap, eq.getOperator()); boolean b = R.add(lhs, rhs); if (b) { implicitUnaryCount++; IBinaryNaturalRelation iR = findOrCreateRelation(invImplicitUnaryMap, eq.getOperator()); iR.add(rhs, lhs); } } private void removeImplicitStatement(UnaryStatement<PointsToSetVariable> eq) { if (DEBUG) { System.err.println(("removeImplicitStatement " + eq)); } int lhs = eq.getLHS().getGraphNodeId(); int rhs = eq.getRightHandSide().getGraphNodeId(); if (DEBUG) { System.err.println(("lhs rhs " + lhs + " " + rhs)); } IBinaryNaturalRelation R = findOrCreateRelation(implicitUnaryMap, eq.getOperator()); R.remove(lhs, rhs); IBinaryNaturalRelation iR = findOrCreateRelation(invImplicitUnaryMap, eq.getOperator()); iR.remove(rhs, lhs); implicitUnaryCount--; } @Override @SuppressWarnings("unchecked") public Iterator<AbstractStatement> getStatements() { Iterator<AbstractStatement> it = new FilterIterator(delegateGraph.iterator(), new Predicate() { @Override public boolean test(Object x) { return x instanceof AbstractStatement; } }); return new CompoundIterator<AbstractStatement>(it, new GlobalImplicitIterator()); } /** * Iterator of implicit equations that use a particular variable. */ private final class ImplicitUseIterator implements Iterator<AbstractStatement> { final PointsToSetVariable use; final IntIterator defs; final UnaryOperator<PointsToSetVariable> op; ImplicitUseIterator(UnaryOperator<PointsToSetVariable> op, PointsToSetVariable use, IntSet defs) { this.op = op; this.use = use; this.defs = defs.intIterator(); } @Override public boolean hasNext() { return defs.hasNext(); } @Override public AbstractStatement next() { int l = defs.next(); PointsToSetVariable lhs = (PointsToSetVariable) delegateGraph.getNode(l); UnaryStatement temp = op.makeEquation(lhs, use); if (DEBUG) { System.err.print(("XX Return temp: " + temp)); System.err.println(("lhs rhs " + l + " " + use.getGraphNodeId())); } return temp; } @Override public void remove() { // TODO Auto-generated method stub Assertions.UNREACHABLE(); } } /** * Iterator of implicit equations that def a particular variable. */ private final class ImplicitDefIterator implements Iterator<AbstractStatement> { final PointsToSetVariable def; final IntIterator uses; final UnaryOperator<PointsToSetVariable> op; ImplicitDefIterator(UnaryOperator<PointsToSetVariable> op, IntSet uses, PointsToSetVariable def) { this.op = op; this.def = def; this.uses = uses.intIterator(); } @Override public boolean hasNext() { return uses.hasNext(); } @Override public AbstractStatement next() { int r = uses.next(); PointsToSetVariable rhs = (PointsToSetVariable) delegateGraph.getNode(r); UnaryStatement temp = op.makeEquation(def, rhs); if (DEBUG) { System.err.print(("YY Return temp: " + temp)); } return temp; } @Override public void remove() { // TODO Auto-generated method stub Assertions.UNREACHABLE(); } } /** * Iterator of all implicit equations */ private class GlobalImplicitIterator implements Iterator<AbstractStatement> { private final Iterator<UnaryOperator<PointsToSetVariable>> outerKeyDelegate = implicitUnaryMap.keySet().iterator(); private Iterator innerDelegate; private UnaryOperator<PointsToSetVariable> currentOperator; GlobalImplicitIterator() { advanceOuter(); } /** * advance to the next operator */ private void advanceOuter() { innerDelegate = null; while (outerKeyDelegate.hasNext()) { currentOperator = outerKeyDelegate.next(); IBinaryNaturalRelation R = implicitUnaryMap.get(currentOperator); Iterator it = R.iterator(); if (it.hasNext()) { innerDelegate = it; return; } } } @Override public boolean hasNext() { return innerDelegate != null; } @Override public AbstractStatement next() { IntPair p = (IntPair) innerDelegate.next(); int lhs = p.getX(); int rhs = p.getY(); UnaryStatement result = currentOperator.makeEquation((PointsToSetVariable) delegateGraph.getNode(lhs), (PointsToSetVariable) delegateGraph.getNode(rhs)); if (!innerDelegate.hasNext()) { advanceOuter(); } return result; } @Override public void remove() { // TODO Auto-generated method stub Assertions.UNREACHABLE(); } } @Override public void removeStatement(IFixedPointStatement<PointsToSetVariable> eq) throws IllegalArgumentException { if (eq == null) { throw new IllegalArgumentException("eq == null"); } if (useImplicitRepresentation(eq)) { removeImplicitStatement((UnaryStatement<PointsToSetVariable>) eq); } else { delegateStatements.remove(eq); delegateGraph.removeNodeAndEdges(eq); } } @Override public void reorder() { VariableGraphView graph = new VariableGraphView(); Iterator<PointsToSetVariable> order = Topological.makeTopologicalIter(graph); int number = 0; while (order.hasNext()) { Object elt = order.next(); if (elt instanceof IVariable) { IVariable v = (IVariable) elt; v.setOrderNumber(number++); } } } /** * A graph of just the variables in the system. v1 -> v2 iff there exists equation e s.t. e uses v1 and e defs v2. * * Note that this graph trickily and fragilely reuses the nodeManager from the delegateGraph, above. This will work ok as long as * every variable is inserted in the delegateGraph. */ private class VariableGraphView extends AbstractNumberedGraph<PointsToSetVariable> { /* * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) */ @Override public void removeNodeAndEdges(PointsToSetVariable N) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() */ @Override public Iterator<PointsToSetVariable> iterator() { return getVariables(); } /* * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() */ @Override public int getNumberOfNodes() { return delegateGraph.getVarCount(); } /* * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) */ @Override public void addNode(PointsToSetVariable n) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) */ @Override public void removeNode(PointsToSetVariable n) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) */ @Override public boolean containsNode(PointsToSetVariable N) { Assertions.UNREACHABLE(); return false; } /* * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) */ @Override public Iterator<PointsToSetVariable> getPredNodes(PointsToSetVariable v) { final Iterator eqs = getStatementsThatDef(v); return new Iterator<PointsToSetVariable>() { Iterator<INodeWithNumber> inner; @Override public boolean hasNext() { return eqs.hasNext() || (inner != null); } @Override public PointsToSetVariable next() { if (inner != null) { PointsToSetVariable result = (PointsToSetVariable)inner.next(); if (!inner.hasNext()) { inner = null; } return result; } else { AbstractStatement eq = (AbstractStatement) eqs.next(); if (useImplicitRepresentation(eq)) { return (PointsToSetVariable) ((UnaryStatement) eq).getRightHandSide(); } else { inner = delegateGraph.getPredNodes(eq); return next(); } } } @Override public void remove() { // TODO Auto-generated method stub Assertions.UNREACHABLE(); } }; } /* * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) */ @SuppressWarnings("unused") public int getPredNodeCount(INodeWithNumber N) { PointsToSetVariable v = (PointsToSetVariable) N; int result = 0; for (Iterator eqs = getStatementsThatDef(v); eqs.hasNext();) { AbstractStatement eq = (AbstractStatement) eqs.next(); if (useImplicitRepresentation(eq)) { result++; } else { result += delegateGraph.getPredNodeCount(N); } } return result; } /* * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) */ @Override public Iterator<PointsToSetVariable> getSuccNodes(PointsToSetVariable v) { final Iterator eqs = getStatementsThatUse(v); return new Iterator<PointsToSetVariable>() { PointsToSetVariable nextResult; { advance(); } @Override public boolean hasNext() { return nextResult != null; } @Override public PointsToSetVariable next() { PointsToSetVariable result = nextResult; advance(); return result; } private void advance() { nextResult = null; while (eqs.hasNext() && nextResult == null) { AbstractStatement eq = (AbstractStatement) eqs.next(); nextResult = (PointsToSetVariable) eq.getLHS(); } } @Override public void remove() { // TODO Auto-generated method stub Assertions.UNREACHABLE(); } }; } /* * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) */ @Override public int getSuccNodeCount(PointsToSetVariable v) { int result = 0; for (Iterator eqs = getStatementsThatUse(v); eqs.hasNext();) { AbstractStatement eq = (AbstractStatement) eqs.next(); IVariable lhs = eq.getLHS(); if (lhs != null) { result++; } } return result; } /* * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) */ @Override public void addEdge(PointsToSetVariable src, PointsToSetVariable dst) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.EdgeManager#removeAllIncidentEdges(java.lang.Object) */ @Override public void removeAllIncidentEdges(PointsToSetVariable node) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() */ @Override @SuppressWarnings("unchecked") protected NumberedNodeManager getNodeManager() { return nodeManager; } /* * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() */ @Override @SuppressWarnings("unchecked") protected NumberedEdgeManager getEdgeManager() { // TODO Auto-generated method stub Assertions.UNREACHABLE(); return null; } } @Override @SuppressWarnings("unchecked") public Iterator<AbstractStatement> getStatementsThatUse(PointsToSetVariable v) { if (v == null) { throw new IllegalArgumentException("v is null"); } int number = v.getGraphNodeId(); if (number == -1) { return EmptyIterator.instance(); } Iterator<INodeWithNumber> result = delegateGraph.getSuccNodes(v); for (int i = 0; i < invImplicitUnaryMap.size(); i++) { UnaryOperator op = invImplicitUnaryMap.getKey(i); IBinaryNaturalRelation R = (IBinaryNaturalRelation) invImplicitUnaryMap.getValue(i); IntSet s = R.getRelated(number); if (s != null) { result = new CompoundIterator<INodeWithNumber>(new ImplicitUseIterator(op, v, s), result); } } List<AbstractStatement> list = new ArrayList<AbstractStatement>(); while (result.hasNext()) { list.add((AbstractStatement) result.next()); } return list.iterator(); } @Override @SuppressWarnings("unchecked") public Iterator<AbstractStatement> getStatementsThatDef(PointsToSetVariable v) { if (v == null) { throw new IllegalArgumentException("v is null"); } int number = v.getGraphNodeId(); if (number == -1) { return EmptyIterator.instance(); } Iterator<INodeWithNumber> result = delegateGraph.getPredNodes(v); for (int i = 0; i < implicitUnaryMap.size(); i++) { UnaryOperator op = implicitUnaryMap.getKey(i); IBinaryNaturalRelation R = (IBinaryNaturalRelation) implicitUnaryMap.getValue(i); IntSet s = R.getRelated(number); if (s != null) { result = new CompoundIterator<INodeWithNumber>(new ImplicitDefIterator(op, s, v), result); } } List<AbstractStatement> list = new ArrayList<AbstractStatement>(); while (result.hasNext()) { list.add((AbstractStatement) result.next()); } return list.iterator(); } /** * Note that this implementation consults the implicit relation for each and every operator cached. This will be inefficient if * there are many implicit operators. * * @throws IllegalArgumentException if v is null * */ @Override public int getNumberOfStatementsThatUse(PointsToSetVariable v) { if (v == null) { throw new IllegalArgumentException("v is null"); } int number = v.getGraphNodeId(); if (number == -1) { return 0; } int result = delegateGraph.getSuccNodeCount(v); for (Iterator it = invImplicitUnaryMap.keySet().iterator(); it.hasNext();) { UnaryOperator op = (UnaryOperator) it.next(); IBinaryNaturalRelation R = invImplicitUnaryMap.get(op); IntSet s = R.getRelated(number); if (s != null) { result += s.size(); } } return result; } @Override public int getNumberOfStatementsThatDef(PointsToSetVariable v) { if (v == null) { throw new IllegalArgumentException("v is null"); } int number = v.getGraphNodeId(); if (number == -1) { return 0; } int result = delegateGraph.getPredNodeCount(v); for (Iterator it = implicitUnaryMap.keySet().iterator(); it.hasNext();) { UnaryOperator op = (UnaryOperator) it.next(); IBinaryNaturalRelation R = implicitUnaryMap.get(op); IntSet s = R.getRelated(number); if (s != null) { result += s.size(); } } return result; } @Override @SuppressWarnings("unchecked") public Iterator<PointsToSetVariable> getVariables() { Iterator<PointsToSetVariable> it = new FilterIterator(delegateGraph.iterator(), new Predicate() { @Override public boolean test(Object x) { return x instanceof IVariable; } }); return it; } /* * @see com.ibm.wala.util.debug.VerboseAction#performVerboseAction() */ public void performVerboseAction() { if (VERBOSE) { System.err.println(("stats for " + getClass())); System.err.println(("number of variables: " + delegateGraph.getVarCount())); System.err.println(("implicit equations: " + (implicitUnaryCount))); System.err.println(("explicit equations: " + delegateGraph.getEquationCount())); System.err.println("implicit map:"); int count = 0; int totalBytes = 0; for (Iterator it = implicitUnaryMap.entrySet().iterator(); it.hasNext();) { count++; Map.Entry e = (Map.Entry) it.next(); IBinaryNaturalRelation R = (IBinaryNaturalRelation) e.getValue(); System.err.println(("entry " + count)); R.performVerboseAction(); HeapTracer.Result result = HeapTracer.traceHeap(Collections.singleton(R), false); totalBytes += result.getTotalSize(); } System.err.println(("bytes in implicit map: " + totalBytes)); } } @Override public boolean containsStatement(IFixedPointStatement<PointsToSetVariable> eq) throws IllegalArgumentException { if (eq == null) { throw new IllegalArgumentException("eq == null"); } if (useImplicitRepresentation(eq)) { UnaryStatement<PointsToSetVariable> ueq = (UnaryStatement<PointsToSetVariable>) eq; return containsImplicitStatement(ueq); } else { return delegateStatements.contains(eq); } } /** * @return true iff the graph already contains this equation */ private boolean containsImplicitStatement(UnaryStatement<PointsToSetVariable> eq) { if (!containsVariable(eq.getLHS())) { return false; } if (!containsVariable(eq.getRightHandSide())) { return false; } int lhs = eq.getLHS().getGraphNodeId(); int rhs = eq.getRightHandSide().getGraphNodeId(); UnaryOperator op = eq.getOperator(); IBinaryNaturalRelation R = implicitUnaryMap.get(op); if (R != null) { return R.contains(lhs, rhs); } else { return false; } } @Override public boolean containsVariable(PointsToSetVariable v) { return delegateGraph.containsNode(v); } @Override public void addStatement(IFixedPointStatement<PointsToSetVariable> statement) throws IllegalArgumentException, UnimplementedError { if (statement == null) { throw new IllegalArgumentException("statement == null"); } if (statement instanceof UnaryStatement) { addStatement((UnaryStatement<PointsToSetVariable>) statement); } else if (statement instanceof GeneralStatement) { addStatement((GeneralStatement<PointsToSetVariable>) statement); } else { Assertions.UNREACHABLE("unexpected: " + statement.getClass()); } } /** * A graph of just the variables in the system. v1 -> v2 iff there exists an assignment equation e s.t. e uses v1 and e defs v2. * */ public NumberedGraph<PointsToSetVariable> getAssignmentGraph() { return new FilteredConstraintGraphView() { @Override boolean isInteresting(AbstractStatement eq) { return eq instanceof AssignEquation; } }; } /** * A graph of just the variables in the system. v1 -> v2 iff there exists an Assingnment or Filter equation e s.t. e uses v1 and e * defs v2. * */ public Graph<PointsToSetVariable> getFilterAssignmentGraph() { return new FilteredConstraintGraphView() { @Override boolean isInteresting(AbstractStatement eq) { return eq instanceof AssignEquation || eq.getOperator() instanceof PropagationCallGraphBuilder.FilterOperator; } }; } /** * NOTE: do not use this method unless you really know what you are doing. Functionality is fragile and may not work in the * future. */ public Graph<PointsToSetVariable> getFlowGraphIncludingImplicitConstraints() { return new VariableGraphView(); } /** * A graph of just the variables in the system. v1 -> v2 that are related by def-use with "interesting" operators * */ private abstract class FilteredConstraintGraphView extends AbstractNumberedGraph<PointsToSetVariable> { abstract boolean isInteresting(AbstractStatement eq); /* * @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object) */ @Override public void removeNodeAndEdges(PointsToSetVariable N) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.NodeManager#iterateNodes() */ @Override public Iterator<PointsToSetVariable> iterator() { return getVariables(); } /* * @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes() */ @Override public int getNumberOfNodes() { return delegateGraph.getVarCount(); } /* * @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object) */ @Override public void addNode(PointsToSetVariable n) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object) */ @Override public void removeNode(PointsToSetVariable n) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object) */ @Override public boolean containsNode(PointsToSetVariable N) { Assertions.UNREACHABLE(); return false; } /* * @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object) */ @Override public Iterator<PointsToSetVariable> getPredNodes(PointsToSetVariable v) { final Iterator eqs = getStatementsThatDef(v); return new Iterator<PointsToSetVariable>() { PointsToSetVariable nextResult; { advance(); } @Override public boolean hasNext() { return nextResult != null; } @Override public PointsToSetVariable next() { PointsToSetVariable result = nextResult; advance(); return result; } private void advance() { nextResult = null; while (eqs.hasNext() && nextResult == null) { AbstractStatement eq = (AbstractStatement) eqs.next(); if (isInteresting(eq)) { nextResult = (PointsToSetVariable) ((UnaryStatement) eq).getRightHandSide(); } } } @Override public void remove() { Assertions.UNREACHABLE(); } }; } /* * @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object) */ @Override public int getPredNodeCount(PointsToSetVariable v) { int result = 0; for (Iterator eqs = getStatementsThatDef(v); eqs.hasNext();) { AbstractStatement eq = (AbstractStatement) eqs.next(); if (isInteresting(eq)) { result++; } } return result; } /* * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object) */ @Override public Iterator<PointsToSetVariable> getSuccNodes(PointsToSetVariable v) { final Iterator eqs = getStatementsThatUse(v); return new Iterator<PointsToSetVariable>() { PointsToSetVariable nextResult; { advance(); } @Override public boolean hasNext() { return nextResult != null; } @Override public PointsToSetVariable next() { PointsToSetVariable result = nextResult; advance(); return result; } private void advance() { nextResult = null; while (eqs.hasNext() && nextResult == null) { AbstractStatement eq = (AbstractStatement) eqs.next(); if (isInteresting(eq)) { nextResult = (PointsToSetVariable) ((UnaryStatement) eq).getLHS(); } } } @Override public void remove() { // TODO Auto-generated method stub Assertions.UNREACHABLE(); } }; } /* * @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object) */ @Override public int getSuccNodeCount(PointsToSetVariable v) { int result = 0; for (Iterator eqs = getStatementsThatUse(v); eqs.hasNext();) { AbstractStatement eq = (AbstractStatement) eqs.next(); if (isInteresting(eq)) { result++; } } return result; } /* * @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object, java.lang.Object) */ @Override public void addEdge(PointsToSetVariable src, PointsToSetVariable dst) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.EdgeManager#removeAllIncidentEdges(java.lang.Object) */ @Override public void removeAllIncidentEdges(PointsToSetVariable node) { Assertions.UNREACHABLE(); } /* * @see com.ibm.wala.util.graph.AbstractGraph#getNodeManager() */ @Override @SuppressWarnings("unchecked") protected NumberedNodeManager getNodeManager() { return nodeManager; } /* * @see com.ibm.wala.util.graph.AbstractGraph#getEdgeManager() */ @Override protected NumberedEdgeManager<PointsToSetVariable> getEdgeManager() { Assertions.UNREACHABLE(); return null; } } public String spaceReport() { StringBuffer result = new StringBuffer("PropagationGraph\n"); result.append("ImplicitEdges:" + countImplicitEdges() + "\n"); // for (Iterator it = implicitUnaryMap.values().iterator(); it.hasNext(); ) // { // result.append(it.next() + "\n"); // } return result.toString(); } private int countImplicitEdges() { int result = 0; for (Iterator it = new GlobalImplicitIterator(); it.hasNext();) { it.next(); result++; } return result; } }