bug fixes with InducedCFGs and context-sensitive slicing

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@2307 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
sjfink 2008-01-07 20:31:24 +00:00
parent 3f623ac0a7
commit f4f8d417a5
2 changed files with 99 additions and 149 deletions

View File

@ -42,12 +42,12 @@ import com.ibm.wala.util.graph.impl.NodeWithNumber;
/** /**
* A ControlFlowGraph computed from a set of SSA instructions * A ControlFlowGraph computed from a set of SSA instructions
* *
* This is a funny CFG ... we assume that there are always fallthru edges, even * This is a funny CFG ... we assume that there are always fallthru edges, even from throws and returns.
* from throws and returns.
*/ */
public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> { public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
private static final boolean DEBUG = false; private static final boolean DEBUG = true;
/** /**
* A partial map from Instruction -> BasicBlock * A partial map from Instruction -> BasicBlock
*/ */
@ -57,11 +57,16 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
private final IInstruction[] instructions; private final IInstruction[] instructions;
private BasicBlock entry;
private BasicBlock exit;
/** /**
* TODO: we do not yet support induced CFGS with exception handlers. * TODO: we do not yet support induced CFGS with exception handlers.
* *
* @param instructions * @param instructions
* @throws IllegalArgumentException if instructions is null * @throws IllegalArgumentException
* if instructions is null
*/ */
public InducedCFG(SSAInstruction[] instructions, IMethod method, Context context) { public InducedCFG(SSAInstruction[] instructions, IMethod method, Context context) {
super(method); super(method);
@ -70,15 +75,8 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
} }
this.context = context; this.context = context;
this.instructions = instructions; this.instructions = instructions;
if (DEBUG) {
Trace.println("compute InducedCFG: " + method);
}
i2block = new BasicBlock[instructions.length]; i2block = new BasicBlock[instructions.length];
if (instructions.length == 0) { makeBasicBlocks();
makeEmptyBlocks();
} else {
makeBasicBlocks();
}
init(); init();
computeEdges(); computeEdges();
@ -94,14 +92,13 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
@Override @Override
public int hashCode() { public int hashCode() {
return context.hashCode() ^ getMethod().hashCode(); return context.hashCode() + 77 * getMethod().hashCode();
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return (o instanceof InducedCFG) && return (o instanceof InducedCFG) && getMethod().equals(((InducedCFG) o).getMethod())
getMethod().equals(((InducedCFG)o).getMethod()) && && context.equals(((InducedCFG) o).context);
context.equals(((InducedCFG)o).context);
} }
public IInstruction[] getInstructions() { public IInstruction[] getInstructions() {
@ -116,18 +113,34 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
BasicBlock b = (BasicBlock) it.next(); BasicBlock b = (BasicBlock) it.next();
if (b.equals(exit())) if (b.equals(exit()))
continue; continue;
b.computeOutgoingEdges(); if (b.equals(entry())) {
addNormalEdge(b, getNode(b.getGraphNodeId() + 1));
continue;
}
SSAInstruction last = (SSAInstruction) getInstructions()[b.getLastInstructionIndex()];
if (last.isPEI()) {
// we don't currently model catch blocks here ... instead just link
// to the exit block
addExceptionalEdge(b,exit());
}
// this CFG is odd in that we assume fallthru might always
// happen .. this is because I'm too lazy to code control
// flow in all method summaries yet.
if (true) {
// if (last.isFallThrough()) {
if (DEBUG) {
Trace.println("Add fallthru to " + getNode(b.getGraphNodeId() + 1));
}
addNormalEdge(b, getNode(b.getGraphNodeId() + 1));
}
if (last instanceof SSAReturnInstruction) {
// link each return instruction to the exit block.
BasicBlock exit = exit();
addNormalEdge(b, exit);
}
} }
} }
/**
* Create basic blocks for an empty method
*/
private void makeEmptyBlocks() {
BasicBlock b = new BasicBlock(-1);
addNode(b);
}
protected BranchVisitor makeBranchVisitor(boolean[] r) { protected BranchVisitor makeBranchVisitor(boolean[] r) {
return new BranchVisitor(r); return new BranchVisitor(r);
} }
@ -140,49 +153,54 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
* Walk through the instructions and compute basic block boundaries. * Walk through the instructions and compute basic block boundaries.
*/ */
private void makeBasicBlocks() { private void makeBasicBlocks() {
// allocate the entry block
BasicBlock entry = new BasicBlock(-1, -2);
addNode(entry);
this.entry = entry;
SSAInstruction[] instructions = (SSAInstruction[]) getInstructions(); SSAInstruction[] instructions = (SSAInstruction[]) getInstructions();
final boolean[] r = new boolean[instructions.length]; if (instructions.length > 0) {
final boolean[] r = new boolean[instructions.length];
// Compute r so r[i] == true iff instruction i begins a basic block. // Compute r so r[i] == true iff instruction i begins a basic block.
// While doing so count the number of blocks. // While doing so count the number of blocks.
r[0] = true; r[0] = true;
BranchVisitor branchVisitor = makeBranchVisitor(r); BranchVisitor branchVisitor = makeBranchVisitor(r);
PEIVisitor peiVisitor = makePEIVisitor(r); PEIVisitor peiVisitor = makePEIVisitor(r);
for (int i = 0; i < instructions.length; i++) { for (int i = 0; i < instructions.length; i++) {
if (instructions[i] != null) { if (instructions[i] != null) {
branchVisitor.setIndex(i); branchVisitor.setIndex(i);
instructions[i].visit(branchVisitor); instructions[i].visit(branchVisitor);
// TODO: deal with exception handlers // TODO: deal with exception handlers
peiVisitor.setIndex(i); peiVisitor.setIndex(i);
instructions[i].visit(peiVisitor); instructions[i].visit(peiVisitor);
}
}
BasicBlock b = null;
for (int i = 0; i < r.length; i++) {
if (r[i]) {
b = new BasicBlock(i);
addNode(b);
if (DEBUG) {
Trace.println("Add basic block " + b);
} }
} }
i2block[i] = b;
BasicBlock b = null;
for (int i = 0; i < r.length; i++) {
if (r[i]) {
int end = instructions.length - 1;
for (int j = i; j < instructions.length; j++) {
if (r[j]) {
end = j;
break;
}
}
b = new BasicBlock(i, end);
addNode(b);
}
i2block[i] = b;
}
} }
// allocate the exit block // allocate the exit block
BasicBlock exit = new BasicBlock(-1); BasicBlock exit = new BasicBlock(-3, -4);
if (DEBUG) {
Trace.println("Add exit block " + exit);
}
addNode(exit); addNode(exit);
this.exit = exit;
} }
/** /**
* @author sfink * This visitor identifies basic block boundaries induced by branch instructions.
*
* This visitor identifies basic block boundaries induced by branch
* instructions.
*/ */
public class BranchVisitor extends SSAInstruction.Visitor { public class BranchVisitor extends SSAInstruction.Visitor {
final private boolean[] r; final private boolean[] r;
@ -190,6 +208,7 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
protected BranchVisitor(boolean[] r) { protected BranchVisitor(boolean[] r) {
this.r = r; this.r = r;
} }
int index = 0; int index = 0;
void setIndex(int i) { void setIndex(int i) {
@ -211,11 +230,11 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
@Override @Override
public void visitSwitch(SSASwitchInstruction instruction) { public void visitSwitch(SSASwitchInstruction instruction) {
Assertions.UNREACHABLE("haven't implemented logic for switch yet."); Assertions.UNREACHABLE("haven't implemented logic for switch yet.");
// breakBasicBlock(); // breakBasicBlock();
// int[] targets = instruction.getTargets(); // int[] targets = instruction.getTargets();
// for (int i = 0; i < targets.length; i++) { // for (int i = 0; i < targets.length; i++) {
// r[targets[i]] = true; // r[targets[i]] = true;
// } // }
} }
@Override @Override
@ -234,6 +253,7 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
} }
} }
} }
// TODO: extend the following to deal with catch blocks. Right now // TODO: extend the following to deal with catch blocks. Right now
// it simply breaks basic blocks at PEIs. // it simply breaks basic blocks at PEIs.
public class PEIVisitor extends SSAInstruction.Visitor { public class PEIVisitor extends SSAInstruction.Visitor {
@ -242,6 +262,7 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
protected PEIVisitor(boolean[] r) { protected PEIVisitor(boolean[] r) {
this.r = r; this.r = r;
} }
int index = 0; int index = 0;
void setIndex(int i) { void setIndex(int i) {
@ -330,86 +351,21 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
return false; return false;
} }
} }
private final int start; private final int start;
BasicBlock(int start) { private final int end;
BasicBlock(int start, int end) {
this.start = start; this.start = start;
this.end = end;
} }
/**
* Add any exceptional edges generated by the last instruction in a basic
* block.
*
* @param last
* the last instruction in a basic block.
*/
private void addExceptionalEdges(SSAInstruction last) {
if (last.isPEI()) {
// we don't currently model catch blocks here ... instead just link
// to the exit block
addExceptionalEdgeTo(exit());
}
}
private void addNormalEdgeTo(BasicBlock b) {
addNormalEdge(this, b);
}
private void addExceptionalEdgeTo(BasicBlock b) {
addExceptionalEdge(this, b);
}
private void computeOutgoingEdges() {
if (DEBUG) {
Trace.println("Block " + this + ": computeOutgoingEdges()");
}
// TODO: we don't currently model branches
SSAInstruction last = (SSAInstruction) getInstructions()[getLastInstructionIndex()];
addExceptionalEdges(last);
// this CFG is odd in that we assume fallthru might always
// happen .. this is because I'm too lazy to code control
// flow in all method summaries yet.
if (true) {
// if (last.isFallThrough()) {
if (DEBUG) {
Trace.println("Add fallthru to " + getNode(getGraphNodeId() + 1));
}
addNormalEdgeTo(getNode(getGraphNodeId() + 1));
}
if (last instanceof SSAReturnInstruction) {
// link each return instrution to the exit block.
BasicBlock exit = exit();
addNormalEdgeTo(exit);
}
}
public int getFirstInstructionIndex() { public int getFirstInstructionIndex() {
return start; return start;
} }
/**
* Method getLastInstructionIndex.
*
* @return int
*/
public int getLastInstructionIndex() { public int getLastInstructionIndex() {
int exitNumber = InducedCFG.this.getNumber(exit()); return end;
if (getGraphNodeId() == exitNumber) {
// this is the exit block
return -2;
}
if (getGraphNodeId() == (exitNumber - 1)) {
// this is the last non-exit block
return getInstructions().length - 1;
} else {
BasicBlock next = getNode(getGraphNodeId() + 1);
return next.getFirstInstructionIndex() - 1;
}
} }
public boolean isCatchBlock() { public boolean isCatchBlock() {
@ -434,14 +390,14 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
* @see com.ibm.wala.cfg.IBasicBlock#isExitBlock() * @see com.ibm.wala.cfg.IBasicBlock#isExitBlock()
*/ */
public boolean isExitBlock() { public boolean isExitBlock() {
return getLastInstructionIndex() == -2; return this.equals(exit);
} }
/* /*
* @see com.ibm.wala.cfg.IBasicBlock#isEntryBlock() * @see com.ibm.wala.cfg.IBasicBlock#isEntryBlock()
*/ */
public boolean isEntryBlock() { public boolean isEntryBlock() {
return getNumber() == 0; return this.equals(entry);
} }
/* /*
@ -465,9 +421,9 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
public int getNumber() { public int getNumber() {
return InducedCFG.this.getNumber(this); return InducedCFG.this.getNumber(this);
} }
public Iterator<IInstruction> iterator() { public Iterator<IInstruction> iterator() {
return new ArrayIterator<IInstruction>(getInstructions(),getFirstInstructionIndex(),getLastInstructionIndex()); return new ArrayIterator<IInstruction>(getInstructions(), getFirstInstructionIndex(), getLastInstructionIndex());
} }
} }
@ -493,8 +449,7 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
} }
/** /**
* Since this CFG is synthetic, for now we assume the instruction index is the * Since this CFG is synthetic, for now we assume the instruction index is the same as the program counter
* same as the program counter
* *
* @see com.ibm.wala.cfg.ControlFlowGraph#getProgramCounter(int) * @see com.ibm.wala.cfg.ControlFlowGraph#getProgramCounter(int)
*/ */
@ -505,6 +460,5 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
return index; return index;
} }
} }
} }

