From 27f886b7af89b17c30f2904a6d94d0b0c0915efb Mon Sep 17 00:00:00 2001 From: sjfink Date: Wed, 30 Apr 2008 13:59:51 +0000 Subject: [PATCH] restructure tabulation with multiple return sites. delete some obsolete ExplodedSupergraph crud. git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@2773 f5eafffb-2e1d-0410-98e4-8ec43c5233c4 --- .../dataflow/IFDS/ExplodedSupergraph.java | 259 ---------- .../dataflow/IFDS/ExplodedSupergraphNode.java | 70 --- .../dataflow/IFDS/ExplodedSupergraphPath.java | 472 ------------------ .../ExplodedSupergraphWithSummaryEdges.java | 115 ----- .../wala/dataflow/IFDS/IFlowFunctionMap.java | 29 +- .../dataflow/IFDS/IdentityFlowFunctions.java | 5 + .../wala/dataflow/IFDS/TabulationSolver.java | 24 +- .../IFDS/UniversalKillFlowFunction.java | 3 + .../ipa/slicer/ReachabilityFunctions.java | 5 + .../ibm/wala/ipa/slicer/SliceFunctions.java | 4 +- 10 files changed, 47 insertions(+), 939 deletions(-) delete mode 100644 com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraph.java delete mode 100644 com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphNode.java delete mode 100644 com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphPath.java delete mode 100644 com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphWithSummaryEdges.java diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraph.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraph.java deleted file mode 100644 index 583289f49..000000000 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraph.java +++ /dev/null @@ -1,259 +0,0 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.HashSet; -import java.util.Iterator; - -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.UnimplementedError; -import com.ibm.wala.util.graph.Graph; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; - -/** - * - * A view of a supergraph as an exploded supergraph. - * - * Nodes are ExplodedSupergraphNodes. Edges are edges as realized by IFDS flow - * functions; - * - * Note: not terribly efficient, use with care. - * - * @author sfink - */ -public class ExplodedSupergraph implements Graph> { - - private final ISupergraph supergraph; - - private final IFlowFunctionMap flowFunctions; - - public ExplodedSupergraph(ISupergraph supergraph, IFlowFunctionMap flowFunctions) { - this.supergraph = supergraph; - this.flowFunctions = flowFunctions; - } - - public void removeNodeAndEdges(ExplodedSupergraphNode N) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public Iterator> iterator() throws UnimplementedError { - Assertions.UNREACHABLE(); - return null; - } - - public int getNumberOfNodes() throws UnimplementedError { - Assertions.UNREACHABLE(); - return 0; - } - - public void addNode(ExplodedSupergraphNode n) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - - } - - public void removeNode(ExplodedSupergraphNode n) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public boolean containsNode(ExplodedSupergraphNode N) throws UnimplementedError { - Assertions.UNREACHABLE(); - return false; - } - - public Iterator> getPredNodes(ExplodedSupergraphNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - T dest = node.getSupergraphNode(); - HashSet> result = HashSetFactory.make(supergraph.getPredNodeCount(dest)); - for (Iterator it = supergraph.getPredNodes(dest); it.hasNext();) { - T src = it.next(); - if (supergraph.classifyEdge(src, dest) != ISupergraph.RETURN_EDGE) { - IFlowFunction f = getFlowFunction(src, dest); - if (f instanceof IReversibleFlowFunction) { - IReversibleFlowFunction rf = (IReversibleFlowFunction) f; - IntSet sources = rf.getSources(node.getFact()); - if (sources != null) { - for (IntIterator ii = sources.intIterator(); ii.hasNext();) { - int t = ii.next(); - result.add(new ExplodedSupergraphNode(src, t)); - } - } - } else { - Assertions.UNREACHABLE("need to implement for non-reversible flow function " + f.getClass()); - } - } else { - // special logic for a return edge. dest is a return site - for (Iterator it2 = supergraph.getCallSites(dest); it2.hasNext(); ) { - T callBlock = it2.next(); - IFlowFunction f = flowFunctions.getReturnFlowFunction(callBlock,src,dest); - if (f instanceof IReversibleFlowFunction) { - IReversibleFlowFunction rf = (IReversibleFlowFunction) f; - IntSet sources = rf.getSources(node.getFact()); - if (sources != null) { - for (IntIterator ii = sources.intIterator(); ii.hasNext();) { - int t = ii.next(); - result.add(new ExplodedSupergraphNode(src, t)); - } - } - } else { - Assertions.UNREACHABLE("need to implement for non-reversible flow function " + f.getClass()); - } - } - } - } - return result.iterator(); - } - - public int getPredNodeCount(ExplodedSupergraphNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - T dest = node.getSupergraphNode(); - int count = 0; - for (Iterator it = supergraph.getPredNodes(dest); it.hasNext();) { - T src = it.next(); - if (supergraph.classifyEdge(src, dest) != ISupergraph.RETURN_EDGE) { - IFlowFunction f = getFlowFunction(src, dest); - if (f instanceof IReversibleFlowFunction) { - IReversibleFlowFunction rf = (IReversibleFlowFunction) f; - IntSet sources = rf.getSources(node.getFact()); - if (sources != null) { - count += sources.size(); - } - } else { - Assertions.UNREACHABLE("need to implement for non-reversible flow function"); - } - } else { - // special logic for a return edge - Assertions.UNREACHABLE("TODO: Implement me!"); - } - } - return count; - } - - public Iterator> getSuccNodes(ExplodedSupergraphNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - T src = node.getSupergraphNode(); - HashSet> result = HashSetFactory.make(supergraph.getSuccNodeCount(src)); - for (Iterator it = supergraph.getSuccNodes(src); it.hasNext();) { - T dest = it.next(); - if (supergraph.classifyEdge(src, dest) != ISupergraph.RETURN_EDGE) { - IUnaryFlowFunction f = (IUnaryFlowFunction) getFlowFunction(src, dest); - IntSet targets = f.getTargets(node.getFact()); - if (targets != null) { - for (IntIterator ii = targets.intIterator(); ii.hasNext();) { - int t = ii.next(); - result.add(new ExplodedSupergraphNode(dest, t)); - } - } - } else { - // special logic for a return edge. dest is a return site - for (Iterator it2 = supergraph.getCallSites(dest); it2.hasNext(); ) { - T callBlock = it2.next(); - IUnaryFlowFunction f = (IUnaryFlowFunction) flowFunctions.getReturnFlowFunction(callBlock,src,dest); - IntSet targets = f.getTargets(node.getFact()); - if (targets != null) { - for (IntIterator ii = targets.intIterator(); ii.hasNext();) { - int t = ii.next(); - result.add(new ExplodedSupergraphNode(dest, t)); - } - } - } - } - } - return result.iterator(); - } - - private IFlowFunction getFlowFunction(T src, T dest) { - switch (supergraph.classifyEdge(src, dest)) { - case ISupergraph.CALL_EDGE: - return flowFunctions.getCallFlowFunction(src, dest); - case ISupergraph.CALL_TO_RETURN_EDGE: - Iterator callees = supergraph.getCalledNodes(src); - if (callees.hasNext()) { - return flowFunctions.getCallToReturnFlowFunction(src, dest); - } else { - return flowFunctions.getCallNoneToReturnFlowFunction(src, dest); - } - case ISupergraph.RETURN_EDGE: - Assertions.UNREACHABLE(); - return null; - // return flowFunctions.getReturnFlowFunction(src, dest); - case ISupergraph.OTHER: - return flowFunctions.getNormalFlowFunction(src, dest); - default: - Assertions.UNREACHABLE(); - return null; - } - } - - public int getSuccNodeCount(ExplodedSupergraphNode node) { - if (node == null) { - throw new IllegalArgumentException("node is null"); - } - T src = node.getSupergraphNode(); - int count = 0; - for (Iterator it = supergraph.getSuccNodes(src); it.hasNext();) { - T dest = it.next(); - IUnaryFlowFunction f = (IUnaryFlowFunction) getFlowFunction(src, dest); - IntSet targets = f.getTargets(node.getFact()); - if (targets != null) { - count += targets.size(); - } - } - return count; - } - - public void addEdge(ExplodedSupergraphNode src, ExplodedSupergraphNode dst) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void removeEdge(ExplodedSupergraphNode src, ExplodedSupergraphNode dst) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void removeAllIncidentEdges(ExplodedSupergraphNode node) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void removeIncomingEdges(ExplodedSupergraphNode node) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public void removeOutgoingEdges(ExplodedSupergraphNode node) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public boolean hasEdge(ExplodedSupergraphNode src, ExplodedSupergraphNode dst) { - for (Iterator it = getSuccNodes(src); it.hasNext();) { - if (it.next().equals(dst)) { - return true; - } - } - return false; - } - - public ISupergraph getSupergraph() { - return supergraph; - } - - /** - * @return Returns the flowFunctions. - */ - public IFlowFunctionMap getFlowFunctions() { - return flowFunctions; - } -} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphNode.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphNode.java deleted file mode 100644 index 8a27697cd..000000000 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphNode.java +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import com.ibm.wala.annotations.NonNull; - -/** - * A node in the exploded supergraph - * - * Note that this representation is inefficient and should be used with care. - * - * @author sfink - */ -public class ExplodedSupergraphNode { - - @NonNull - private final T supergraphNode; - - private final int fact; - - /** - * @param supergraphNode - * @param fact - */ - public ExplodedSupergraphNode(T supergraphNode, int fact) { - this.supergraphNode = supergraphNode; - this.fact = fact; - } - - @Override - public boolean equals(Object arg0) { - if (arg0 == null) { - return false; - } - if (getClass().equals(arg0.getClass())) { - ExplodedSupergraphNode other = (ExplodedSupergraphNode) arg0; - return supergraphNode.equals(other.supergraphNode) && fact == other.fact; - } else { - return false; - } - } - - @Override - public int hashCode() { - return 8353 * supergraphNode.hashCode() + fact; - } - - @Override - public String toString() { - return supergraphNode.toString() + "," + fact; - } - - public int getFact() { - return fact; - } - - public T getSupergraphNode() { - return supergraphNode; - } - - -} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphPath.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphPath.java deleted file mode 100644 index 1aa59ec20..000000000 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphPath.java +++ /dev/null @@ -1,472 +0,0 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Stack; - -import com.ibm.wala.ipa.callgraph.CGNode; -import com.ibm.wala.util.collections.CollectionFilter; -import com.ibm.wala.util.collections.Filter; -import com.ibm.wala.util.collections.FilterIterator; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Pair; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.Trace; -import com.ibm.wala.util.graph.impl.GraphInverter; -import com.ibm.wala.util.graph.traverse.BFSPathFinder; - -/** - * - * A realizable path in the exploded supergraph - * - * @author sfink - */ -public class ExplodedSupergraphPath { - - private static final boolean DEBUG = false; - - /** - * List - */ - private final List> outermostList; - - /** - * Map: Pair -> List - * for any call-to-return edge, we memoize a List which holds a SLVP by which - * the callee gets to the return site. - */ - private final Map>> edge2SLVP = HashMapFactory.make(); - - /** - * Should we skip over boring calls when iterating? - */ - private boolean skipBoringCalls = false; - - private final ExplodedSupergraphWithSummaryEdges esg; - - /** - * @param nodeList - */ - private ExplodedSupergraphPath(List> nodeList, ExplodedSupergraphWithSummaryEdges esg) { - this.outermostList = nodeList; - this.esg = esg; - } - - /** - * @author sfink - * - * warning: these paths can be exponentially long - */ - private final class PathIterator implements Iterator { - - final private Iterator it; - - public void remove() { - Assertions.UNREACHABLE(); - } - - PathIterator() { - // Trace.println(ExplodedSupergraphPath.this); - // callStack holds the set of caller nodes currently on the call - // stack - Stack callStack = new Stack(); - List> L = new ArrayList>(outermostList); - for (int i = 0; i < L.size() - 1; i++) { - ExplodedSupergraphNode src = L.get(i); - ExplodedSupergraphNode dest = L.get(i + 1); - if (esg.getSupergraph().isExit(src.getSupergraphNode())) { - if (!callStack.isEmpty()) { - callStack.pop(); - } - } else { - if (skipBoringCalls && src.getFact() == dest.getFact()) { - continue; - } else if (esg.getSupergraph().isCall(src.getSupergraphNode()) - && esg.getSupergraph().getProcOf(src.getSupergraphNode()).equals( - esg.getSupergraph().getProcOf(dest.getSupergraphNode()))) { - CGNode srcNode = (CGNode) esg.getSupergraph().getProcOf(src.getSupergraphNode()); - // avoid recursive path blowup - if (!callStack.contains(srcNode)) { - callStack.push(srcNode); - // splice the sublist into the main list. - List slvp = findOrCreateSLVP(src, dest, callStack); - if (slvp != null) { - L.addAll(i + 1, findOrCreateSLVP(src, dest, callStack)); - } - } - } - } - } - it = L.iterator(); - } - - public boolean hasNext() { - return it.hasNext(); - } - - public Object next() { - return it.next(); - } - } - - /** - * @param callStack Stack which should not be traversed into - * @return null if none found - */ - private List> findOrCreateSLVP(ExplodedSupergraphNode src, ExplodedSupergraphNode dest, Stack callStack) { - Pair p = Pair.make(src, dest); - List> l = edge2SLVP.get(p); - // a bit of a hack ... give up on some memoization - if (l != null && !validInCallStack(l, callStack)) { - l = null; - } - if (l == null) { - l = computeSummarySLVP(src, dest, callStack); - if (l != null) { - // we might fail to find a path due to limitations in - // how we cope with reflection - edge2SLVP.put(p, l); - } - } - return l; - } - - /** - * a List of nodes is "valid" for a particular callStack iff none of the call - * nodes in the list originate from a node in the call Stack - * - * @param l - * a list of ExplodedSupergraphNode - * @param callStack - * Collection - */ - private boolean validInCallStack(List> l, Stack callStack) { - Iterator> it = l.iterator(); - while (it.hasNext()) { - ExplodedSupergraphNode src = it.next(); - if (callStack.contains(esg.getSupergraph().getProcOf(src.getSupergraphNode()))) { - return false; - } - } - return true; - } - - /** - * @return Iterator - */ - public Iterator iterator() { - return new PathIterator(); - } - - /** - * A filter which accepts exploded supergraph nodes with the universal (0) - * factoid. - */ - private final static Filter zeroFactFilter = new Filter() { - public boolean accepts(Object o) { - ExplodedSupergraphNode node = (ExplodedSupergraphNode) o; - return node.getFact() == 0; - } - - }; - - /** - * This object traverses an exploded supergraph with summary edges from a set - * of sources, until it finds a sink. - * - * During this traversal, it will NOT traverse interprocedural - * edges - * - * @author sfink - * - */ - static class SLVPFinder extends BFSPathFinder> { - final ExplodedSupergraphWithSummaryEdges esg; - - final Collection exclusions; - - SLVPFinder(ExplodedSupergraphWithSummaryEdges esg, Collection> sources, Collection> sinks, Collection exclusions) { - super(esg, sources.iterator(), new CollectionFilter>(sinks)); - this.esg = esg; - this.exclusions = exclusions; - // Trace.println("FINDER"); - // Trace.printCollection("sources", sources); - // Trace.printCollection("sinks", sinks); - // Trace.printCollection("exclusions", exclusions); - } - - @Override - protected Iterator> getConnected(final ExplodedSupergraphNode n) { - - return new FilterIterator>(super.getConnected(n), new Filter() { - @SuppressWarnings("unchecked") - public boolean accepts(Object o) { - ExplodedSupergraphNode dest = (ExplodedSupergraphNode) o; - // if (exclusions.contains(new Pair(src, dest))) { - // Trace.println("exclude " + src + " , " + dest); - // } - return sameProc(n, dest) && !exclusions.contains(esg.getSupergraph().getProcOf(n.getSupergraphNode())); - } - }); - - } - - private final boolean sameProc(ExplodedSupergraphNode a, ExplodedSupergraphNode b) { - final PartiallyCollapsedSupergraph supergraph = (PartiallyCollapsedSupergraph) esg.getSupergraph(); - return supergraph.getProcOf(a.getSupergraphNode()).equals(supergraph.getProcOf(b.getSupergraphNode())); - } - - @Override - public List> find() { - List> L = super.find(); - if (L == null) { - return L; - } else { - Collections.reverse(L); - return L; - } - } - } - - /** - * This object traverses an exploded supergraph with summary edges - * backwards from a sink, until it finds an node with the universal - * (0) factoid. - * - * During this traversal, it will NOT traverse return edges from a - * caller into the callee. Thus the returned path will only go UP the call - * stack, and never down. - * - * Note that we're guaranteed to find some universal factoid since - * exists. - * - * @author sfink - * - */ - static class NoReturnBackwardsPathFinder extends BFSPathFinder> { - final ExplodedSupergraphWithSummaryEdges esg; - - @SuppressWarnings("unchecked") - NoReturnBackwardsPathFinder(ExplodedSupergraphWithSummaryEdges esg, ExplodedSupergraphNode sink) { - super(GraphInverter.invert(esg), Collections.singleton(sink).iterator(), zeroFactFilter); - this.esg = esg; - } - - @Override - protected Iterator> getConnected(ExplodedSupergraphNode n) { - ExplodedSupergraphNode src = n; - PartiallyCollapsedSupergraph supergraph = (PartiallyCollapsedSupergraph) esg.getSupergraph(); - HashSet> result = HashSetFactory.make(esg.getPredNodeCount(n)); - // add facts from non-call exploded supergraph edges - for (Iterator> it = super.getConnected(n); it.hasNext();) { - ExplodedSupergraphNode dest = it.next(); - // remember that we're traversing the graph backwards! - switch (supergraph.classifyEdge(dest.getSupergraphNode(), src.getSupergraphNode())) { - case ISupergraph.RETURN_EDGE: - if (DEBUG) { - Trace.println("Exclude edge " + src + " " + dest); - } - // do nothing - break; - default: - result.add(dest); - break; - } - } - if (DEBUG) { - Trace.printCollection("getConnected " + n, result); - if (result.size() == 0) { - if (n.toString().indexOf("BB[SSA]0") > -1) { - if (n.toString().indexOf("k.read()I") > -1) { - Iterator x = super.getConnected(n); - System.err.println(x); - } - } - } - } - return result.iterator(); - } - } - - /** - * Find a realizable path in the exploded supergraph to a sink node, from any - * exploded supergraph node which represents the universal (0) factoid. - * - * @return an ExplodedSupergraphPath found, or null if not found. - */ - public static ExplodedSupergraphPath findRealizablePath(ExplodedSupergraphWithSummaryEdges esg, ExplodedSupergraphNode sink) { - BFSPathFinder> backwardsFinder = new NoReturnBackwardsPathFinder(esg, sink); - if (DEBUG) { - Trace.println("find path to sink " + sink); - } - - List> L = backwardsFinder.find(); - - if (DEBUG) { - Trace.println("got backwards path " + new ExplodedSupergraphPath(L, esg)); - } - if (L == null) { - return null; - } - ExplodedSupergraphPath result = new ExplodedSupergraphPath(L, esg); - return result; - } - - /** - * for a call-to-return edge , return a List which holds a SLVP by - * which the callee gets to the return site. - * - * Note: During the traversal, exclude any edges which are already in the call - * stack. - * - * @return null if search fails to find a path - * - */ - private List> computeSummarySLVP(ExplodedSupergraphNode src, ExplodedSupergraphNode dest, Collection callStack) { - - // calledTargets := exploded nodes that are reached from the src by a - // call. - HashSet> calledTargets = HashSetFactory.make(3); - for (Iterator> it = esg.getSuccNodes(src); it.hasNext();) { - ExplodedSupergraphNode target = it.next(); - if (esg.getSupergraph().classifyEdge(src.getSupergraphNode(), target.getSupergraphNode()) == ISupergraph.CALL_EDGE) { - calledTargets.add(target); - } - } - - HashSet> calledExitNodes = HashSetFactory.make(3); - for (Iterator> it = esg.getPredNodes(dest); it.hasNext();) { - ExplodedSupergraphNode target = it.next(); - if (esg.getSupergraph().classifyEdge(target.getSupergraphNode(), dest.getSupergraphNode()) == ISupergraph.RETURN_EDGE) { - calledExitNodes.add(target); - } - } - - if (calledTargets.isEmpty() || calledExitNodes.isEmpty()) { - return null; - } else { - if (DEBUG) { - Trace.println("fill in summary: " + src + " -> " + dest); - Trace.printCollection("calledTargets ", calledTargets); - } - // find a path from any calledTarget to the dest. - SLVPFinder innerFinder = new SLVPFinder(esg, calledTargets, calledExitNodes, callStack); - List> subList = innerFinder.find(); - // under current algorithm subList might be null due to - // failures to handle reflection well. - // if (Assertions.verifyAssertions) { - // Assertions._assert(subList != null); - // } - if (DEBUG) { - if (subList == null) { - Trace.println("null sublist"); - } else { - Trace.printCollection("subList ", subList); - } - } - return subList; - } - } - - @Override - public String toString() { - - StringBuffer result = new StringBuffer("Outermost List: \n"); - if (outermostList == null) { - return "null outermost list"; - } - appendNumberedList(result, outermostList.iterator()); - for (Iterator it = edge2SLVP.entrySet().iterator(); it.hasNext();) { - Map.Entry e = (Map.Entry) it.next(); - Pair p = (Pair) e.getKey(); - result.append("SLVP for " + p + "\n"); - List l = (List) e.getValue(); - appendNumberedList(result, l.iterator()); - } - return result.toString(); - } - - private void appendNumberedList(StringBuffer result, Iterator it) { - int i = 0; - while (it.hasNext()) { - i++; - ExplodedSupergraphNode n = (ExplodedSupergraphNode) it.next(); - result.append(i + " " + n + "\n"); - } - } - - /** - * Create a brief(er) summary of a path, which includes: 1) only call and - * return nodes, and 2) excludes call/return pairs in which no state - * transitions occur - */ - public static ExplodedSupergraphPath summarize(ISupergraph supergraph, ExplodedSupergraphPath path) { - pruneForCallReturn(supergraph, path); - pruneBoringCalls(path); - return path; - } - - /** - * Create a briefer summary of a path, which excludes call/return pairs in - * which no state transitions occur - * @throws IllegalArgumentException if path is null - */ - public static void pruneBoringCalls(ExplodedSupergraphPath path) { - if (path == null) { - throw new IllegalArgumentException("path is null"); - } - path.skipBoringCalls = true; - } - - /** - * Create a brief(er) summary of a path, which includes only call and return - * nodes - * @throws IllegalArgumentException if path is null - */ - public static void pruneForCallReturn(ISupergraph supergraph, ExplodedSupergraphPath path) { - if (path == null) { - throw new IllegalArgumentException("path is null"); - } - pruneListForCallReturn(supergraph, path.outermostList); - for (Iterator>> it = path.edge2SLVP.values().iterator(); it.hasNext();) { - List> l = it.next(); - pruneListForCallReturn(supergraph, l); - } - } - - /** - * Create a brief(er) summary of a path, which includes only call and return - * nodes - * @throws IllegalArgumentException if L == null - */ - public static List> pruneListForCallReturn(ISupergraph supergraph, List> L) throws IllegalArgumentException { - if (L == null) { - throw new IllegalArgumentException("L == null"); - } - for (int i = 0; i < L.size(); i++) { - ExplodedSupergraphNode n = L.get(i); - if (!supergraph.isEntry(n.getSupergraphNode()) && !supergraph.isExit(n.getSupergraphNode()) - && !supergraph.isCall(n.getSupergraphNode()) && !supergraph.isReturn(n.getSupergraphNode())) { - L.remove(i); - i--; - } - } - return L; - } -} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphWithSummaryEdges.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphWithSummaryEdges.java deleted file mode 100644 index 9a2ae31da..000000000 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/ExplodedSupergraphWithSummaryEdges.java +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************* - * 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.dataflow.IFDS; - -import java.util.HashSet; -import java.util.Iterator; - -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.collections.Iterator2Collection; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.intset.IntIterator; -import com.ibm.wala.util.intset.IntSet; - -/** - * This version of the exploded supergraph includes summary edges as deduced by - * the tabulation solver - * - * @author sfink - * - */ -public class ExplodedSupergraphWithSummaryEdges extends ExplodedSupergraph { - - private final TabulationSolver solver; - - /** - * @param supergraph - * @param flowFunctions - * @param solver - */ - public ExplodedSupergraphWithSummaryEdges(ISupergraph supergraph, IFlowFunctionMap flowFunctions, - TabulationSolver solver) { - super(supergraph, flowFunctions); - this.solver = solver; - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ExplodedSupergraph#getSuccNodes(java.lang.Object) - */ - @Override - public Iterator> getSuccNodes(ExplodedSupergraphNode src) { - if (src == null) { - throw new IllegalArgumentException("src is null"); - } - HashSet> result = HashSetFactory.make(5); - result.addAll(Iterator2Collection.toCollection(super.getSuccNodes(src))); - - // add facts from summary edges - if (getSupergraph().isCall(src.getSupergraphNode())) { - for (Iterator it = getSupergraph().getReturnSites(src.getSupergraphNode()); it.hasNext();) { - T dest = it.next(); - Assertions.UNREACHABLE(); - IntSet summary = null; -// IntSet summary = solver.getSummaryTargets(src.getSupergraphNode(), src.getFact(), dest); - if (summary != null) { - for (IntIterator ii = summary.intIterator(); ii.hasNext();) { - int d2 = ii.next(); - result.add(new ExplodedSupergraphNode(dest, d2)); - } - } - } - } - return result.iterator(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ExplodedSupergraph#getPredNodes(java.lang.Object) - */ - @Override - public Iterator> getPredNodes(ExplodedSupergraphNode dest) { - if (dest == null) { - throw new IllegalArgumentException("dest is null"); - } - HashSet> result = HashSetFactory.make(5); - result.addAll(Iterator2Collection.toCollection(super.getPredNodes(dest))); - - // add facts from summary edges - if (getSupergraph().isReturn(dest.getSupergraphNode())) { - for (Iterator it = getSupergraph().getCallSites(dest.getSupergraphNode()); it.hasNext();) { - T src = it.next(); - IntSet summary = solver.getSummarySources(dest.getSupergraphNode(), dest.getFact(), src); - if (summary != null) { - for (IntIterator ii = summary.intIterator(); ii.hasNext();) { - int d1 = ii.next(); - result.add(new ExplodedSupergraphNode(src, d1)); - } - } - } - } - return result.iterator(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ExplodedSupergraph#getPredNodeCount(java.lang.Object) - */ - @Override - public int getPredNodeCount(ExplodedSupergraphNode N) { - return Iterator2Collection.toCollection(getPredNodes(N)).size(); - } - - /* - * @see com.ibm.wala.dataflow.IFDS.ExplodedSupergraph#getSuccNodeCount(java.lang.Object) - */ - @Override - public int getSuccNodeCount(ExplodedSupergraphNode N) { - return Iterator2Collection.toCollection(getSuccNodes(N)).size(); - } -} diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunctionMap.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunctionMap.java index 177105841..6f657347b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunctionMap.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IFlowFunctionMap.java @@ -23,44 +23,39 @@ public interface IFlowFunctionMap { /** * @param src * @param dest - * @return the flow function for a "normal" edge in the supergraph from - * src->dest + * @return the flow function for a "normal" edge in the supergraph from src->dest */ public IUnaryFlowFunction getNormalFlowFunction(T src, T dest); /** - * @param src - * @param dest - * @return the flow function for a "call" edge in the supergraph from - * src->dest + * @param src the call block + * @param dest the entry of the callee + * @param ret the block that will be returned to, in the caller. This can be null .. signifying that facts can flow + * into the callee but not return + * @return the flow function for a "call" edge in the supergraph from src->dest */ - public IUnaryFlowFunction getCallFlowFunction(T src, T dest); + public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret); /** - * @param call - * supergraph node of the call instruction for this return edge. + * @param call supergraph node of the call instruction for this return edge. * @param src * @param dest - * @return the flow function for a "return" edge in the supergraph from - * src->dest + * @return the flow function for a "return" edge in the supergraph from src->dest */ public IFlowFunction getReturnFlowFunction(T call, T src, T dest); - /** * @param src * @param dest - * @return the flow function for a "call-to-return" edge in the supergraph - * from src->dest + * @return the flow function for a "call-to-return" edge in the supergraph from src->dest */ public IUnaryFlowFunction getCallToReturnFlowFunction(T src, T dest); /** * @param src * @param dest - * @return the flow function for a "call-to-return" edge in the supergraph - * from src->dest, when the supergraph does not contain any callees of - * src. This happens via, e.g., slicing. + * @return the flow function for a "call-to-return" edge in the supergraph from src->dest, when the supergraph does + * not contain any callees of src. This happens via, e.g., slicing. */ public IUnaryFlowFunction getCallNoneToReturnFlowFunction(T src, T dest); } diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunctions.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunctions.java index 0fc2e3f12..c06226fe8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunctions.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/IdentityFlowFunctions.java @@ -38,6 +38,7 @@ public class IdentityFlowFunctions implements IFlowFunctionMap { /* * @see com.ibm.wala.dataflow.IFDS.IFlowFunctionMap#getCallFlowFunction(java.lang.Object, java.lang.Object) */ + @Deprecated public IUnaryFlowFunction getCallFlowFunction(T src, T dest) { return IdentityFlowFunction.identity(); } @@ -70,4 +71,8 @@ public class IdentityFlowFunctions implements IFlowFunctionMap { return IdentityFlowFunction.identity(); } + public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret) { + return IdentityFlowFunction.identity(); + } + } 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 4338209d3..5098ff70f 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 @@ -541,16 +541,32 @@ public class TabulationSolver { final int c = supergraph.getNumber(edge.target); final Collection returnSites = Iterator2Collection.toCollection(supergraph.getReturnSites(edge.target)); - + // [14 - 16] for (Iterator it = supergraph.getCalledNodes(edge.target); it.hasNext();) { final T callee = it.next(); if (DEBUG_LEVEL > 0) { System.err.println(" process callee: " + callee); } - IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.target, callee); + MutableSparseIntSet reached = MutableSparseIntSet.makeEmpty(); + // 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) { + IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.target, callee, returnSite); + // reached := {d1} that reach the callee + IntSet r = computeFlow(edge.d2, f); + if (r != null) { + reached.addAll(r); + } + } + // in some problems, we also want to consider flow into a callee that can never flow out + // via a return. in this case, the return site is null. + IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.target, callee, null); // reached := {d1} that reach the callee - IntSet reached = computeFlow(edge.d2, f); + IntSet r = computeFlow(edge.d2, f); + if (r != null) { + reached.addAll(r); + } if (DEBUG_LEVEL > 0) { System.err.println(" reached: " + reached); } @@ -968,7 +984,7 @@ public class TabulationSolver { @SuppressWarnings("unchecked") @Override protected boolean compareElements(PathEdge p1, PathEdge p2) { - return problem.getDomain().hasPriorityOver(p1, p2); + return problem.getDomain().hasPriorityOver(p1, p2); } } diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/UniversalKillFlowFunction.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/UniversalKillFlowFunction.java index 3bb1a8d87..6ce40f227 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/UniversalKillFlowFunction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/UniversalKillFlowFunction.java @@ -18,8 +18,11 @@ import com.ibm.wala.util.intset.SparseIntSet; * * TODO: optimize by building this edge as implicit in every flow function. * + * This is deprecated ... it's confusing and non-general. + * * @author sfink */ +@Deprecated public class UniversalKillFlowFunction implements IReversibleFlowFunction { private final static UniversalKillFlowFunction singleton = new UniversalKillFlowFunction(); diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/ReachabilityFunctions.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/ReachabilityFunctions.java index 709cf01a9..7d7d266ab 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/ReachabilityFunctions.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/ReachabilityFunctions.java @@ -46,6 +46,7 @@ public class ReachabilityFunctions implements IFlowFunctionMap { private ReachabilityFunctions() { } + @Deprecated public IUnaryFlowFunction getCallFlowFunction(T src, T dest) { return FLOW_REACHES; } @@ -74,4 +75,8 @@ public class ReachabilityFunctions implements IFlowFunctionMap { return FLOW_REACHES; } + public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret) { + return FLOW_REACHES; + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SliceFunctions.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SliceFunctions.java index e296f6e02..8aba0913f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SliceFunctions.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SliceFunctions.java @@ -24,8 +24,8 @@ import com.ibm.wala.util.debug.Assertions; */ public class SliceFunctions implements IPartiallyBalancedFlowFunctions { - public IUnaryFlowFunction getCallFlowFunction(Statement src, Statement dest) { - return ReachabilityFunctions.createReachabilityFunctions().getCallFlowFunction(src, dest); + public IUnaryFlowFunction getCallFlowFunction(Statement src, Statement dest, Statement ret) { + return ReachabilityFunctions.createReachabilityFunctions().getCallFlowFunction(src, dest, ret); } public IUnaryFlowFunction getCallNoneToReturnFlowFunction(Statement src, Statement dest) {