diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BackwardsSupergraph.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BackwardsSupergraph.java index f47b99abc..94f8917b9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BackwardsSupergraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/BackwardsSupergraph.java @@ -127,8 +127,8 @@ public class BackwardsSupergraph implements ISupergraph { /* * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object) */ - public Iterator getReturnSites(T c) { - return delegate.getCallSites(c); + public Iterator getReturnSites(T c, P callee) { + return delegate.getCallSites(c, callee); } /* @@ -251,19 +251,6 @@ public class BackwardsSupergraph implements ISupergraph { return delegate.getEntriesForProcedure(object); } -// /* -// * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getMainEntry() -// */ -// public T getMainEntry() { -// return delegate.getMainExit(); -// } -// -// /* -// * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getMainExit() -// */ -// public T getMainExit() { -// return delegate.getMainEntry(); -// } /* * @see com.ibm.wala.dataflow.IFDS.ISupergraph#isReturn(java.lang.Object) @@ -276,8 +263,8 @@ public class BackwardsSupergraph implements ISupergraph { /* * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object) */ - public Iterator getCallSites(T r) { - return delegate.getReturnSites(r); + public Iterator getCallSites(T r, P callee) { + return delegate.getReturnSites(r, callee); } /* diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ISupergraph.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ISupergraph.java index 88efcf43e..8e60c13ca 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ISupergraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ISupergraph.java @@ -19,20 +19,17 @@ import com.ibm.wala.util.graph.NumberedGraph; * * A supergraph as defined by Reps, Horwitz, and Sagiv POPL95 *

- * In our implementation we don't require explicit entry and exit nodes. So, the - * first basic block in a method is implicitly the entry node, but might also be - * a call node too. Similarly for exit nodes. The solver is coded to deal with - * this appropriately. + * In our implementation we don't require explicit entry and exit nodes. So, the first basic block in a method is + * implicitly the entry node, but might also be a call node too. Similarly for exit nodes. The solver is coded to deal + * with this appropriately. *

- * Additionally, due to exceptional control flow, each method might have - * multiple exits or multiple entries. + * Additionally, due to exceptional control flow, each method might have multiple exits or multiple entries. * - * T type of node in the supergraph - * P type of a procedure (like a box in an RSM) + * T type of node in the supergraph P type of a procedure (like a box in an RSM) * * @author sfink */ -public interface ISupergraph extends NumberedGraph { +public interface ISupergraph extends NumberedGraph { public static final byte CALL_EDGE = 0; @@ -42,102 +39,87 @@ public interface ISupergraph extends NumberedGraph { public static final byte OTHER = 3; - /** * @return the graph of procedures (e.g. a call graph) over which this supergraph is induced. */ Graph getProcedureGraph(); /** - * @param n - * a node in this supergraph + * @param n a node in this supergraph * @return true iff this node includes a call. */ boolean isCall(T n); /** - * @param call - * a "call" node in the supergraph + * @param call a "call" node in the supergraph * @return an Iterator of nodes that are targets of this call. */ Iterator getCalledNodes(T call); /** - * @param call - * a "call" node in the supergraph - * @return an Iterator of nodes that are normal (non-call) successors of this - * call. This should only apply to backwards problems, where we might - * have, say, a call and a goto flow into a return site. + * @param call a "call" node in the supergraph + * @return an Iterator of nodes that are normal (non-call) successors of this call. This should only apply to + * backwards problems, where we might have, say, a call and a goto flow into a return site. */ Iterator getNormalSuccessors(T call); /** - * @param call - * a "call" node in the supergraph - * @return the corresponding return nodes. There may be many, because of - * exceptional control flow. + * @param call a "call" node in the supergraph + * @param callee a "called" "procedure" in the supergraph. if callee is null, answer return sites for which no callee was found. + * @return the corresponding return nodes. There may be many, because of exceptional control flow. */ - Iterator getReturnSites(T call); + Iterator getReturnSites(T call, P callee); /** - * @param r - * a "return" node in the supergraph + * @param r a "return" node in the supergraph + * @param callee a "called" "procedure" in the supergraph. if callee is null, answer return sites for which no callee was found. * @return the corresponding call nodes. There may be many. */ - Iterator getCallSites(T r); + Iterator getCallSites(T ret, P callee); /** - * @param n - * a node in the supergraph + * @param n a node in the supergraph * @return true iff this node is an exit node */ boolean isExit(T n); /** - * @param n - * a node in the supergraph + * @param n a node in the supergraph * @return an object which represents the procedure which contains n */ P getProcOf(T n); /** - * @return the blocks in the supergraph that represents entry nodes for - * procedure p + * @return the blocks in the supergraph that represents entry nodes for procedure p */ T[] getEntriesForProcedure(P procedure); - + /** - * @return the blocks in the supergraph that represents exit nodes for - * procedure p + * @return the blocks in the supergraph that represents exit nodes for procedure p */ T[] getExitsForProcedure(P procedure); /** - * @param procedure - * an object that represents a procedure + * @param procedure an object that represents a procedure * @return the number of blocks from this procedure in this supergraph */ int getNumberOfBlocks(P procedure); /** - * @param n - * a node in the supergraph + * @param n a node in the supergraph * @return the "logical" basic block number of n in its procedure */ int getLocalBlockNumber(T n); /** - * @param procedure - * an object that represents a procedure - * @param i - * the "logical" basic block number of a node in the procedure + * @param procedure an object that represents a procedure + * @param i the "logical" basic block number of a node in the procedure * @return the corresponding node in the supergraph */ T getLocalBlock(P procedure, int i); /** - * @param n - * a node in this supergraph + * @param n a node in this supergraph * @return true iff this node is a return site. */ boolean isReturn(T n); @@ -148,10 +130,8 @@ public interface ISupergraph extends NumberedGraph { boolean isEntry(T n); /** - * @param src - * node in the supergraph - * @param dest - * a successor of src in the supergraph + * @param src node in the supergraph + * @param dest a successor of src in the supergraph * @return one of CALL_EDGE, RETURN_EDGE, CALL_TO_RETURN_EDGE, or OTHER */ byte classifyEdge(T src, T dest); diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyCollapsedSupergraph.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyCollapsedSupergraph.java index 4513075f4..cbf656d20 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyCollapsedSupergraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PartiallyCollapsedSupergraph.java @@ -56,8 +56,14 @@ import com.ibm.wala.util.intset.MutableSparseIntSet; * This graph is an InterproceduralCFG for uncollapsible nodes, hooked up to * collapsed nodes. * + * This class is deprecated. It's quite a kludge, and likely not worth the constant-time + * speedup for most applications. I don't have any tests exercising this right now, so + * it may be rotting. Clients that use this should probably migrate to a simpler + * supergraph. + * * @author sfink */ +@Deprecated public class PartiallyCollapsedSupergraph extends AbstractGraph implements ISupergraph { /** @@ -235,8 +241,11 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph implemen return new FilterIterator(edgeManager.getSuccNodes(n), isEntry); } + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object, java.lang.Object) + */ @SuppressWarnings("unchecked") - public Iterator getReturnSites(Object object) { + public Iterator getReturnSites(Object object, CGNode callee) { if (object instanceof BasicBlockInContext) { return partialIPFG.getReturnSites((BasicBlockInContext) object); } else { @@ -245,10 +254,13 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph implemen } } + /* + * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object, java.lang.Object) + */ @SuppressWarnings("unchecked") - public Iterator getCallSites(Object object) { + public Iterator getCallSites(Object object, CGNode callee) { if (object instanceof BasicBlockInContext) { - return partialIPFG.getCallSites((BasicBlockInContext) object); + return partialIPFG.getCallSites((BasicBlockInContext) object, callee); } else { CGNode n = nodeManager.getProcOfCollapsedNode(object); return new NonNullSingletonIterator(nodeManager.getCollapsedEntry(n)); @@ -305,7 +317,7 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph implemen // add an edge from n_exit -> return sites Object e_n = nodeManager.getCollapsedExit(n); - for (Iterator returnSites = getReturnSites(bb); returnSites.hasNext();) { + for (Iterator returnSites = getReturnSites(bb, n); returnSites.hasNext();) { Object ret = returnSites.next(); Set in = MapUtil.findOrCreateSet(incomingTransverseEdges, ret); in.add(e_n); @@ -509,7 +521,7 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph implemen HashSet result = HashSetFactory.make(4); for (Iterator it = getPredNodes(entry); it.hasNext();) { Object callSite = it.next(); - for (Iterator returnSites = getReturnSites(callSite); returnSites.hasNext();) { + for (Iterator returnSites = getReturnSites(callSite, n); returnSites.hasNext();) { result.add(returnSites.next()); } } @@ -560,7 +572,7 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph implemen BimodalMutableIntSet result = new BimodalMutableIntSet(); for (Iterator it = getPredNodes(entry); it.hasNext();) { Object callSite = it.next(); - for (Iterator returnSites = getReturnSites(callSite); returnSites.hasNext();) { + for (Iterator returnSites = getReturnSites(callSite, n); returnSites.hasNext();) { result.add(getNumber(returnSites.next())); } } diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java index 5098ff70f..303fedabf 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java @@ -377,7 +377,6 @@ public class TabulationSolver { * @param D4 set of d1 s.t. -> was recorded as call flow */ private void propagateToReturnSites(final PathEdge edge, IntSet succ, final T c, final IntSet D4) { - if (DEBUG_LEVEL > 1) { System.err.println("Successor nodes: " + succ); for (IntIterator it = succ.intIterator(); it.hasNext();) { @@ -394,7 +393,7 @@ public class TabulationSolver { // note that we might have different summary edges for each // potential return site, and different flow functions from this // exit block to each return site. - for (Iterator retSites = supergraph.getReturnSites(c); retSites.hasNext();) { + for (Iterator retSites = supergraph.getReturnSites(c, supergraph.getProcOf(edge.target)); retSites.hasNext();) { final T retSite = retSites.next(); if (DEBUG_LEVEL > 1) { System.err.println("candidate return site: " + retSite + " " + supergraph.getNumber(retSite)); @@ -539,9 +538,10 @@ public class TabulationSolver { // c:= number of the call node final int c = supergraph.getNumber(edge.target); - - final Collection returnSites = Iterator2Collection.toCollection(supergraph.getReturnSites(edge.target)); + Collection allReturnSites = HashSetFactory.make(); + // populate allReturnSites with return sites for missing calls. + allReturnSites.addAll(Iterator2Collection.toCollection(supergraph.getReturnSites(edge.target, null))); // [14 - 16] for (Iterator it = supergraph.getCalledNodes(edge.target); it.hasNext();) { final T callee = it.next(); @@ -549,6 +549,8 @@ public class TabulationSolver { System.err.println(" process callee: " + callee); } MutableSparseIntSet reached = MutableSparseIntSet.makeEmpty(); + final Collection returnSites = Iterator2Collection.toCollection(supergraph.getReturnSites(edge.target, supergraph.getProcOf(callee))); + allReturnSites.addAll(returnSites); // we modify this to handle each return site individually. Some types of problems // compute different flow functions for each return site. for (final T returnSite : returnSites) { @@ -644,6 +646,9 @@ public class TabulationSolver { } IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.target, m); IntSet D3 = computeFlow(edge.d2, f); + if (DEBUG_LEVEL > 0) { + System.err.println("normal successor reached: " + D3); + } if (D3 != null) { D3.foreach(new IntSetAction() { public void act(int d3) { @@ -655,7 +660,7 @@ public class TabulationSolver { // [17 - 19] // we modify this to handle each return site individually - for (final T returnSite : returnSites) { + for (final T returnSite : allReturnSites) { if (DEBUG_LEVEL > 0) { System.err.println(" process return site: " + returnSite); } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/cfg/AbstractInterproceduralCFG.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/cfg/AbstractInterproceduralCFG.java index c7c0b5875..0d8ab2c62 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/cfg/AbstractInterproceduralCFG.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/cfg/AbstractInterproceduralCFG.java @@ -56,8 +56,8 @@ public abstract class AbstractInterproceduralCFG imple private static final int DEBUG_LEVEL = 0; /** - * Should the graph include call-to-return edges? - * When set to false, the graphs output by {@link IFDSExplorer} look incorrect + * Should the graph include call-to-return edges? When set to false, the graphs output by + * {@link IFDSExplorer} look incorrect */ private final static boolean CALL_TO_RETURN_EDGES = true; @@ -606,37 +606,54 @@ public abstract class AbstractInterproceduralCFG imple } /** - * @param bb node in the IPCFG that ends in a call + * @param callBlock node in the IPCFG that ends in a call * @return the nodes that are return sites for this call. * @throws IllegalArgumentException if bb is null */ - public Iterator getReturnSites(BasicBlockInContext bb) { - if (bb == null) { + public Iterator getReturnSites(BasicBlockInContext callBlock) { + if (callBlock == null) { throw new IllegalArgumentException("bb is null"); } - final CGNode node = bb.getNode(); + final CGNode node = callBlock.getNode(); // a successor node is a return site if it is in the same // procedure, and is not the entry() node. Filter isReturn = new Filter() { public boolean accepts(Object o) { - if (Assertions.verifyAssertions) { - Assertions._assert(o instanceof BasicBlockInContext); - } BasicBlockInContext other = (BasicBlockInContext) o; return !other.isEntryBlock() && node.equals(other.getNode()); } }; - return new FilterIterator(getSuccNodes(bb), isReturn); + return new FilterIterator(getSuccNodes(callBlock), isReturn); } - public Iterator> getCallSites(BasicBlockInContext bb) { - if (bb == null) { + /** + * get the basic blocks which are call sites that may call callee and return to returnBlock if callee is null, answer + * return sites for which no callee was found. + */ + public Iterator> getCallSites(BasicBlockInContext returnBlock, final CGNode callee) { + if (returnBlock == null) { throw new IllegalArgumentException("bb is null"); } - ControlFlowGraph cfg = getCFG(bb); - Iterator it = cfg.getPredNodes(bb.getDelegate()); - final CGNode node = bb.getNode(); + final ControlFlowGraph cfg = getCFG(returnBlock); + Iterator it = cfg.getPredNodes(returnBlock.getDelegate()); + final CGNode node = returnBlock.getNode(); + + Filter dispatchFilter = new Filter() { + public boolean accepts(T callBlock) { + BasicBlockInContext bb = new BasicBlockInContext(node, callBlock); + if (!hasCall(bb, cfg)) { + return false; + } + if (callee != null) { + return getCallTargets(bb).contains(callee); + } else { + return getCallTargets(bb).isEmpty(); + } + } + }; + it = new FilterIterator(it, dispatchFilter); + Function> toContext = new Function>() { public BasicBlockInContext apply(T object) { T b = object; diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SDGSupergraph.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SDGSupergraph.java index 042bcf93e..0c6aceca9 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SDGSupergraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SDGSupergraph.java @@ -63,7 +63,7 @@ class SDGSupergraph implements ISupergraph { /* * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object) */ - public Iterator getCallSites(Statement r) { + public Iterator getCallSites(Statement r, PDG callee) { switch (r.getKind()) { case EXC_RET_CALLER: { ExceptionalReturnCaller n = (ExceptionalReturnCaller) r; @@ -183,7 +183,7 @@ class SDGSupergraph implements ISupergraph { /* * @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object) */ - public Iterator getReturnSites(Statement call) { + public Iterator getReturnSites(Statement call, PDG callee) { switch (call.getKind()) { case PARAM_CALLER: { ParamCaller n = (ParamCaller) call;