use of soot.baf.ThrowInst in project soot by Sable.
the class ExceptionalUnitGraph method buildExceptionalEdges.
/**
* Method to compute the edges corresponding to exceptional control flow.
*
* @param throwAnalysis
* the source of information about the exceptions which each
* {@link Unit} may throw.
*
* @param unitToExceptionDests
* A <code>Map</code> from {@link Unit}s to {@link Collection}s
* of {@link ExceptionalUnitGraph.ExceptionDest ExceptionDest}s
* which represent the handlers that might catch exceptions
* thrown by the <code>Unit</code>. This is an ``in parameter''.
*
* @param unitToSuccs
* A <code>Map</code> from <code>Unit</code>s to {@link List}s of
* <code>Unit</code>s. This is an ``out parameter'';
* <code>buildExceptionalEdges</code> will add a mapping from
* every <code>Unit</code> in the body that may throw an
* exception that could be caught by a {@link Trap} in the body
* to a list of its exceptional successors.
*
* @param unitToPreds
* A <code>Map</code> from <code>Unit</code>s to
* <code>List</code>s of <code>Unit</code>s. This is an ``out
* parameter''; <code>buildExceptionalEdges</code> will add a
* mapping from each handler unit that may catch an exception to
* the list of <code>Unit</code>s whose exceptions it may catch.
* @param omitExceptingUnitEdges
* Indicates whether to omit exceptional edges from excepting
* units which lack side effects
*
* @return a {@link Set} of trap <code>Unit</code>s that might catch
* exceptions thrown by the first <code>Unit</code> in the
* {@link Body} associated with the graph being constructed. Such
* trap <code>Unit</code>s may need to be added to the list of heads
* (depending on your definition of heads), since they can be the
* first <code>Unit</code> in the <code>Body</code> which actually
* completes execution.
*/
protected Set<Unit> buildExceptionalEdges(ThrowAnalysis throwAnalysis, Map<Unit, Collection<ExceptionDest>> unitToExceptionDests, Map<Unit, List<Unit>> unitToSuccs, Map<Unit, List<Unit>> unitToPreds, boolean omitExceptingUnitEdges) {
Set<Unit> trapsThatAreHeads = new ArraySet<Unit>();
Unit entryPoint = unitChain.getFirst();
for (Entry<Unit, Collection<ExceptionDest>> entry : unitToExceptionDests.entrySet()) {
Unit thrower = entry.getKey();
List<Unit> throwersPreds = getUnexceptionalPredsOf(thrower);
Collection<ExceptionDest> dests = entry.getValue();
// We need to recognize:
// - caught exceptions for which we must add edges from the
// thrower's predecessors to the catcher:
// - all exceptions of non-throw instructions;
// - implicit exceptions of throw instructions.
//
// - caught exceptions where we must add edges from the
// thrower itself to the catcher:
// - any exception of non-throw instructions if
// omitExceptingUnitEdges is not set.
// - any exception of non-throw instructions with side effects.
// - explicit exceptions of throw instructions
// - implicit exceptions of throw instructions if
// omitExceptingUnitEdges is not set.
// - implicit exceptions of throw instructions with possible
// side effects (this is only possible for the grimp
// IR, where the throw's argument may be an
// expression---probably a NewInvokeExpr---which
// might have executed partially before the
// exception arose).
//
// Note that a throw instruction may be capable of throwing a given
// Throwable type both implicitly and explicitly.
//
// We track these situations using predThrowables and
// selfThrowables. Essentially predThrowables is the set
// of Throwable types to whose catchers there should be
// edges from predecessors of the thrower, while
// selfThrowables is the set of Throwable types to whose
// catchers there should be edges from the thrower itself,
// but we we take some short cuts to avoid calling
// ThrowableSet.catchableAs() when we can avoid it.
boolean alwaysAddSelfEdges = ((!omitExceptingUnitEdges) || mightHaveSideEffects(thrower));
ThrowableSet predThrowables = null;
ThrowableSet selfThrowables = null;
if (thrower instanceof ThrowInst) {
ThrowInst throwInst = (ThrowInst) thrower;
predThrowables = throwAnalysis.mightThrowImplicitly(throwInst);
selfThrowables = throwAnalysis.mightThrowExplicitly(throwInst);
} else if (thrower instanceof ThrowStmt) {
ThrowStmt throwStmt = (ThrowStmt) thrower;
predThrowables = throwAnalysis.mightThrowImplicitly(throwStmt);
selfThrowables = throwAnalysis.mightThrowExplicitly(throwStmt);
}
for (ExceptionDest dest : dests) {
if (dest.getTrap() != null) {
Unit catcher = dest.getTrap().getHandlerUnit();
RefType trapsType = dest.getTrap().getException().getType();
if (predThrowables == null || predThrowables.catchableAs(trapsType)) {
// catcher.
if (thrower == entryPoint) {
trapsThatAreHeads.add(catcher);
}
for (Unit pred : throwersPreds) {
addEdge(unitToSuccs, unitToPreds, pred, catcher);
}
}
if (alwaysAddSelfEdges || (selfThrowables != null && selfThrowables.catchableAs(trapsType))) {
addEdge(unitToSuccs, unitToPreds, thrower, catcher);
}
}
}
}
// worklist containing CFG edges that lead to such a handler.
class CFGEdge {
// If null, represents an edge to the handler
Unit head;
// from the fictitious "predecessor" of the
// very first unit in the chain. I.e., tail
// is a handler which might be reached as a
// result of an exception thrown by the
// first Unit in the Body.
Unit tail;
CFGEdge(Unit head, Unit tail) {
if (tail == null)
throw new RuntimeException("invalid CFGEdge(" + (head == null ? "null" : head.toString()) + ',' + "null" + ')');
this.head = head;
this.tail = tail;
}
@Override
public boolean equals(Object rhs) {
if (rhs == this) {
return true;
}
if (!(rhs instanceof CFGEdge)) {
return false;
}
CFGEdge rhsEdge = (CFGEdge) rhs;
return ((this.head == rhsEdge.head) && (this.tail == rhsEdge.tail));
}
@Override
public int hashCode() {
// Following Joshua Bloch's recipe in "Effective Java", Item 8:
int result = 17;
result = 37 * result + this.head.hashCode();
result = 37 * result + this.tail.hashCode();
return result;
}
}
LinkedList<CFGEdge> workList = new LinkedList<CFGEdge>();
for (Trap trap : body.getTraps()) {
Unit handlerStart = trap.getHandlerUnit();
if (mightThrowToIntraproceduralCatcher(handlerStart)) {
List<Unit> handlerPreds = getUnexceptionalPredsOf(handlerStart);
for (Unit pred : handlerPreds) {
workList.addLast(new CFGEdge(pred, handlerStart));
}
handlerPreds = getExceptionalPredsOf(handlerStart);
for (Unit pred : handlerPreds) {
workList.addLast(new CFGEdge(pred, handlerStart));
}
if (trapsThatAreHeads.contains(handlerStart)) {
workList.addLast(new CFGEdge(null, handlerStart));
}
}
}
// the handler's exception.
while (workList.size() > 0) {
CFGEdge edgeToThrower = workList.removeFirst();
Unit pred = edgeToThrower.head;
Unit thrower = edgeToThrower.tail;
Collection<ExceptionDest> throwerDests = getExceptionDests(thrower);
for (ExceptionDest dest : throwerDests) {
if (dest.getTrap() != null) {
Unit handlerStart = dest.getTrap().getHandlerUnit();
boolean edgeAdded = false;
if (pred == null) {
if (!trapsThatAreHeads.contains(handlerStart)) {
trapsThatAreHeads.add(handlerStart);
edgeAdded = true;
}
} else {
if (!getExceptionalSuccsOf(pred).contains(handlerStart)) {
addEdge(unitToSuccs, unitToPreds, pred, handlerStart);
edgeAdded = true;
}
}
if (edgeAdded && mightThrowToIntraproceduralCatcher(handlerStart)) {
workList.addLast(new CFGEdge(pred, handlerStart));
}
}
}
}
return trapsThatAreHeads;
}
Aggregations