View File

@ -510,15 +510,12 @@ public class HeapReachingDefs {
if (DEBUG) { if (DEBUG) {
System.err.println("getEdgeXfer: " + src + " " + dst + " " + src.isEntryBlock()); System.err.println("getEdgeXfer: " + src + " " + dst + " " + src.isEntryBlock());
} }
IntSet gen = null;
if (src.isEntryBlock()) { if (src.isEntryBlock()) {
if (DEBUG) { if (DEBUG) {
System.err.println("heapEntry " + heapEntryStatements()); System.err.println("heapEntry " + heapEntryStatements());
} }
gen = new BitVectorIntSet(heapEntryStatements()).toSparseIntSet(); return new BitVectorUnionVector(new BitVectorIntSet(heapEntryStatements()).getBitVector());
} else { }
gen = new SparseIntSet();
}
if (src.getInstruction() != null && !(src.getInstruction() instanceof SSAAbstractInvokeInstruction) if (src.getInstruction() != null && !(src.getInstruction() instanceof SSAAbstractInvokeInstruction)
&& !cfg.getNormalSuccessors(src).contains(dst)) { && !cfg.getNormalSuccessors(src).contains(dst)) {
// if the edge only happens due to exceptional control flow, then no // if the edge only happens due to exceptional control flow, then no
@ -530,8 +527,7 @@ public class HeapReachingDefs {
return BitVectorIdentity.instance(); return BitVectorIdentity.instance();
} else { } else {
BitVector kill = kill(src); BitVector kill = kill(src);
IntSet gen2 = gen(src); IntSet gen = gen(src);
gen = gen2 == null ? gen : gen.union(gen2);
if (DEBUG) { if (DEBUG) {
System.err.println("gen: " + gen + " kill: " + kill); System.err.println("gen: " + gen + " kill: " + kill);
} }