change ControlFlowGraph.getExceptionalSuccessors to return a List, in order of increasing catch scope

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@1822 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
sjfink 2007-10-04 15:48:46 +00:00
parent 516adf98aa
commit d445f0861a
10 changed files with 112 additions and 126 deletions

View File

@ -10,9 +10,11 @@
*******************************************************************************/
package com.ibm.wala.cfg;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.shrikeBT.Constants;
@ -35,6 +37,8 @@ import com.ibm.wala.util.intset.BitVector;
import com.ibm.wala.util.intset.FixedSizeBitVector;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.MutableSparseIntSet;
import com.ibm.wala.util.intset.SimpleIntVector;
import com.ibm.wala.util.intset.SimpleVector;
/**
*
@ -63,8 +67,16 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
/**
* An object to track not-to-exit exceptional edges in this cfg
*/
final private SparseNumberedEdgeManager<T> exceptionalEdgeManager = new SparseNumberedEdgeManager<T>(nodeManager,
0, BasicNaturalRelation.SIMPLE);
final private SparseNumberedEdgeManager<T> exceptionalEdgeManager = new SparseNumberedEdgeManager<T>(nodeManager, 0,
BasicNaturalRelation.SIMPLE);
/**
* An object to track not-to-exit exceptional edges in this cfg, indexed by
* block number. exceptionalEdges[i] is a list of block numbers that are
* non-exit exceptional successors of block i, in order of increasing "catch
* scope".
*/
final private SimpleVector<SimpleIntVector> exceptionalSuccessors = new SimpleVector<SimpleIntVector>();
/**
* Which basic blocks have a normal edge to exit()?
@ -186,7 +198,7 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
/**
* @param number
* number of a basic block in this cfg
* number of a basic block in this cfg
*/
boolean hasAnyNormalOut(int number) {
return (fallThru.get(number) || normalEdgeManager.getSuccNodeCount(number) > 0 || normalToExit.get(number));
@ -194,7 +206,7 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
/**
* @param number
* number of a basic block in this cfg
* number of a basic block in this cfg
*/
private int getNumberOfNormalOut(int number) {
int xtra = 0;
@ -209,7 +221,7 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
/**
* @param number
* number of a basic block in this cfg
* number of a basic block in this cfg
*/
public int getNumberOfExceptionalOut(int number) {
int xtra = 0;
@ -316,13 +328,23 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
}
}
/**
* @param number
* of a basic block
* @return the exceptional successors of the basic block, in order of
* increasing catch scope.
*/
private Iterator<T> iterateExceptionalSuccessors(int number) {
if (exceptionalEdgeManager.hasAnySuccessor(number)) {
if (exceptionalToExit.get(number)) {
return IteratorPlusOne.make(exceptionalEdgeManager.getSuccNodes(number), exit());
} else {
return exceptionalEdgeManager.getSuccNodes(number);
List<T> result = new ArrayList<T>();
SimpleIntVector v = exceptionalSuccessors.get(number);
for (int i = 0; i <= v.getMaxIndex(); i++) {
result.add(getNode(v.get(i)));
}
if (exceptionalToExit.get(number)) {
result.add(exit);
}
return result.iterator();
} else {
if (exceptionalToExit.get(number)) {
return new NonNullSingletonIterator<T>(exit());
@ -463,7 +485,7 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
* @param src
* @param dst
* @throws IllegalArgumentException
* if dst is null
* if dst is null
*/
public void addNormalEdge(T src, T dst) {
if (dst == null) {
@ -479,10 +501,8 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
}
/**
* @param src
* @param dst
* @throws IllegalArgumentException
* if dst is null
* if dst is null
*/
public void addExceptionalEdge(T src, T dst) {
if (dst == null) {
@ -492,6 +512,12 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
exceptionalToExit.set(getNumber(src));
} else {
exceptionalEdgeManager.addEdge(src, dst);
SimpleIntVector v = exceptionalSuccessors.get(getNumber(src));
if (v == null) {
v = new SimpleIntVector(-1);
exceptionalSuccessors.set(getNumber(src), v);
}
v.set(v.getMaxIndex() + 1, getNumber(dst));
}
}
@ -574,11 +600,15 @@ public abstract class AbstractCFG<T extends IBasicBlock> implements ControlFlowG
/*
* @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalSuccessors(com.ibm.wala.cfg.T)
*/
public Collection<T> getExceptionalSuccessors(T b) {
public List<T> getExceptionalSuccessors(T b) {
if (b == null) {
throw new IllegalArgumentException("b is null");
}
return Iterator2Collection.toCollection(iterateExceptionalSuccessors(b.getNumber()));
List<T> result = new ArrayList<T>();
for (Iterator<T> it = iterateExceptionalSuccessors(b.getNumber()); it.hasNext();) {
result.add(it.next());
}
return result;
}
/*

View File

@ -11,6 +11,7 @@
package com.ibm.wala.cfg;
import java.util.Collection;
import java.util.List;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.shrikeBT.IInstruction;
@ -66,13 +67,15 @@ public interface ControlFlowGraph<T extends IBasicBlock> extends NumberedGraph<T
public IMethod getMethod();
/**
* The order of blocks returned should be arbitrary but deterministic.
* The order of blocks returned must indicate the exception-handling scope.
* So the first block is the first candidate catch block, and so on.
* With this invariant one can compute the exceptional control flow for
* a given exception type.
*
* @param b
* @return the basic blocks which may be reached from b via exceptional
* control flow
*/
public Collection<T> getExceptionalSuccessors(T b);
public List<T> getExceptionalSuccessors(T b);
/**
* The order of blocks returned should be arbitrary but deterministic.

View File

@ -351,23 +351,17 @@ public class InducedCFG extends AbstractCFG<InducedCFG.BasicBlock> {
}
}
/**
* @param b
*/
private void addNormalEdgeTo(BasicBlock b) {
addNormalEdge(this, b);
}
/**
* @param b
*/
private void addExceptionalEdgeTo(BasicBlock b) {
addExceptionalEdge(this, b);
}
/**
* Method computeOutgoingEdges.
*/
private void computeOutgoingEdges() {
if (DEBUG) {

View File

@ -226,9 +226,6 @@ public class ShrikeCFG extends AbstractCFG<ShrikeCFG.BasicBlock> {
return ShrikeCFG.this.isCatchBlock(getNumber());
}
/**
* Method computeOutgoingEdges.
*/
private void computeOutgoingEdges() {
if (DEBUG) {
Trace.println("Block " + this + ": computeOutgoingEdges()");
@ -377,38 +374,16 @@ public class ShrikeCFG extends AbstractCFG<ShrikeCFG.BasicBlock> {
return hs;
}
// /**
// * @return true iff exception extends RuntimeException or Error
// */
// private boolean isUndeclaredType(IClass exception) {
// IClass re = cha.lookupClass(TypeReference.JavaLangRuntimeException);
// IClass error = cha.lookupClass(TypeReference.JavaLangError);
// boolean result = cha.isSubclassOf(exception, re) ||
// cha.isSubclassOf(exception, error);
// return result;
// }
/**
* @param b
*/
private void addNormalEdgeTo(BasicBlock b) {
addNormalEdge(this, b);
}
/**
* @param b
*/
private void addExceptionalEdgeTo(BasicBlock b) {
addExceptionalEdge(this, b);
}
/**
* Method getLastInstructionIndex.
*
* @return int
*/
public int getLastInstructionIndex() {
public int getLastInstructionIndex() {
if (this == entry() || this == exit()) {
// these are the special end blocks
return -2;
@ -422,16 +397,10 @@ public class ShrikeCFG extends AbstractCFG<ShrikeCFG.BasicBlock> {
}
}
/**
* Method getFirstInstructionIndex.
*/
public int getFirstInstructionIndex() {
return startIndex;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "BB[Shrike]" + getNumber() + " - " + method.getDeclaringClass().getReference().getName() + "." + method.getName();
@ -481,9 +450,6 @@ public class ShrikeCFG extends AbstractCFG<ShrikeCFG.BasicBlock> {
}
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer s = new StringBuffer("");
@ -502,29 +468,17 @@ public class ShrikeCFG extends AbstractCFG<ShrikeCFG.BasicBlock> {
return s.toString();
}
/**
* Method getMaxStackHeight.
*
* @return int
*/
public int getMaxStackHeight() {
return method.getMaxStackHeight();
}
/**
* Method getMaxLocals
*
* @return int
*/
public int getMaxLocals() {
return method.getMaxLocals();
}
/**
* Returns the exceptionHandlers.
*
* @return Set
*/
public Set<ExceptionHandler> getExceptionHandlers() {
return exceptionHandlers;
}

View File

@ -10,10 +10,11 @@
*******************************************************************************/
package com.ibm.wala.cfg;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.shrikeBT.IInstruction;
@ -24,7 +25,6 @@ import com.ibm.wala.ssa.SSAPiInstruction;
import com.ibm.wala.ssa.SSAThrowInstruction;
import com.ibm.wala.util.IteratorPlusOne;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.debug.Trace;
import com.ibm.wala.util.debug.UnimplementedError;
@ -477,14 +477,14 @@ public class TwoExitCFG implements ControlFlowGraph<ISSABasicBlock> {
/*
* @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalSuccessors(com.ibm.wala.cfg.ISSABasicBlock)
*/
public Collection<ISSABasicBlock> getExceptionalSuccessors(ISSABasicBlock b) {
public List<ISSABasicBlock> getExceptionalSuccessors(ISSABasicBlock b) {
if (b == null) {
throw new IllegalArgumentException("b is null");
}
if (b.equals(exceptionalExit)) {
return Collections.emptySet();
return Collections.emptyList();
} else {
HashSet<ISSABasicBlock> c = HashSetFactory.make(getSuccNodeCount(b));
List<ISSABasicBlock> c = new ArrayList<ISSABasicBlock>(getSuccNodeCount(b));
for (Iterator<ISSABasicBlock> it = delegate.getExceptionalSuccessors(b).iterator(); it.hasNext(); ) {
ISSABasicBlock o = it.next();
if (o.equals(delegate.exit())) {

View File

@ -681,12 +681,6 @@ public abstract class ShrikeBTMethod implements IMethod, BytecodeConstants {
}
}
/**
* Method getHandlers.
*
* @return ExceptionHandler[][]
* @throws InvalidClassFileException
*/
public ExceptionHandler[][] getHandlers() throws InvalidClassFileException {
if (getBCInfo().decoder == null) {
return null;
@ -696,18 +690,16 @@ public abstract class ShrikeBTMethod implements IMethod, BytecodeConstants {
}
/**
* Method getParameterType. By convention, for a non-static method,
* getParameterType(0) is the this pointer
*
* @param i
* @return TypeReference
* By convention, for a non-static method, getParameterType(0) is the this
* pointer
*/
public TypeReference getParameterType(int i) {
if (!isStatic()) {
if (i == 0)
if (i == 0) {
return declaringClass.getReference();
else
} else {
return getReference().getParameterType(i - 1);
}
} else {
return getReference().getParameterType(i);
}

View File

@ -10,9 +10,11 @@
*****************************************************************************/
package com.ibm.wala.ipa.cfg;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
@ -282,8 +284,12 @@ public class PrunedCFG<T extends IBasicBlock> extends AbstractNumberedGraph<T> i
return edges;
}
public Collection<T> getExceptionalSuccessors(final T N) {
return Iterator2Collection.toCollection(edges.getExceptionalSuccessors(N));
public List<T> getExceptionalSuccessors(final T N) {
ArrayList<T> result = new ArrayList<T>();
for (Iterator<T> it = edges.getExceptionalSuccessors(N); it.hasNext(); ) {
result.add(it.next());
}
return result;
}
public Collection<T> getNormalSuccessors(final T N) {

View File

@ -76,15 +76,15 @@ public abstract class IR {
* Mapping from PEI program counters to instruction[] indices
*/
final private Map<ProgramCounter, Integer> peiMapping = HashMapFactory.make();
/**
* Mapping from SSAInstruction to Basic Block, computed lazily
*/
private Map<SSAInstruction, ISSABasicBlock> instruction2Block;
/**
* subclasses must provide a source name mapping, if they want one
* (or null otherwise)
* subclasses must provide a source name mapping, if they want one (or null
* otherwise)
*/
protected abstract SSA2LocalMap getLocalMap();
@ -97,9 +97,9 @@ public abstract class IR {
* keep this package private: all calls should be through SSACache
*
* @param method
* the method to construct SSA form for
* the method to construct SSA form for
* @param options
* governing ssa construction options
* governing ssa construction options
*/
protected IR(IMethod method, SSAInstruction[] instructions, SymbolTable symbolTable, SSACFG cfg, SSAOptions options) {
if (method == null) {
@ -143,7 +143,8 @@ public abstract class IR {
* Create a string representation, with decoration for each variable
*
* @param d
* an object which provides string decorators for variables in the IR
* an object which provides string decorators for variables in the
* IR
*/
public String toString(ValueDecorator d) {
StringBuffer result = new StringBuffer(method.toString());
@ -179,7 +180,7 @@ public abstract class IR {
StringBuffer x = new StringBuffer(j + " " + instructions[j].toString(symbolTable, d));
StringStuff.padWithSpaces(x, 45);
result.append(x);
result.append(instructionPosition(j));
result.append(instructionPosition(j));
result.append("\n");
}
}
@ -389,7 +390,7 @@ public abstract class IR {
* visit each normal (non-phi, non-pi, non-catch) instruction in this IR
*
* @param v
* a visitor
* a visitor
*/
public void visitNormalInstructions(SSAInstruction.Visitor v) {
for (Iterator i = iterateNormalInstructions(); i.hasNext();) {
@ -401,7 +402,7 @@ public abstract class IR {
* visit each instruction in this IR
*
* @param v
* a visitor
* a visitor
*/
public void visitAllInstructions(SSAInstruction.Visitor v) {
for (Iterator i = iterateAllInstructions(); i.hasNext();) {
@ -468,7 +469,8 @@ public abstract class IR {
/**
* @param site
* @return the invoke instructions corresponding to this call site
* @throws IllegalArgumentException if site is null
* @throws IllegalArgumentException
* if site is null
*/
public SSAAbstractInvokeInstruction[] getCalls(CallSiteReference site) {
if (site == null) {
@ -487,7 +489,8 @@ public abstract class IR {
/**
* @param site
* @return the instruction indices corresponding to this call site
* @throws IllegalArgumentException if site is null
* @throws IllegalArgumentException
* if site is null
*/
public IntSet getCallInstructionIndices(CallSiteReference site) {
if (site == null) {
@ -516,7 +519,7 @@ public abstract class IR {
/**
* @param pc
* a program counter
* a program counter
* @return the instruction (a PEI) at this program counter
*/
public SSAInstruction getPEI(ProgramCounter pc) {
@ -561,9 +564,10 @@ public abstract class IR {
/**
* @param site
* a call site in this method
* a call site in this method
* @return the basic block corresponding to this instruction
* @throws IllegalArgumentException if site is null
* @throws IllegalArgumentException
* if site is null
*/
public ISSABasicBlock[] getBasicBlocksForCall(final CallSiteReference site) {
if (site == null) {
@ -578,12 +582,12 @@ public abstract class IR {
}
return result;
}
/**
* This is space-inefficient. Use with care.
* This is space-inefficient. Use with care.
*
* Be very careful; note the strange identity semantics of SSAInstruction,
* using ==. You can't mix SSAInstructions and IRs freely.
* using ==. You can't mix SSAInstructions and IRs freely.
*/
public ISSABasicBlock getBasicBlockForInstruction(SSAInstruction s) {
if (instruction2Block == null) {
@ -596,11 +600,11 @@ public abstract class IR {
instruction2Block = HashMapFactory.make();
for (ISSABasicBlock b : cfg) {
for (IInstruction s : b) {
instruction2Block.put((SSAInstruction)s, b);
instruction2Block.put((SSAInstruction) s, b);
}
}
}
/**
* TODO: why do we need this? We should enforce instructions == null if
* necessary, I think.
@ -620,9 +624,9 @@ public abstract class IR {
/**
* @param index
* an index into the IR instruction array
* an index into the IR instruction array
* @param vn
* a value number
* a value number
* @return if we know that immediately after the given program counter, v_vn
* corresponds to one or more locals and local variable names are
* available, the name of the locals which v_vn represents. Otherwise,
@ -643,9 +647,9 @@ public abstract class IR {
public interface SSA2LocalMap {
/**
* @param index
* an index into the IR instruction array
* an index into the IR instruction array
* @param vn
* a value number
* a value number
* @return if we know that immediately after the given program counter, v_vn
* corresponds to one or more locals and local variable names are
* available, the name of the locals which v_vn represents.

View File

@ -33,7 +33,6 @@ import com.ibm.wala.util.MapIterator;
import com.ibm.wala.util.ShrikeUtil;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.collections.Iterator2Collection;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.debug.Trace;
@ -907,13 +906,13 @@ public class SSACFG implements ControlFlowGraph<ISSABasicBlock> {
/*
* @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalSuccessors(com.ibm.wala.cfg.IBasicBlock)
*/
public Collection<ISSABasicBlock> getExceptionalSuccessors(final ISSABasicBlock b) {
public List<ISSABasicBlock> getExceptionalSuccessors(final ISSABasicBlock b) {
if (b == null) {
throw new IllegalArgumentException("b is null");
}
final IBasicBlock n = cfg.getNode(b.getNumber());
final Iterator i = cfg.getExceptionalSuccessors(n).iterator();
final Collection<ISSABasicBlock> c = HashSetFactory.make(getSuccNodeCount(b));
final List<ISSABasicBlock> c = new ArrayList<ISSABasicBlock>(getSuccNodeCount(b));
for (; i.hasNext();) {
final IBasicBlock s = (IBasicBlock) i.next();
c.add(basicBlocks[cfg.getNumber(s)]);

View File

@ -125,10 +125,10 @@ public class ExplodedControlFlowGraph implements ControlFlowGraph<ExplodedContro
}
}
public Collection<ExplodedBasicBlock> getExceptionalSuccessors(ExplodedBasicBlock eb) {
public List<ExplodedBasicBlock> getExceptionalSuccessors(ExplodedBasicBlock eb) {
assert eb != null;
if (eb.equals(exit)) {
return Collections.emptySet();
return Collections.emptyList();
}
if (eb.isEntryBlock() || eb.instructionIndex == eb.original.getLastInstructionIndex()) {
List<ExplodedBasicBlock> result = new ArrayList<ExplodedBasicBlock>();
@ -142,7 +142,7 @@ public class ExplodedControlFlowGraph implements ControlFlowGraph<ExplodedContro
}
return result;
} else {
return Collections.emptySet();
return Collections.emptyList();
}
}
@ -385,6 +385,10 @@ public class ExplodedControlFlowGraph implements ControlFlowGraph<ExplodedContro
public int getLastInstructionIndex() {
return instructionIndex;
}
public ExplodedControlFlowGraph getCFG() {
return ExplodedControlFlowGraph.this;
}
public IMethod getMethod() {
Assertions.UNREACHABLE();