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:
sjfink 2008-05-09 20:53:38 +00:00
parent 1ddd6f19dd
commit c502e1a354
6 changed files with 96 additions and 95 deletions

View File

@ -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);
}
/*

View File

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

View File

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

View File

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

View File

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

View File

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