tabulation and IPCFG bug fixes
git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@2794 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
parent
1ddd6f19dd
commit
c502e1a354
|
@ -127,8 +127,8 @@ public class BackwardsSupergraph<T, P> implements ISupergraph<T, P> {
|
|||
/*
|
||||
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object)
|
||||
*/
|
||||
public Iterator<? extends T> getReturnSites(T c) {
|
||||
return delegate.getCallSites(c);
|
||||
public Iterator<? extends T> getReturnSites(T c, P callee) {
|
||||
return delegate.getCallSites(c, callee);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -251,19 +251,6 @@ public class BackwardsSupergraph<T, P> implements ISupergraph<T, P> {
|
|||
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<T, P> implements ISupergraph<T, P> {
|
|||
/*
|
||||
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object)
|
||||
*/
|
||||
public Iterator<? extends T> getCallSites(T r) {
|
||||
return delegate.getReturnSites(r);
|
||||
public Iterator<? extends T> getCallSites(T r, P callee) {
|
||||
return delegate.getReturnSites(r, callee);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -19,20 +19,17 @@ import com.ibm.wala.util.graph.NumberedGraph;
|
|||
*
|
||||
* A supergraph as defined by Reps, Horwitz, and Sagiv POPL95
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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<T,P> extends NumberedGraph<T> {
|
||||
public interface ISupergraph<T, P> extends NumberedGraph<T> {
|
||||
|
||||
public static final byte CALL_EDGE = 0;
|
||||
|
||||
|
@ -42,102 +39,87 @@ public interface ISupergraph<T,P> extends NumberedGraph<T> {
|
|||
|
||||
public static final byte OTHER = 3;
|
||||
|
||||
|
||||
/**
|
||||
* @return the graph of procedures (e.g. a call graph) over which this supergraph is induced.
|
||||
*/
|
||||
Graph<? extends P> 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<? extends T> 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<T> 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<? extends T> getReturnSites(T call);
|
||||
Iterator<? extends T> 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<? extends T> getCallSites(T r);
|
||||
Iterator<? extends T> 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<T,P> extends NumberedGraph<T> {
|
|||
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);
|
||||
|
|
|
@ -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<Object> implements ISupergraph<Object, CGNode> {
|
||||
|
||||
/**
|
||||
|
@ -235,8 +241,11 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph<Object> implemen
|
|||
return new FilterIterator<Object>(edgeManager.getSuccNodes(n), isEntry);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Iterator<? extends Object> getReturnSites(Object object) {
|
||||
public Iterator<? extends Object> getReturnSites(Object object, CGNode callee) {
|
||||
if (object instanceof BasicBlockInContext) {
|
||||
return partialIPFG.getReturnSites((BasicBlockInContext) object);
|
||||
} else {
|
||||
|
@ -245,10 +254,13 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph<Object> implemen
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Iterator<? extends Object> getCallSites(Object object) {
|
||||
public Iterator<? extends Object> getCallSites(Object object, CGNode callee) {
|
||||
if (object instanceof BasicBlockInContext) {
|
||||
return partialIPFG.getCallSites((BasicBlockInContext<ISSABasicBlock>) object);
|
||||
return partialIPFG.getCallSites((BasicBlockInContext<ISSABasicBlock>) object, callee);
|
||||
} else {
|
||||
CGNode n = nodeManager.getProcOfCollapsedNode(object);
|
||||
return new NonNullSingletonIterator<CollapsedNode>(nodeManager.getCollapsedEntry(n));
|
||||
|
@ -305,7 +317,7 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph<Object> 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<Object> in = MapUtil.findOrCreateSet(incomingTransverseEdges, ret);
|
||||
in.add(e_n);
|
||||
|
@ -509,7 +521,7 @@ public class PartiallyCollapsedSupergraph extends AbstractGraph<Object> implemen
|
|||
HashSet<Object> 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<Object> 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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -377,7 +377,6 @@ public class TabulationSolver<T, P> {
|
|||
* @param D4 set of d1 s.t. <c, d1> -> <edge.s_p, edge.d2> was recorded as call flow
|
||||
*/
|
||||
private void propagateToReturnSites(final PathEdge<T> 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<T, P> {
|
|||
// 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<? extends T> retSites = supergraph.getReturnSites(c); retSites.hasNext();) {
|
||||
for (Iterator<? extends T> 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<T, P> {
|
|||
|
||||
// c:= number of the call node
|
||||
final int c = supergraph.getNumber(edge.target);
|
||||
|
||||
final Collection<T> returnSites = Iterator2Collection.toCollection(supergraph.getReturnSites(edge.target));
|
||||
|
||||
Collection<T> allReturnSites = HashSetFactory.make();
|
||||
// populate allReturnSites with return sites for missing calls.
|
||||
allReturnSites.addAll(Iterator2Collection.toCollection(supergraph.getReturnSites(edge.target, null)));
|
||||
// [14 - 16]
|
||||
for (Iterator<? extends T> it = supergraph.getCalledNodes(edge.target); it.hasNext();) {
|
||||
final T callee = it.next();
|
||||
|
@ -549,6 +549,8 @@ public class TabulationSolver<T, P> {
|
|||
System.err.println(" process callee: " + callee);
|
||||
}
|
||||
MutableSparseIntSet reached = MutableSparseIntSet.makeEmpty();
|
||||
final Collection<T> 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<T, P> {
|
|||
}
|
||||
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<T, P> {
|
|||
|
||||
// [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);
|
||||
}
|
||||
|
|
|
@ -56,8 +56,8 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
|
|||
private static final int DEBUG_LEVEL = 0;
|
||||
|
||||
/**
|
||||
* Should the graph include call-to-return edges?
|
||||
* When set to <code>false</code>, the graphs output by {@link IFDSExplorer} look incorrect
|
||||
* Should the graph include call-to-return edges? When set to <code>false</code>, 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<T extends ISSABasicBlock> 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<BasicBlockInContext> getReturnSites(BasicBlockInContext<T> bb) {
|
||||
if (bb == null) {
|
||||
public Iterator<BasicBlockInContext> getReturnSites(BasicBlockInContext<T> 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<BasicBlockInContext>(getSuccNodes(bb), isReturn);
|
||||
return new FilterIterator<BasicBlockInContext>(getSuccNodes(callBlock), isReturn);
|
||||
}
|
||||
|
||||
public Iterator<BasicBlockInContext<T>> getCallSites(BasicBlockInContext<T> 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<BasicBlockInContext<T>> getCallSites(BasicBlockInContext<T> returnBlock, final CGNode callee) {
|
||||
if (returnBlock == null) {
|
||||
throw new IllegalArgumentException("bb is null");
|
||||
}
|
||||
ControlFlowGraph<T> cfg = getCFG(bb);
|
||||
Iterator<? extends T> it = cfg.getPredNodes(bb.getDelegate());
|
||||
final CGNode node = bb.getNode();
|
||||
final ControlFlowGraph<T> cfg = getCFG(returnBlock);
|
||||
Iterator<? extends T> it = cfg.getPredNodes(returnBlock.getDelegate());
|
||||
final CGNode node = returnBlock.getNode();
|
||||
|
||||
Filter<? extends T> dispatchFilter = new Filter<T>() {
|
||||
public boolean accepts(T callBlock) {
|
||||
BasicBlockInContext<T> bb = new BasicBlockInContext<T>(node, callBlock);
|
||||
if (!hasCall(bb, cfg)) {
|
||||
return false;
|
||||
}
|
||||
if (callee != null) {
|
||||
return getCallTargets(bb).contains(callee);
|
||||
} else {
|
||||
return getCallTargets(bb).isEmpty();
|
||||
}
|
||||
}
|
||||
};
|
||||
it = new FilterIterator<T>(it, dispatchFilter);
|
||||
|
||||
Function<T, BasicBlockInContext<T>> toContext = new Function<T, BasicBlockInContext<T>>() {
|
||||
public BasicBlockInContext<T> apply(T object) {
|
||||
T b = object;
|
||||
|
|
|
@ -63,7 +63,7 @@ class SDGSupergraph implements ISupergraph<Statement, PDG> {
|
|||
/*
|
||||
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getCallSites(java.lang.Object)
|
||||
*/
|
||||
public Iterator<? extends Statement> getCallSites(Statement r) {
|
||||
public Iterator<? extends Statement> getCallSites(Statement r, PDG callee) {
|
||||
switch (r.getKind()) {
|
||||
case EXC_RET_CALLER: {
|
||||
ExceptionalReturnCaller n = (ExceptionalReturnCaller) r;
|
||||
|
@ -183,7 +183,7 @@ class SDGSupergraph implements ISupergraph<Statement, PDG> {
|
|||
/*
|
||||
* @see com.ibm.wala.dataflow.IFDS.ISupergraph#getReturnSites(java.lang.Object)
|
||||
*/
|
||||
public Iterator<? extends Statement> getReturnSites(Statement call) {
|
||||
public Iterator<? extends Statement> getReturnSites(Statement call, PDG callee) {
|
||||
switch (call.getKind()) {
|
||||
case PARAM_CALLER: {
|
||||
ParamCaller n = (ParamCaller) call;
|
||||
|
|
Loading…
Reference in New Issue