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
This commit is contained in:
sjfink 2008-04-30 13:59:51 +00:00
parent 96952cd431
commit 27f886b7af
10 changed files with 47 additions and 939 deletions

View File

@ -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<T> implements Graph<ExplodedSupergraphNode<T>> {
private final ISupergraph<T,?> supergraph;
private final IFlowFunctionMap<T> flowFunctions;
public ExplodedSupergraph(ISupergraph<T,?> supergraph, IFlowFunctionMap<T> flowFunctions) {
this.supergraph = supergraph;
this.flowFunctions = flowFunctions;
}
public void removeNodeAndEdges(ExplodedSupergraphNode N) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public Iterator<ExplodedSupergraphNode<T>> 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<ExplodedSupergraphNode<T>> getPredNodes(ExplodedSupergraphNode<T> node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
T dest = node.getSupergraphNode();
HashSet<ExplodedSupergraphNode<T>> result = HashSetFactory.make(supergraph.getPredNodeCount(dest));
for (Iterator<? extends T> 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<T>(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<? extends T> 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<T>(src, t));
}
}
} else {
Assertions.UNREACHABLE("need to implement for non-reversible flow function " + f.getClass());
}
}
}
}
return result.iterator();
}
public int getPredNodeCount(ExplodedSupergraphNode<T> node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
T dest = node.getSupergraphNode();
int count = 0;
for (Iterator<? extends T> 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<ExplodedSupergraphNode<T>> getSuccNodes(ExplodedSupergraphNode<T> node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
T src = node.getSupergraphNode();
HashSet<ExplodedSupergraphNode<T>> result = HashSetFactory.make(supergraph.getSuccNodeCount(src));
for (Iterator<? extends T> 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<T>(dest, t));
}
}
} else {
// special logic for a return edge. dest is a return site
for (Iterator<? extends T> 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<T>(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<T> node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
T src = node.getSupergraphNode();
int count = 0;
for (Iterator<? extends T> 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<T> src, ExplodedSupergraphNode<T> dst) {
for (Iterator it = getSuccNodes(src); it.hasNext();) {
if (it.next().equals(dst)) {
return true;
}
}
return false;
}
public ISupergraph<T,?> getSupergraph() {
return supergraph;
}
/**
* @return Returns the flowFunctions.
*/
public IFlowFunctionMap getFlowFunctions() {
return flowFunctions;
}
}

View File

@ -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<T> {
@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;
}
}

View File

@ -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<T> {
private static final boolean DEBUG = false;
/**
* List<ExplodedSupergraphNode>
*/
private final List<ExplodedSupergraphNode<T>> outermostList;
/**
* Map: Pair<ExplodedSupegraphNode,ExplodedSupergraphNode> -> List<ExplodedSupergraphNode>
* 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<Pair, List<ExplodedSupergraphNode<T>>> edge2SLVP = HashMapFactory.make();
/**
* Should we skip over boring calls when iterating?
*/
private boolean skipBoringCalls = false;
private final ExplodedSupergraphWithSummaryEdges<T> esg;
/**
* @param nodeList
*/
private ExplodedSupergraphPath(List<ExplodedSupergraphNode<T>> nodeList, ExplodedSupergraphWithSummaryEdges<T> 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 <CGNode> currently on the call
// stack
Stack<CGNode> callStack = new Stack<CGNode>();
List<ExplodedSupergraphNode<T>> L = new ArrayList<ExplodedSupergraphNode<T>>(outermostList);
for (int i = 0; i < L.size() - 1; i++) {
ExplodedSupergraphNode<T> src = L.get(i);
ExplodedSupergraphNode<T> 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<CGNode> which should not be traversed into
* @return null if none found
*/
private List<ExplodedSupergraphNode<T>> findOrCreateSLVP(ExplodedSupergraphNode<T> src, ExplodedSupergraphNode<T> dest, Stack<CGNode> callStack) {
Pair p = Pair.make(src, dest);
List<ExplodedSupergraphNode<T>> 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<CGNode>
*/
private boolean validInCallStack(List<ExplodedSupergraphNode<T>> l, Stack<CGNode> callStack) {
Iterator<ExplodedSupergraphNode<T>> it = l.iterator();
while (it.hasNext()) {
ExplodedSupergraphNode<T> src = it.next();
if (callStack.contains(esg.getSupergraph().getProcOf(src.getSupergraphNode()))) {
return false;
}
}
return true;
}
/**
* @return Iterator<ExplodedSupergraphNode>
*/
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 <em>NOT</em> traverse interprocedural
* edges
*
* @author sfink
*
*/
static class SLVPFinder<T> extends BFSPathFinder<ExplodedSupergraphNode<T>> {
final ExplodedSupergraphWithSummaryEdges esg;
final Collection<CGNode> exclusions;
SLVPFinder(ExplodedSupergraphWithSummaryEdges<T> esg, Collection<ExplodedSupergraphNode<T>> sources, Collection<ExplodedSupergraphNode<T>> sinks, Collection<CGNode> exclusions) {
super(esg, sources.iterator(), new CollectionFilter<ExplodedSupergraphNode<T>>(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<ExplodedSupergraphNode<T>> getConnected(final ExplodedSupergraphNode<T> n) {
return new FilterIterator<ExplodedSupergraphNode<T>>(super.getConnected(n), new Filter() {
@SuppressWarnings("unchecked")
public boolean accepts(Object o) {
ExplodedSupergraphNode<T> dest = (ExplodedSupergraphNode<T>) 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<T> a, ExplodedSupergraphNode<T> b) {
final PartiallyCollapsedSupergraph supergraph = (PartiallyCollapsedSupergraph) esg.getSupergraph();
return supergraph.getProcOf(a.getSupergraphNode()).equals(supergraph.getProcOf(b.getSupergraphNode()));
}
@Override
public List<ExplodedSupergraphNode<T>> find() {
List<ExplodedSupergraphNode<T>> L = super.find();
if (L == null) {
return L;
} else {
Collections.reverse(L);
return L;
}
}
}
/**
* This object traverses an exploded supergraph with summary edges
* <em>backwards</em> from a sink, until it finds an node with the universal
* (0) factoid.
*
* During this traversal, it will <em>NOT</em> 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 <main,0>
* exists.
*
* @author sfink
*
*/
static class NoReturnBackwardsPathFinder<T> extends BFSPathFinder<ExplodedSupergraphNode<T>> {
final ExplodedSupergraphWithSummaryEdges<T> esg;
@SuppressWarnings("unchecked")
NoReturnBackwardsPathFinder(ExplodedSupergraphWithSummaryEdges<T> esg, ExplodedSupergraphNode<T> sink) {
super(GraphInverter.invert(esg), Collections.singleton(sink).iterator(), zeroFactFilter);
this.esg = esg;
}
@Override
protected Iterator<ExplodedSupergraphNode<T>> getConnected(ExplodedSupergraphNode<T> n) {
ExplodedSupergraphNode src = n;
PartiallyCollapsedSupergraph supergraph = (PartiallyCollapsedSupergraph) esg.getSupergraph();
HashSet<ExplodedSupergraphNode<T>> result = HashSetFactory.make(esg.getPredNodeCount(n));
// add facts from non-call exploded supergraph edges
for (Iterator<? extends ExplodedSupergraphNode<T>> it = super.getConnected(n); it.hasNext();) {
ExplodedSupergraphNode<T> 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 <T> ExplodedSupergraphPath<T> findRealizablePath(ExplodedSupergraphWithSummaryEdges<T> esg, ExplodedSupergraphNode<T> sink) {
BFSPathFinder<ExplodedSupergraphNode<T>> backwardsFinder = new NoReturnBackwardsPathFinder<T>(esg, sink);
if (DEBUG) {
Trace.println("find path to sink " + sink);
}
List<ExplodedSupergraphNode<T>> L = backwardsFinder.find();
if (DEBUG) {
Trace.println("got backwards path " + new ExplodedSupergraphPath<T>(L, esg));
}
if (L == null) {
return null;
}
ExplodedSupergraphPath<T> result = new ExplodedSupergraphPath<T>(L, esg);
return result;
}
/**
* for a call-to-return edge <src,dest>, 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<ExplodedSupergraphNode<T>> computeSummarySLVP(ExplodedSupergraphNode<T> src, ExplodedSupergraphNode<T> dest, Collection<CGNode> callStack) {
// calledTargets := exploded nodes that are reached from the src by a
// call.
HashSet<ExplodedSupergraphNode<T>> calledTargets = HashSetFactory.make(3);
for (Iterator<ExplodedSupergraphNode<T>> it = esg.getSuccNodes(src); it.hasNext();) {
ExplodedSupergraphNode<T> target = it.next();
if (esg.getSupergraph().classifyEdge(src.getSupergraphNode(), target.getSupergraphNode()) == ISupergraph.CALL_EDGE) {
calledTargets.add(target);
}
}
HashSet<ExplodedSupergraphNode<T>> calledExitNodes = HashSetFactory.make(3);
for (Iterator<ExplodedSupergraphNode<T>> it = esg.getPredNodes(dest); it.hasNext();) {
ExplodedSupergraphNode<T> 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<T> innerFinder = new SLVPFinder<T>(esg, calledTargets, calledExitNodes, callStack);
List<ExplodedSupergraphNode<T>> 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 <T> ExplodedSupergraphPath<T> summarize(ISupergraph<T,?> supergraph, ExplodedSupergraphPath<T> 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 <T> void pruneBoringCalls(ExplodedSupergraphPath<T> 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 <T> void pruneForCallReturn(ISupergraph<T,?> supergraph, ExplodedSupergraphPath<T> path) {
if (path == null) {
throw new IllegalArgumentException("path is null");
}
pruneListForCallReturn(supergraph, path.outermostList);
for (Iterator<List<ExplodedSupergraphNode<T>>> it = path.edge2SLVP.values().iterator(); it.hasNext();) {
List<ExplodedSupergraphNode<T>> 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 <T> List<ExplodedSupergraphNode<T>> pruneListForCallReturn(ISupergraph<T,?> supergraph, List<ExplodedSupergraphNode<T>> L) throws IllegalArgumentException {
if (L == null) {
throw new IllegalArgumentException("L == null");
}
for (int i = 0; i < L.size(); i++) {
ExplodedSupergraphNode<T> 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;
}
}

View File

@ -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<T> extends ExplodedSupergraph<T> {
private final TabulationSolver<T, ?> solver;
/**
* @param supergraph
* @param flowFunctions
* @param solver
*/
public ExplodedSupergraphWithSummaryEdges(ISupergraph<T, ?> supergraph, IFlowFunctionMap<T> flowFunctions,
TabulationSolver<T, ?> solver) {
super(supergraph, flowFunctions);
this.solver = solver;
}
/*
* @see com.ibm.wala.dataflow.IFDS.ExplodedSupergraph#getSuccNodes(java.lang.Object)
*/
@Override
public Iterator<ExplodedSupergraphNode<T>> getSuccNodes(ExplodedSupergraphNode<T> src) {
if (src == null) {
throw new IllegalArgumentException("src is null");
}
HashSet<ExplodedSupergraphNode<T>> result = HashSetFactory.make(5);
result.addAll(Iterator2Collection.toCollection(super.getSuccNodes(src)));
// add facts from summary edges
if (getSupergraph().isCall(src.getSupergraphNode())) {
for (Iterator<? extends T> 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<T>(dest, d2));
}
}
}
}
return result.iterator();
}
/*
* @see com.ibm.wala.dataflow.IFDS.ExplodedSupergraph#getPredNodes(java.lang.Object)
*/
@Override
public Iterator<ExplodedSupergraphNode<T>> getPredNodes(ExplodedSupergraphNode<T> dest) {
if (dest == null) {
throw new IllegalArgumentException("dest is null");
}
HashSet<ExplodedSupergraphNode<T>> result = HashSetFactory.make(5);
result.addAll(Iterator2Collection.toCollection(super.getPredNodes(dest)));
// add facts from summary edges
if (getSupergraph().isReturn(dest.getSupergraphNode())) {
for (Iterator<? extends T> 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<T>(src, d1));
}
}
}
}
return result.iterator();
}
/*
* @see com.ibm.wala.dataflow.IFDS.ExplodedSupergraph#getPredNodeCount(java.lang.Object)
*/
@Override
public int getPredNodeCount(ExplodedSupergraphNode<T> N) {
return Iterator2Collection.toCollection(getPredNodes(N)).size();
}
/*
* @see com.ibm.wala.dataflow.IFDS.ExplodedSupergraph#getSuccNodeCount(java.lang.Object)
*/
@Override
public int getSuccNodeCount(ExplodedSupergraphNode<T> N) {
return Iterator2Collection.toCollection(getSuccNodes(N)).size();
}
}

View File

@ -23,44 +23,39 @@ public interface IFlowFunctionMap<T> {
/**
* @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);
}

View File

@ -38,6 +38,7 @@ public class IdentityFlowFunctions<T> implements IFlowFunctionMap<T> {
/*
* @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<T> implements IFlowFunctionMap<T> {
return IdentityFlowFunction.identity();
}
public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret) {
return IdentityFlowFunction.identity();
}
}

View File

@ -541,16 +541,32 @@ public class TabulationSolver<T, P> {
final int c = supergraph.getNumber(edge.target);
final Collection<T> returnSites = Iterator2Collection.toCollection(supergraph.getReturnSites(edge.target));
// [14 - 16]
for (Iterator<? extends T> 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<T, P> {
@SuppressWarnings("unchecked")
@Override
protected boolean compareElements(PathEdge<T> p1, PathEdge<T> p2) {
return problem.getDomain().hasPriorityOver(p1, p2);
return problem.getDomain().hasPriorityOver(p1, p2);
}
}

View File

@ -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();

View File

@ -46,6 +46,7 @@ public class ReachabilityFunctions<T> implements IFlowFunctionMap<T> {
private ReachabilityFunctions() {
}
@Deprecated
public IUnaryFlowFunction getCallFlowFunction(T src, T dest) {
return FLOW_REACHES;
}
@ -74,4 +75,8 @@ public class ReachabilityFunctions<T> implements IFlowFunctionMap<T> {
return FLOW_REACHES;
}
public IUnaryFlowFunction getCallFlowFunction(T src, T dest, T ret) {
return FLOW_REACHES;
}
}

View File

@ -24,8 +24,8 @@ import com.ibm.wala.util.debug.Assertions;
*/
public class SliceFunctions implements IPartiallyBalancedFlowFunctions<Statement> {
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) {