even more laziness

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@3067 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
msridhar1 2008-10-23 19:14:11 +00:00
parent 27d977c26d
commit e8fea2bfa9
1 changed files with 232 additions and 71 deletions

View File

@ -23,6 +23,7 @@ import com.ibm.wala.shrikeBT.IInstruction;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrikeBT.InvokeInstruction;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.util.collections.Filter;
@ -38,6 +39,7 @@ import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph;
import com.ibm.wala.util.intset.BitVector;
import com.ibm.wala.util.intset.BitVectorIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.MutableIntSet;
import com.ibm.wala.viz.IFDSExplorer;
/**
@ -53,7 +55,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
private static final int DEBUG_LEVEL = 0;
private static final boolean WARN_ON_EAGER_CONSTRUCTION = false;
private static final boolean FAIL_ON_EAGER_CONSTRUCTION = false;
/**
@ -83,9 +85,24 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
private final BitVector hasCallVector = new BitVector();
/**
* node numbers of CGNodes we have already added to IPCFG
* CGNodes whose intraprocedural edges have been added to IPCFG
*/
private final BitVectorIntSet cgNodesVisited = new BitVectorIntSet();
private final MutableIntSet cgNodesVisited = new BitVectorIntSet();
/**
* those cg nodes whose edges to callers have been added
*/
private final MutableIntSet cgNodesWithCallerEdges = new BitVectorIntSet();
/**
* those call nodes whose successor edges (interprocedural) have been added
*/
private final MutableIntSet handledCalls = new BitVectorIntSet();
/**
* those return nodes whose predecessor edges (interprocedural) have been added
*/
private final MutableIntSet handledReturns = new BitVectorIntSet();
protected abstract ControlFlowGraph<T> getCFG(CGNode n);
@ -114,9 +131,10 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
/**
* If n is relevant and its cfg has not already been added, add nodes and edges for n
*
* @param n
*/
private void addNodesAndEdgesForCGNodeIfNeeded(CGNode n) {
private void addIntraproceduralNodesAndEdgesForCGNodeIfNeeded(CGNode n) {
if (!cgNodesVisited.contains(cg.getNumber(n)) && relevant.accepts(n)) {
if (DEBUG_LEVEL > 0) {
System.err.println("Adding nodes and edges for cg node: " + n);
@ -129,7 +147,6 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
addNodeForEachBasicBlock(cfg, n);
IInstruction[] instrs = cfg.getInstructions();
// create edges for node n.
addInterproceduralEdgesForEntryAndExitBlocks(n, cfg);
for (Iterator<T> bbs = cfg.iterator(); bbs.hasNext();) {
T bb = bbs.next();
if (bb != cfg.entry())
@ -140,8 +157,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
}
/**
* Add edges to the IPCFG for the incoming edges incident on a basic block bb. For calls, we also add outgoing edges to entries of
* callees.
* Add edges to the IPCFG for the incoming edges incident on a basic block bb.
*
* @param n a call graph node
* @param cfg the CFG for n
@ -150,14 +166,14 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
*/
private void addEdgesToNonEntryBlock(CGNode n, ControlFlowGraph<T> cfg, IInstruction[] instrs, T bb) {
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("addEdgesToNonEntryBlock: " + bb);
System.err.println("nPred: " + cfg.getPredNodeCount(bb));
}
for (Iterator<? extends T> ps = cfg.getPredNodes(bb); ps.hasNext();) {
T pb = ps.next();
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("Consider previous block: " + pb);
}
@ -172,42 +188,42 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
int index = pb.getLastInstructionIndex();
IInstruction inst = instrs[index];
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("Last instruction is : " + inst);
}
if (inst instanceof IInvokeInstruction) {
// a previous instruction is a call instruction. If necessary,
// add an edge from the exit() of each target of the call.
IInvokeInstruction call = (IInvokeInstruction) inst;
CallSiteReference site = makeCallSiteReference(n.getMethod().getDeclaringClass().getClassLoader().getReference(), cfg
.getProgramCounter(index), call);
if (DEBUG_LEVEL > 0) {
System.err.println("got Site: " + site);
}
boolean irrelevantTargets = false;
for (Iterator ts = cg.getPossibleTargets(n, site).iterator(); ts.hasNext();) {
CGNode tn = (CGNode) ts.next();
if (!relevant.accepts(tn)) {
if (DEBUG_LEVEL > 0) {
System.err.println("Irrelevant target: " + tn);
}
irrelevantTargets = true;
continue;
}
// IInvokeInstruction call = (IInvokeInstruction) inst;
// CallSiteReference site = makeCallSiteReference(n.getMethod().getDeclaringClass().getClassLoader().getReference(), cfg
// .getProgramCounter(index), call);
// if (DEBUG_LEVEL > 1) {
// System.err.println("got Site: " + site);
// }
// boolean irrelevantTargets = false;
// for (Iterator ts = cg.getPossibleTargets(n, site).iterator(); ts.hasNext();) {
// CGNode tn = (CGNode) ts.next();
// if (!relevant.accepts(tn)) {
// if (DEBUG_LEVEL > 1) {
// System.err.println("Irrelevant target: " + tn);
// }
// irrelevantTargets = true;
// continue;
// }
//
// if (DEBUG_LEVEL > 1) {
// System.err.println("Relevant target: " + tn);
// }
// // add an edge from tn exit to this node
// ControlFlowGraph<? extends T> tcfg = getCFG(tn);
// // tcfg might be null if tn is an unmodelled native method
// if (tcfg != null) {
// addEdgesFromExitToReturn(n, bb, tn, tcfg);
// addEdgesFromCallToEntry(n, pb, tn, tcfg);
// }
// }
if (DEBUG_LEVEL > 0) {
System.err.println("Relevant target: " + tn);
}
// add an edge from tn exit to this node
ControlFlowGraph<? extends T> tcfg = getCFG(tn);
// tcfg might be null if tn is an unmodelled native method
if (tcfg != null) {
addEdgesFromExitToReturn(n, bb, tn, tcfg);
addEdgesFromCallToEntry(n, pb, tn, tcfg);
}
}
if (irrelevantTargets || CALL_TO_RETURN_EDGES) {
if (CALL_TO_RETURN_EDGES) {
// Add a "normal" edge from the predecessor block to this block.
BasicBlockInContext<T> p = new BasicBlockInContext<T>(n, pb);
BasicBlockInContext<T> b = new BasicBlockInContext<T>(n, bb);
@ -260,7 +276,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
private void addEdgesFromExitToReturn(CGNode caller, T returnBlock, CGNode target, ControlFlowGraph<? extends T> targetCFG) {
T texit = targetCFG.exit();
BasicBlockInContext<T> exit = new BasicBlockInContext<T>(target, texit);
addNodeForBasicBlock(targetCFG, exit);
addNodeForBasicBlockIfNeeded(exit);
BasicBlockInContext<T> ret = new BasicBlockInContext<T>(caller, returnBlock);
if (Assertions.verifyAssertions) {
if (!g.containsNode(exit) || !g.containsNode(ret)) {
@ -268,7 +284,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
Assertions._assert(g.containsNode(ret), "IPCFG does not contain " + ret);
}
}
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("addEdgeFromExitToReturn " + exit + ret);
}
g.addEdge(exit, ret);
@ -283,7 +299,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
private void addEdgesFromCallToEntry(CGNode caller, T callBlock, CGNode target, ControlFlowGraph<? extends T> targetCFG) {
T tentry = targetCFG.entry();
BasicBlockInContext<T> entry = new BasicBlockInContext<T>(target, tentry);
addNodeForBasicBlock(targetCFG, entry);
addNodeForBasicBlockIfNeeded(entry);
BasicBlockInContext<T> call = new BasicBlockInContext<T>(caller, callBlock);
if (Assertions.verifyAssertions) {
if (!g.containsNode(entry) || !g.containsNode(call)) {
@ -291,7 +307,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
Assertions._assert(g.containsNode(call), "IPCFG does not contain " + call);
}
}
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("addEdgeFromCallToEntry " + call + " " + entry);
}
g.addEdge(call, entry);
@ -313,7 +329,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
for (Iterator callers = cg.getPredNodes(n); callers.hasNext();) {
CGNode caller = (CGNode) callers.next();
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("got caller " + caller);
}
if (relevant.accepts(caller)) {
@ -323,25 +339,25 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
ControlFlowGraph<T> ccfg = getCFG(caller);
IInstruction[] cinsts = ccfg.getInstructions();
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("Visiting " + cinsts.length + " instructions");
}
for (int i = 0; i < cinsts.length; i++) {
if (cinsts[i] instanceof IInvokeInstruction) {
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("Checking invokeinstruction: " + cinsts[i]);
}
IInvokeInstruction call = (IInvokeInstruction) cinsts[i];
CallSiteReference site = makeCallSiteReference(n.getMethod().getDeclaringClass().getClassLoader().getReference(), ccfg
.getProgramCounter(i), call);
if (cg.getPossibleTargets(caller, site).contains(n)) {
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("Adding edge " + ccfg.getBlockForInstruction(i) + " to " + entryBlock);
}
T callerBB = ccfg.getBlockForInstruction(i);
BasicBlockInContext<T> b1 = new BasicBlockInContext<T>(caller, callerBB);
// need to add a node for caller basic block, in case we haven't processed caller yet
addNodeForBasicBlock(ccfg, b1);
addNodeForBasicBlockIfNeeded(b1);
BasicBlockInContext<T> b2 = new BasicBlockInContext<T>(n, entryBlock);
g.addEdge(b1, b2);
// also add edges from exit node to all return nodes (successor of call bb)
@ -349,7 +365,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
T returnBB = succIter.next();
BasicBlockInContext<T> b3 = new BasicBlockInContext<T>(n, exitBlock);
BasicBlockInContext<T> b4 = new BasicBlockInContext<T>(caller, returnBB);
addNodeForBasicBlock(ccfg, b4);
addNodeForBasicBlockIfNeeded(b4);
g.addEdge(b3, b4);
}
}
@ -367,17 +383,18 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
private void addNodeForEachBasicBlock(ControlFlowGraph<? extends T> cfg, CGNode N) {
for (Iterator<? extends T> bbs = cfg.iterator(); bbs.hasNext();) {
T bb = bbs.next();
if (DEBUG_LEVEL > 0) {
if (DEBUG_LEVEL > 1) {
System.err.println("IPCFG Add basic block " + bb);
}
BasicBlockInContext<T> b = new BasicBlockInContext<T>(N, bb);
addNodeForBasicBlock(cfg, b);
addNodeForBasicBlockIfNeeded(b);
}
}
private void addNodeForBasicBlock(ControlFlowGraph<? extends T> cfg, BasicBlockInContext<T> b) {
private void addNodeForBasicBlockIfNeeded(BasicBlockInContext<T> b) {
if (!g.containsNode(b)) {
g.addNode(b);
ControlFlowGraph<T> cfg = getCFG(b);
if (hasCall(b, cfg)) {
hasCallVector.set(g.getNumber(b));
}
@ -421,7 +438,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
System.err.println("WARNING: forcing full ICFG construction by calling iterator()");
}
if (FAIL_ON_EAGER_CONSTRUCTION) {
throw new UnimplementedError();
throw new UnimplementedError();
}
constructFullGraph();
return g.iterator();
@ -436,14 +453,123 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
}
if (FAIL_ON_EAGER_CONSTRUCTION) {
throw new UnimplementedError();
}
}
constructFullGraph();
return g.getNumberOfNodes();
}
private boolean constructedFullGraph = false;
private void constructFullGraph() {
for (CGNode n : cg) {
addNodesAndEdgesForCGNodeIfNeeded(n);
if (!constructedFullGraph) {
for (CGNode n : cg) {
addIntraproceduralNodesAndEdgesForCGNodeIfNeeded(n);
addEdgesToCallees(n);
}
for (int i = 0; i < g.getMaxNumber(); i++) {
addedSuccs.add(i);
addedPreds.add(i);
}
constructedFullGraph = true;
}
}
/**
* add interprocedural edges to nodes in callees of n
*
* @param n
*/
private void addEdgesToCallees(CGNode n) {
ControlFlowGraph<T> cfg = getCFG(n);
if (cfg != null) {
for (Iterator<T> bbs = cfg.iterator(); bbs.hasNext();) {
T bb = bbs.next();
BasicBlockInContext<T> block = new BasicBlockInContext<T>(n, bb);
if (hasCall(block)) {
addCalleeEdgesForCall(n, block);
}
}
}
}
/**
* add edges to callees for return block and corresponding call block(s)
*/
private void addCalleeEdgesForReturn(CGNode node, BasicBlockInContext<T> returnBlock) {
final int num = g.getNumber(returnBlock);
if (!handledReturns.contains(num)) {
handledReturns.add(num);
// compute calls for return
ControlFlowGraph<T> cfg = getCFG(returnBlock);
for (Iterator<? extends T> it = cfg.getPredNodes(returnBlock.getDelegate()); it.hasNext();) {
T b = it.next();
final BasicBlockInContext<T> block = new BasicBlockInContext<T>(node, b);
if (hasCall(block)) {
addCalleeEdgesForCall(node, block);
}
}
}
}
/**
* add edges to callee entry for call block, and edges from callee exit to corresponding return blocks
*/
private void addCalleeEdgesForCall(CGNode n, BasicBlockInContext<T> callBlock) {
int num = g.getNumber(callBlock);
if (!handledCalls.contains(num)) {
handledCalls.add(num);
ControlFlowGraph<T> cfg = getCFG(n);
int index = callBlock.getLastInstructionIndex();
SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) callBlock.getLastInstruction();
CallSiteReference site = makeCallSiteReference(n.getMethod().getDeclaringClass().getClassLoader().getReference(), cfg
.getProgramCounter(index), call);
if (DEBUG_LEVEL > 1) {
System.err.println("got Site: " + site);
}
boolean irrelevantTargets = false;
for (Iterator ts = cg.getPossibleTargets(n, site).iterator(); ts.hasNext();) {
CGNode tn = (CGNode) ts.next();
if (!relevant.accepts(tn)) {
if (DEBUG_LEVEL > 1) {
System.err.println("Irrelevant target: " + tn);
}
irrelevantTargets = true;
continue;
}
if (DEBUG_LEVEL > 1) {
System.err.println("Relevant target: " + tn);
}
// add an edge from tn exit to this node
ControlFlowGraph<? extends T> tcfg = getCFG(tn);
// tcfg might be null if tn is an unmodelled native method
if (tcfg != null) {
final T cbDelegate = callBlock.getDelegate();
addEdgesFromCallToEntry(n, cbDelegate, tn, tcfg);
for (Iterator<? extends T> returnBlocks = cfg.getSuccNodes(cbDelegate); returnBlocks.hasNext();) {
T retBlock = returnBlocks.next();
addEdgesFromExitToReturn(n, retBlock, tn, tcfg);
if (irrelevantTargets) {
// Add a "normal" edge from the call block to the return block.
g.addEdge(callBlock, new BasicBlockInContext<T>(n, retBlock));
}
}
}
}
}
}
/**
* add edges to nodes in callers of n
*
* @param n
*/
private void addCallerEdges(CGNode n) {
final int num = cg.getNumber(n);
if (!cgNodesWithCallerEdges.contains(num)) {
cgNodesWithCallerEdges.add(num);
ControlFlowGraph<T> cfg = getCFG(n);
addInterproceduralEdgesForEntryAndExitBlocks(n, cfg);
}
}
@ -465,15 +591,55 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(com.ibm.wala.util.graph.Node)
*/
public Iterator<? extends BasicBlockInContext<T>> getPredNodes(BasicBlockInContext<T> N) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
initForPred(N);
return g.getPredNodes(N);
}
private final MutableIntSet addedPreds = new BitVectorIntSet();
/**
* add enough nodes and edges to the graph to allow for computing predecessors of N
*/
private void initForPred(BasicBlockInContext<T> N) {
CGNode node = getCGNode(N);
addIntraproceduralNodesAndEdgesForCGNodeIfNeeded(node);
int num = g.getNumber(N);
if (!addedPreds.contains(num)) {
addedPreds.add(num);
if (N.getDelegate().isEntryBlock()) {
addCallerEdges(node);
}
if (isReturn(N)) {
addCalleeEdgesForReturn(node, N);
}
}
}
private final MutableIntSet addedSuccs = new BitVectorIntSet();
/**
* add enough nodes and edges to the graph to allow for computing successors of N
*/
private void initForSucc(BasicBlockInContext<T> N) {
CGNode node = getCGNode(N);
addIntraproceduralNodesAndEdgesForCGNodeIfNeeded(node);
int num = g.getNumber(N);
if (!addedSuccs.contains(num)) {
addedSuccs.add(num);
if (N.getDelegate().isExitBlock()) {
addCallerEdges(node);
}
if (hasCall(N)) {
addCalleeEdgesForCall(node, N);
}
}
}
/*
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(com.ibm.wala.util.graph.Node)
*/
public int getPredNodeCount(BasicBlockInContext<T> N) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
initForPred(N);
return g.getPredNodeCount(N);
}
@ -481,7 +647,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(com.ibm.wala.util.graph.Node)
*/
public Iterator<? extends BasicBlockInContext<T>> getSuccNodes(BasicBlockInContext<T> N) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
initForSucc(N);
return g.getSuccNodes(N);
}
@ -489,7 +655,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(com.ibm.wala.util.graph.Node)
*/
public int getSuccNodeCount(BasicBlockInContext<T> N) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
initForSucc(N);
return g.getSuccNodeCount(N);
}
@ -520,7 +686,6 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
* @see com.ibm.wala.util.graph.Graph#containsNode(com.ibm.wala.util.graph.Node)
*/
public boolean containsNode(BasicBlockInContext<T> N) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
return g.containsNode(N);
}
@ -529,12 +694,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
* @return true iff basic block B ends in a call instuction
*/
public boolean hasCall(BasicBlockInContext<T> B) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(B));
if (Assertions.verifyAssertions) {
if (!containsNode(B)) {
Assertions._assert(containsNode(B));
}
}
addNodeForBasicBlockIfNeeded(B);
return hasCallVector.get(getNumber(B));
}
@ -599,11 +759,12 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
}
public boolean hasEdge(BasicBlockInContext<T> src, BasicBlockInContext<T> dst) {
initForSucc(src);
return g.hasEdge(src, dst);
}
public int getNumber(BasicBlockInContext<T> N) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
addNodeForBasicBlockIfNeeded(N);
return g.getNumber(N);
}
@ -616,7 +777,7 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
System.err.println("WARNING: forcing full ICFG construction by calling getMaxNumber()");
}
if (FAIL_ON_EAGER_CONSTRUCTION) {
throw new UnimplementedError();
throw new UnimplementedError();
}
constructFullGraph();
return g.getMaxNumber();
@ -628,12 +789,12 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
}
public IntSet getSuccNodeNumbers(BasicBlockInContext<T> node) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(node));
initForSucc(node);
return g.getSuccNodeNumbers(node);
}
public IntSet getPredNodeNumbers(BasicBlockInContext<T> node) {
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(node));
initForPred(node);
return g.getPredNodeNumbers(node);
}