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:
parent
27d977c26d
commit
e8fea2bfa9
|
@ -23,6 +23,7 @@ import com.ibm.wala.shrikeBT.IInstruction;
|
||||||
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||||
import com.ibm.wala.shrikeBT.InvokeInstruction;
|
import com.ibm.wala.shrikeBT.InvokeInstruction;
|
||||||
import com.ibm.wala.ssa.ISSABasicBlock;
|
import com.ibm.wala.ssa.ISSABasicBlock;
|
||||||
|
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
||||||
import com.ibm.wala.types.ClassLoaderReference;
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
import com.ibm.wala.types.MethodReference;
|
import com.ibm.wala.types.MethodReference;
|
||||||
import com.ibm.wala.util.collections.Filter;
|
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.BitVector;
|
||||||
import com.ibm.wala.util.intset.BitVectorIntSet;
|
import com.ibm.wala.util.intset.BitVectorIntSet;
|
||||||
import com.ibm.wala.util.intset.IntSet;
|
import com.ibm.wala.util.intset.IntSet;
|
||||||
|
import com.ibm.wala.util.intset.MutableIntSet;
|
||||||
import com.ibm.wala.viz.IFDSExplorer;
|
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 int DEBUG_LEVEL = 0;
|
||||||
|
|
||||||
private static final boolean WARN_ON_EAGER_CONSTRUCTION = false;
|
private static final boolean WARN_ON_EAGER_CONSTRUCTION = false;
|
||||||
|
|
||||||
private static final boolean FAIL_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();
|
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);
|
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
|
* If n is relevant and its cfg has not already been added, add nodes and edges for n
|
||||||
|
*
|
||||||
* @param n
|
* @param n
|
||||||
*/
|
*/
|
||||||
private void addNodesAndEdgesForCGNodeIfNeeded(CGNode n) {
|
private void addIntraproceduralNodesAndEdgesForCGNodeIfNeeded(CGNode n) {
|
||||||
if (!cgNodesVisited.contains(cg.getNumber(n)) && relevant.accepts(n)) {
|
if (!cgNodesVisited.contains(cg.getNumber(n)) && relevant.accepts(n)) {
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 0) {
|
||||||
System.err.println("Adding nodes and edges for cg node: " + n);
|
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);
|
addNodeForEachBasicBlock(cfg, n);
|
||||||
IInstruction[] instrs = cfg.getInstructions();
|
IInstruction[] instrs = cfg.getInstructions();
|
||||||
// create edges for node n.
|
// create edges for node n.
|
||||||
addInterproceduralEdgesForEntryAndExitBlocks(n, cfg);
|
|
||||||
for (Iterator<T> bbs = cfg.iterator(); bbs.hasNext();) {
|
for (Iterator<T> bbs = cfg.iterator(); bbs.hasNext();) {
|
||||||
T bb = bbs.next();
|
T bb = bbs.next();
|
||||||
if (bb != cfg.entry())
|
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
|
* Add edges to the IPCFG for the incoming edges incident on a basic block bb.
|
||||||
* callees.
|
|
||||||
*
|
*
|
||||||
* @param n a call graph node
|
* @param n a call graph node
|
||||||
* @param cfg the CFG for n
|
* @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) {
|
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("addEdgesToNonEntryBlock: " + bb);
|
||||||
System.err.println("nPred: " + cfg.getPredNodeCount(bb));
|
System.err.println("nPred: " + cfg.getPredNodeCount(bb));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Iterator<? extends T> ps = cfg.getPredNodes(bb); ps.hasNext();) {
|
for (Iterator<? extends T> ps = cfg.getPredNodes(bb); ps.hasNext();) {
|
||||||
T pb = ps.next();
|
T pb = ps.next();
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("Consider previous block: " + pb);
|
System.err.println("Consider previous block: " + pb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,42 +188,42 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
|
||||||
|
|
||||||
int index = pb.getLastInstructionIndex();
|
int index = pb.getLastInstructionIndex();
|
||||||
IInstruction inst = instrs[index];
|
IInstruction inst = instrs[index];
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("Last instruction is : " + inst);
|
System.err.println("Last instruction is : " + inst);
|
||||||
}
|
}
|
||||||
if (inst instanceof IInvokeInstruction) {
|
if (inst instanceof IInvokeInstruction) {
|
||||||
// a previous instruction is a call instruction. If necessary,
|
// a previous instruction is a call instruction. If necessary,
|
||||||
// add an edge from the exit() of each target of the call.
|
// add an edge from the exit() of each target of the call.
|
||||||
IInvokeInstruction call = (IInvokeInstruction) inst;
|
// IInvokeInstruction call = (IInvokeInstruction) inst;
|
||||||
CallSiteReference site = makeCallSiteReference(n.getMethod().getDeclaringClass().getClassLoader().getReference(), cfg
|
// CallSiteReference site = makeCallSiteReference(n.getMethod().getDeclaringClass().getClassLoader().getReference(), cfg
|
||||||
.getProgramCounter(index), call);
|
// .getProgramCounter(index), call);
|
||||||
if (DEBUG_LEVEL > 0) {
|
// if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("got Site: " + site);
|
// System.err.println("got Site: " + site);
|
||||||
}
|
// }
|
||||||
boolean irrelevantTargets = false;
|
// boolean irrelevantTargets = false;
|
||||||
for (Iterator ts = cg.getPossibleTargets(n, site).iterator(); ts.hasNext();) {
|
// for (Iterator ts = cg.getPossibleTargets(n, site).iterator(); ts.hasNext();) {
|
||||||
CGNode tn = (CGNode) ts.next();
|
// CGNode tn = (CGNode) ts.next();
|
||||||
if (!relevant.accepts(tn)) {
|
// if (!relevant.accepts(tn)) {
|
||||||
if (DEBUG_LEVEL > 0) {
|
// if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("Irrelevant target: " + tn);
|
// System.err.println("Irrelevant target: " + tn);
|
||||||
}
|
// }
|
||||||
irrelevantTargets = true;
|
// irrelevantTargets = true;
|
||||||
continue;
|
// 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) {
|
if (CALL_TO_RETURN_EDGES) {
|
||||||
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) {
|
|
||||||
// Add a "normal" edge from the predecessor block to this block.
|
// Add a "normal" edge from the predecessor block to this block.
|
||||||
BasicBlockInContext<T> p = new BasicBlockInContext<T>(n, pb);
|
BasicBlockInContext<T> p = new BasicBlockInContext<T>(n, pb);
|
||||||
BasicBlockInContext<T> b = new BasicBlockInContext<T>(n, bb);
|
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) {
|
private void addEdgesFromExitToReturn(CGNode caller, T returnBlock, CGNode target, ControlFlowGraph<? extends T> targetCFG) {
|
||||||
T texit = targetCFG.exit();
|
T texit = targetCFG.exit();
|
||||||
BasicBlockInContext<T> exit = new BasicBlockInContext<T>(target, texit);
|
BasicBlockInContext<T> exit = new BasicBlockInContext<T>(target, texit);
|
||||||
addNodeForBasicBlock(targetCFG, exit);
|
addNodeForBasicBlockIfNeeded(exit);
|
||||||
BasicBlockInContext<T> ret = new BasicBlockInContext<T>(caller, returnBlock);
|
BasicBlockInContext<T> ret = new BasicBlockInContext<T>(caller, returnBlock);
|
||||||
if (Assertions.verifyAssertions) {
|
if (Assertions.verifyAssertions) {
|
||||||
if (!g.containsNode(exit) || !g.containsNode(ret)) {
|
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);
|
Assertions._assert(g.containsNode(ret), "IPCFG does not contain " + ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("addEdgeFromExitToReturn " + exit + ret);
|
System.err.println("addEdgeFromExitToReturn " + exit + ret);
|
||||||
}
|
}
|
||||||
g.addEdge(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) {
|
private void addEdgesFromCallToEntry(CGNode caller, T callBlock, CGNode target, ControlFlowGraph<? extends T> targetCFG) {
|
||||||
T tentry = targetCFG.entry();
|
T tentry = targetCFG.entry();
|
||||||
BasicBlockInContext<T> entry = new BasicBlockInContext<T>(target, tentry);
|
BasicBlockInContext<T> entry = new BasicBlockInContext<T>(target, tentry);
|
||||||
addNodeForBasicBlock(targetCFG, entry);
|
addNodeForBasicBlockIfNeeded(entry);
|
||||||
BasicBlockInContext<T> call = new BasicBlockInContext<T>(caller, callBlock);
|
BasicBlockInContext<T> call = new BasicBlockInContext<T>(caller, callBlock);
|
||||||
if (Assertions.verifyAssertions) {
|
if (Assertions.verifyAssertions) {
|
||||||
if (!g.containsNode(entry) || !g.containsNode(call)) {
|
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);
|
Assertions._assert(g.containsNode(call), "IPCFG does not contain " + call);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("addEdgeFromCallToEntry " + call + " " + entry);
|
System.err.println("addEdgeFromCallToEntry " + call + " " + entry);
|
||||||
}
|
}
|
||||||
g.addEdge(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();) {
|
for (Iterator callers = cg.getPredNodes(n); callers.hasNext();) {
|
||||||
CGNode caller = (CGNode) callers.next();
|
CGNode caller = (CGNode) callers.next();
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("got caller " + caller);
|
System.err.println("got caller " + caller);
|
||||||
}
|
}
|
||||||
if (relevant.accepts(caller)) {
|
if (relevant.accepts(caller)) {
|
||||||
|
@ -323,25 +339,25 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
|
||||||
ControlFlowGraph<T> ccfg = getCFG(caller);
|
ControlFlowGraph<T> ccfg = getCFG(caller);
|
||||||
IInstruction[] cinsts = ccfg.getInstructions();
|
IInstruction[] cinsts = ccfg.getInstructions();
|
||||||
|
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("Visiting " + cinsts.length + " instructions");
|
System.err.println("Visiting " + cinsts.length + " instructions");
|
||||||
}
|
}
|
||||||
for (int i = 0; i < cinsts.length; i++) {
|
for (int i = 0; i < cinsts.length; i++) {
|
||||||
if (cinsts[i] instanceof IInvokeInstruction) {
|
if (cinsts[i] instanceof IInvokeInstruction) {
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("Checking invokeinstruction: " + cinsts[i]);
|
System.err.println("Checking invokeinstruction: " + cinsts[i]);
|
||||||
}
|
}
|
||||||
IInvokeInstruction call = (IInvokeInstruction) cinsts[i];
|
IInvokeInstruction call = (IInvokeInstruction) cinsts[i];
|
||||||
CallSiteReference site = makeCallSiteReference(n.getMethod().getDeclaringClass().getClassLoader().getReference(), ccfg
|
CallSiteReference site = makeCallSiteReference(n.getMethod().getDeclaringClass().getClassLoader().getReference(), ccfg
|
||||||
.getProgramCounter(i), call);
|
.getProgramCounter(i), call);
|
||||||
if (cg.getPossibleTargets(caller, site).contains(n)) {
|
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);
|
System.err.println("Adding edge " + ccfg.getBlockForInstruction(i) + " to " + entryBlock);
|
||||||
}
|
}
|
||||||
T callerBB = ccfg.getBlockForInstruction(i);
|
T callerBB = ccfg.getBlockForInstruction(i);
|
||||||
BasicBlockInContext<T> b1 = new BasicBlockInContext<T>(caller, callerBB);
|
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
|
// 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);
|
BasicBlockInContext<T> b2 = new BasicBlockInContext<T>(n, entryBlock);
|
||||||
g.addEdge(b1, b2);
|
g.addEdge(b1, b2);
|
||||||
// also add edges from exit node to all return nodes (successor of call bb)
|
// 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();
|
T returnBB = succIter.next();
|
||||||
BasicBlockInContext<T> b3 = new BasicBlockInContext<T>(n, exitBlock);
|
BasicBlockInContext<T> b3 = new BasicBlockInContext<T>(n, exitBlock);
|
||||||
BasicBlockInContext<T> b4 = new BasicBlockInContext<T>(caller, returnBB);
|
BasicBlockInContext<T> b4 = new BasicBlockInContext<T>(caller, returnBB);
|
||||||
addNodeForBasicBlock(ccfg, b4);
|
addNodeForBasicBlockIfNeeded(b4);
|
||||||
g.addEdge(b3, 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) {
|
private void addNodeForEachBasicBlock(ControlFlowGraph<? extends T> cfg, CGNode N) {
|
||||||
for (Iterator<? extends T> bbs = cfg.iterator(); bbs.hasNext();) {
|
for (Iterator<? extends T> bbs = cfg.iterator(); bbs.hasNext();) {
|
||||||
T bb = bbs.next();
|
T bb = bbs.next();
|
||||||
if (DEBUG_LEVEL > 0) {
|
if (DEBUG_LEVEL > 1) {
|
||||||
System.err.println("IPCFG Add basic block " + bb);
|
System.err.println("IPCFG Add basic block " + bb);
|
||||||
}
|
}
|
||||||
BasicBlockInContext<T> b = new BasicBlockInContext<T>(N, 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)) {
|
if (!g.containsNode(b)) {
|
||||||
g.addNode(b);
|
g.addNode(b);
|
||||||
|
ControlFlowGraph<T> cfg = getCFG(b);
|
||||||
if (hasCall(b, cfg)) {
|
if (hasCall(b, cfg)) {
|
||||||
hasCallVector.set(g.getNumber(b));
|
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()");
|
System.err.println("WARNING: forcing full ICFG construction by calling iterator()");
|
||||||
}
|
}
|
||||||
if (FAIL_ON_EAGER_CONSTRUCTION) {
|
if (FAIL_ON_EAGER_CONSTRUCTION) {
|
||||||
throw new UnimplementedError();
|
throw new UnimplementedError();
|
||||||
}
|
}
|
||||||
constructFullGraph();
|
constructFullGraph();
|
||||||
return g.iterator();
|
return g.iterator();
|
||||||
|
@ -436,14 +453,123 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
|
||||||
}
|
}
|
||||||
if (FAIL_ON_EAGER_CONSTRUCTION) {
|
if (FAIL_ON_EAGER_CONSTRUCTION) {
|
||||||
throw new UnimplementedError();
|
throw new UnimplementedError();
|
||||||
}
|
}
|
||||||
constructFullGraph();
|
constructFullGraph();
|
||||||
return g.getNumberOfNodes();
|
return g.getNumberOfNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean constructedFullGraph = false;
|
||||||
|
|
||||||
private void constructFullGraph() {
|
private void constructFullGraph() {
|
||||||
for (CGNode n : cg) {
|
if (!constructedFullGraph) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(n);
|
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)
|
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(com.ibm.wala.util.graph.Node)
|
||||||
*/
|
*/
|
||||||
public Iterator<? extends BasicBlockInContext<T>> getPredNodes(BasicBlockInContext<T> N) {
|
public Iterator<? extends BasicBlockInContext<T>> getPredNodes(BasicBlockInContext<T> N) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
|
initForPred(N);
|
||||||
return g.getPredNodes(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)
|
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(com.ibm.wala.util.graph.Node)
|
||||||
*/
|
*/
|
||||||
public int getPredNodeCount(BasicBlockInContext<T> N) {
|
public int getPredNodeCount(BasicBlockInContext<T> N) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
|
initForPred(N);
|
||||||
return g.getPredNodeCount(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)
|
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(com.ibm.wala.util.graph.Node)
|
||||||
*/
|
*/
|
||||||
public Iterator<? extends BasicBlockInContext<T>> getSuccNodes(BasicBlockInContext<T> N) {
|
public Iterator<? extends BasicBlockInContext<T>> getSuccNodes(BasicBlockInContext<T> N) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
|
initForSucc(N);
|
||||||
return g.getSuccNodes(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)
|
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(com.ibm.wala.util.graph.Node)
|
||||||
*/
|
*/
|
||||||
public int getSuccNodeCount(BasicBlockInContext<T> N) {
|
public int getSuccNodeCount(BasicBlockInContext<T> N) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
|
initForSucc(N);
|
||||||
return g.getSuccNodeCount(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)
|
* @see com.ibm.wala.util.graph.Graph#containsNode(com.ibm.wala.util.graph.Node)
|
||||||
*/
|
*/
|
||||||
public boolean containsNode(BasicBlockInContext<T> N) {
|
public boolean containsNode(BasicBlockInContext<T> N) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
|
|
||||||
return g.containsNode(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
|
* @return true iff basic block B ends in a call instuction
|
||||||
*/
|
*/
|
||||||
public boolean hasCall(BasicBlockInContext<T> B) {
|
public boolean hasCall(BasicBlockInContext<T> B) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(B));
|
addNodeForBasicBlockIfNeeded(B);
|
||||||
if (Assertions.verifyAssertions) {
|
|
||||||
if (!containsNode(B)) {
|
|
||||||
Assertions._assert(containsNode(B));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hasCallVector.get(getNumber(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) {
|
public boolean hasEdge(BasicBlockInContext<T> src, BasicBlockInContext<T> dst) {
|
||||||
|
initForSucc(src);
|
||||||
return g.hasEdge(src, dst);
|
return g.hasEdge(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumber(BasicBlockInContext<T> N) {
|
public int getNumber(BasicBlockInContext<T> N) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(N));
|
addNodeForBasicBlockIfNeeded(N);
|
||||||
return g.getNumber(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()");
|
System.err.println("WARNING: forcing full ICFG construction by calling getMaxNumber()");
|
||||||
}
|
}
|
||||||
if (FAIL_ON_EAGER_CONSTRUCTION) {
|
if (FAIL_ON_EAGER_CONSTRUCTION) {
|
||||||
throw new UnimplementedError();
|
throw new UnimplementedError();
|
||||||
}
|
}
|
||||||
constructFullGraph();
|
constructFullGraph();
|
||||||
return g.getMaxNumber();
|
return g.getMaxNumber();
|
||||||
|
@ -628,12 +789,12 @@ public abstract class AbstractInterproceduralCFG<T extends ISSABasicBlock> imple
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntSet getSuccNodeNumbers(BasicBlockInContext<T> node) {
|
public IntSet getSuccNodeNumbers(BasicBlockInContext<T> node) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(node));
|
initForSucc(node);
|
||||||
return g.getSuccNodeNumbers(node);
|
return g.getSuccNodeNumbers(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntSet getPredNodeNumbers(BasicBlockInContext<T> node) {
|
public IntSet getPredNodeNumbers(BasicBlockInContext<T> node) {
|
||||||
addNodesAndEdgesForCGNodeIfNeeded(getCGNode(node));
|
initForPred(node);
|
||||||
return g.getPredNodeNumbers(node);
|
return g.getPredNodeNumbers(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue