All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.toolkits.graph.ExceptionalUnitGraph Maven / Gradle / Ivy

There is a newer version: 1.12.0
Show newest version
/* Soot - a J*va Optimization Framework
 * Copyright (C) 1999 Patrice Pominville, Raja Vallee-Rai
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the Sable Research Group and others 1997-2004.  
 * See the 'credits' file distributed with Soot for the complete list of
 * contributors.  (Soot is distributed at http://www.sable.mcgill.ca/soot)
 */


 



package soot.toolkits.graph;

import soot.*;
import soot.util.*;
import java.util.*;
import java.util.Map.Entry;

import soot.options.Options;
import soot.toolkits.exceptions.ThrowAnalysis;
import soot.toolkits.exceptions.ThrowableSet;
import soot.jimple.Stmt;
import soot.jimple.ThrowStmt;
import soot.jimple.StaticFieldRef;
import soot.jimple.InvokeExpr;
import soot.jimple.NewExpr;


/**
 *  

Represents a control flow graph for a {@link Body} instance * where the nodes are {@link Unit} instances, and where control flow * associated with exceptions is taken into account.

* *

To describe precisely the circumstances under which exceptional * edges are added to the graph, we need to distinguish the * exceptions thrown explicitly by a throw instruction * from the exceptions which are thrown implicitly by the VM to * signal an error it encounters in the course of executing * an instruction, which need not be a throw.

* *

For every {@link ThrowInst} or {@link ThrowStmt} * Unit which may explicitly throw an exception that * would be caught by a {@link Trap} in the Body, there * will be an edge from the throw Unit to * the Trap handler's first Unit.

* *

For every Unit which may implicitly throw an * exception that could be caught by a Trap in the * Body, there will be an edge from each of the * excepting Unit's predecessors to the * Trap handler's first Unit (since any of * those predecessors may have been the last Unit to * complete execution before the handler starts execution). If the * excepting Unit might have the side effect of changing * some field, then there will definitely be an edge from the excepting * Unit itself to its handlers, since the side effect * might occur before the exception is raised. If the excepting * Unit has no side effects, then parameters passed to * the ExceptionalUnitGraph constructor determine * whether or not there is an edge from the excepting * Unit itself to the handler Unit.

*/ public class ExceptionalUnitGraph extends UnitGraph implements ExceptionalGraph { protected Map> unitToUnexceptionalSuccs; // If there are no Traps within protected Map> unitToUnexceptionalPreds; // the method, these will be the // same maps as unitToSuccs and // unitToPreds. protected Map> unitToExceptionalSuccs; protected Map> unitToExceptionalPreds; protected Map> unitToExceptionDests; protected ThrowAnalysis throwAnalysis; // Cached reference to the // analysis used to generate this // graph, for generating responses // to getExceptionDests() on the // fly for nodes from which all // exceptions escape the method. /** * Constructs the graph for a given Body instance, using the * ThrowAnalysis and omitExceptingUnitEdges * value that are passed as parameters. * * @param body the Body from which to build a graph. * * @param throwAnalysis the source of information about the exceptions * which each {@link Unit} may throw. * * @param omitExceptingUnitEdges indicates whether the CFG should * omit edges to a handler from trapped * Units which may implicitly throw an * exception which the handler catches but * which have no potential side effects. * The CFG will contain edges to the handler * from all predecessors of * Units which may implicitly throw * a caught exception regardless of the setting for * this parameter. If this parameter is * false, there will also be * edges to the handler from all the * potentially excepting Units * themselves. If this parameter is * true, there will be edges to * the handler from the excepting * Units themselves only if they * have potential side effects (or if they * are themselves the predecessors of other * potentially excepting Units). * A setting of true produces * CFGs which allow for more precise * analyses, since a Unit without * side effects has no effect on the * computational state when it throws an * exception. Use settings of * false for compatibility with * more conservative analyses, or to cater * to conservative bytecode verifiers. */ public ExceptionalUnitGraph(Body body, ThrowAnalysis throwAnalysis, boolean omitExceptingUnitEdges) { super(body); initialize(throwAnalysis, omitExceptingUnitEdges); } /** * Constructs the graph from a given Body instance using the * passed {@link ThrowAnalysis} and a default value, provided by * the {@link Options} class, for the * omitExceptingUnitEdges parameter. * * @param body the {@link Body} from which to build a graph. * * @param throwAnalysis the source of information about the exceptions * which each {@link Unit} may throw. * */ public ExceptionalUnitGraph(Body body, ThrowAnalysis throwAnalysis) { this(body, throwAnalysis, Options.v().omit_excepting_unit_edges()); } /** * Constructs the graph from a given Body instance, using the * {@link Scene}'s default {@link ThrowAnalysis} to estimate the * set of exceptions that each {@link Unit} might throw and a * default value, provided by the {@link Options} class, for the * omitExceptingUnitEdges parameter. * * @param body the Body from which to build a graph. * */ public ExceptionalUnitGraph(Body body) { this(body, Scene.v().getDefaultThrowAnalysis(), Options.v().omit_excepting_unit_edges()); } /** *

Allocates an ExceptionalUnitGraph object * without initializing it. This “partial * constructor” is provided for the benefit of subclasses * whose constructors need to perform some subclass-specific * processing before actually creating the graph edges (because, * for example, the subclass overrides a utility method like * {@link #buildExceptionDests(ThrowAnalysis)} or {@link * #buildExceptionalEdges(ThrowAnalysis, Map, Map, Map, boolean)} * with a replacement method that depends on additional * parameters passed to the subclass's constructor). The * subclass constructor is responsible for calling {@link * #initialize(ThrowAnalysis, boolean)}, or otherwise performing * the initialization required to implement * ExceptionalUnitGraph's interface.

* *

Clients who opt to extend ExceptionalUnitGraph * should be warned that the class has not been carefully * designed for inheritance; code that uses the * protected members of this class may need to be * rewritten for each new Soot release.

* * @param body the Body from which to build a graph. * * @param ignoredBogusParameter a meaningless placeholder, which exists * solely to distinguish this * constructor from the public * {@link #ExceptionalUnitGraph(Body)} * constructor. */ protected ExceptionalUnitGraph(Body body, boolean ignoredBogusParameter) { super(body); } /** * Performs the real work of constructing an * ExceptionalUnitGraph, factored out of the * constructors so that subclasses have the option to delay * creating the graph's edges until after they have performed * some subclass-specific initialization. * * @param throwAnalysis the source of information about the exceptions * which each {@link Unit} may throw. * * @param omitExceptingUnitEdges indicates whether the CFG should * omit edges to a handler from trapped * Units which may throw an * exception which the handler catches but * which have no potential side effects. */ protected void initialize(ThrowAnalysis throwAnalysis, boolean omitExceptingUnitEdges) { int size = unitChain.size(); Set trapUnitsThatAreHeads = Collections.emptySet(); if(Options.v().time()) Timers.v().graphTimer.start(); unitToUnexceptionalSuccs = new HashMap>(size * 2 + 1, 0.7f); unitToUnexceptionalPreds = new HashMap>(size * 2 + 1, 0.7f); buildUnexceptionalEdges(unitToUnexceptionalSuccs, unitToUnexceptionalPreds); makeMappedListsUnmodifiable(unitToUnexceptionalSuccs); makeMappedListsUnmodifiable(unitToUnexceptionalPreds); this.throwAnalysis = throwAnalysis; if (body.getTraps().size() == 0) { // No handlers, so all exceptional control flow exits the // method. unitToExceptionDests = Collections.emptyMap(); unitToExceptionalSuccs = Collections.emptyMap(); unitToExceptionalPreds = Collections.emptyMap(); unitToSuccs = unitToUnexceptionalSuccs; unitToPreds = unitToUnexceptionalPreds; } else { unitToExceptionDests = buildExceptionDests(throwAnalysis); unitToExceptionalSuccs = new HashMap>(unitToExceptionDests.size() * 2 + 1, 0.7f); unitToExceptionalPreds = new HashMap>(body.getTraps().size() * 2 + 1, 0.7f); trapUnitsThatAreHeads = buildExceptionalEdges(throwAnalysis, unitToExceptionDests, unitToExceptionalSuccs, unitToExceptionalPreds, omitExceptingUnitEdges); makeMappedListsUnmodifiable(unitToExceptionalSuccs); makeMappedListsUnmodifiable(unitToExceptionalPreds); // We'll need separate maps for the combined // exceptional and unexceptional edges: unitToSuccs = combineMapValues(unitToUnexceptionalSuccs, unitToExceptionalSuccs); unitToPreds = combineMapValues(unitToUnexceptionalPreds, unitToExceptionalPreds); } buildHeadsAndTails(trapUnitsThatAreHeads); if(Options.v().time()) Timers.v().graphTimer.end(); } /** *

Utility method used in the construction of * {@link soot.toolkits.graph.UnitGraph UnitGraph} * variants which include exceptional control flow. It determines * which {@link Unit}s may throw exceptions that would be caught * by {@link Trap}s within the method.

* * @param throwAnalysis The source of information about which * exceptions each Unit may throw. * * @return null if no Units in the method throw * any exceptions caught within the method. Otherwise, a * {@link Map} from Units to {@link * Collection}s of {@link ExceptionDest}s. * *

The returned map has an idiosyncracy which is hidden * from most client code, but which is exposed to * subclasses extending ExceptionalUnitGraph. * If a Unit throws one or more exceptions * which are caught within the method, it will be mapped * to a Collection of * ExceptionDests describing the sets of * exceptions that the Unit might throw to * each {@link Trap}. But if all of a Unit's * exceptions escape the method, it will be mapped to * nullCollection containing a single * ExceptionDest with a null * trap. (The special case for Units with * no caught exceptions allows * buildExceptionDests() to ignore completely * Units which are outside the scope of all * Traps.)

*/ protected Map> buildExceptionDests(ThrowAnalysis throwAnalysis) { Chain units = body.getUnits(); Map unitToUncaughtThrowables = new HashMap(units.size()); Map> result = null; // Record the caught exceptions. for (Iterator trapIt = body.getTraps().iterator(); trapIt.hasNext(); ) { Trap trap = trapIt.next(); RefType catcher = trap.getException().getType(); for (Iterator unitIt = units.iterator(trap.getBeginUnit(), units.getPredOf(trap.getEndUnit())); unitIt.hasNext(); ) { Unit unit = unitIt.next(); ThrowableSet thrownSet = unitToUncaughtThrowables.get(unit); if (thrownSet == null) { thrownSet = throwAnalysis.mightThrow(unit); } ThrowableSet.Pair catchableAs = thrownSet.whichCatchableAs(catcher); if (catchableAs.getCaught() != ThrowableSet.Manager.v().EMPTY) { result = addDestToMap(result, unit, trap, catchableAs.getCaught()); unitToUncaughtThrowables.put(unit, catchableAs.getUncaught()); } else { // An assertion check: if (thrownSet != catchableAs.getUncaught()) { throw new IllegalStateException("ExceptionalUnitGraph.buildExceptionDests(): catchableAs.caught == EMPTY, but catchableAs.uncaught != thrownSet" + System.getProperty("line.separator") + body.getMethod().getSubSignature() + " Unit: " + unit.toString() + System.getProperty("line.separator") + " catchableAs.getUncaught() == " + catchableAs.getUncaught().toString() + System.getProperty("line.separator") + " thrownSet == " + thrownSet.toString()); } } } } for (Map.Entry entry : unitToUncaughtThrowables.entrySet()) { Unit unit = (Unit) entry.getKey(); ThrowableSet escaping = (ThrowableSet) entry.getValue(); if (escaping != ThrowableSet.Manager.v().EMPTY) { result = addDestToMap(result, unit, null, escaping); } } if (result == null) { result = Collections.emptyMap(); } return result; } /** * A utility method for recording the exceptions that a * Unit throws to a particular Trap. * Note that this method relies on the fact that the call to add * escaping exceptions for a Unit will always follow * all calls for its caught exceptions. * * @param map A Map from Units to * Collections of ExceptionDests. * null if no exceptions have been recorded yet. * * @param u The Unit throwing the exceptions. * * @param t The Trap which catches the exceptions, or * null if the exceptions escape the method. * * @param caught The set of exception types thrown by u which * are caught by t. * * @return a Map which whose contents are equivalent to the * input map, plus the information that u * throws caught to t. */ private Map> addDestToMap (Map> map, Unit u, Trap t, ThrowableSet caught) { Collection dests = (map == null ? null : map.get(u)); if (dests == null) { if (t == null) { // All exceptions from u escape, so don't record any. return map; } else { if (map == null) { map = new HashMap>(unitChain.size() * 2 + 1); } dests = new ArrayList(3); map.put(u, dests); } } dests.add(new ExceptionDest(t, caught)); return map; } /** * 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 unitToExceptionDests2 A Map 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 * Unit. This is an ``in * parameter''. * * @param unitToSuccs A Map from Units to * {@link List}s of Units. This is * an ``out parameter''; * buildExceptionalEdges will add * a mapping from every Unit 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 Map from Units to * Lists of * Units. This is an ``out * parameter''; * buildExceptionalEdges will add * a mapping from each handler unit that may * catch an exception to the list of * Units 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 Units that might catch * exceptions thrown by the first Unit in the * {@link Body} associated with the graph being * constructed. Such trap Units may need to * be added to the list of heads (depending on your * definition of heads), since they can be the first * Unit in the Body which * actually completes execution. */ protected Set buildExceptionalEdges(ThrowAnalysis throwAnalysis, Map> unitToExceptionDests, Map> unitToSuccs, Map> unitToPreds, boolean omitExceptingUnitEdges) { Set trapsThatAreHeads = new ArraySet(); Unit entryPoint = (Unit) unitChain.getFirst(); for (Iterator>> it = unitToExceptionDests.entrySet().iterator(); it.hasNext(); ) { Entry> entry = it.next(); Unit thrower = (Unit) entry.getKey(); List throwersPreds = getUnexceptionalPredsOf(thrower); Collection 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 ThrowStmt) { ThrowStmt throwStmt = (ThrowStmt) thrower; predThrowables = throwAnalysis.mightThrowImplicitly(throwStmt); selfThrowables = throwAnalysis.mightThrowExplicitly(throwStmt); } for (Iterator destIt = dests.iterator(); destIt.hasNext(); ) { ExceptionDest dest = destIt.next(); if (dest.getTrap() != null) { Unit catcher = dest.getTrap().getHandlerUnit(); RefType trapsType = dest.getTrap().getException().getType(); if (predThrowables == null || predThrowables.catchableAs(trapsType)) { // Add edges from the thrower's predecessors to the catcher. if (thrower == entryPoint) { trapsThatAreHeads.add(catcher); } for (Iterator p = throwersPreds.iterator(); p.hasNext(); ) { Unit pred = p.next(); addEdge(unitToSuccs, unitToPreds, pred, catcher); } } if (alwaysAddSelfEdges || (selfThrowables != null && selfThrowables.catchableAs(trapsType))) { addEdge(unitToSuccs, unitToPreds, thrower, catcher); } } } } // Now we have to worry about transitive exceptional // edges, when a handler might itself throw an exception // that is caught within the method. For that we need a // worklist containing CFG edges that lead to such a handler. class CFGEdge { Unit head; // If null, represents an edge to the handler // 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.toString() + ',' + "null" + ')'); this.head = head; this.tail = tail; } 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)); } 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 workList = new LinkedList(); for (Iterator trapIt = body.getTraps().iterator(); trapIt.hasNext(); ) { Trap trap = trapIt.next(); Unit handlerStart = trap.getHandlerUnit(); if (mightThrowToIntraproceduralCatcher(handlerStart)) { List handlerPreds = getUnexceptionalPredsOf(handlerStart); for (Iterator it = handlerPreds.iterator(); it.hasNext(); ) { Unit pred = it.next(); workList.addLast(new CFGEdge(pred, handlerStart)); } handlerPreds = getExceptionalPredsOf(handlerStart); for (Iterator it = handlerPreds.iterator(); it.hasNext(); ) { Unit pred = it.next(); workList.addLast(new CFGEdge(pred, handlerStart)); } if (trapsThatAreHeads.contains(handlerStart)) { workList.addLast(new CFGEdge(null, handlerStart)); } } } // Now for every CFG edge that leads to a handler that may // itself throw an exception catchable within the method, add // edges from the head of that edge to the unit that catches // the handler's exception. while (workList.size() > 0) { CFGEdge edgeToThrower = workList.removeFirst(); Unit pred = edgeToThrower.head; Unit thrower = edgeToThrower.tail; Collection throwerDests = getExceptionDests(thrower); for (Iterator i = throwerDests.iterator(); i.hasNext(); ) { ExceptionDest dest = i.next(); 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; } /** *

Utility method for checking if a {@link Unit} might have side * effects. It simply returns true for any unit which invokes a * method directly or which might invoke static initializers * indirectly (by creating a new object or by refering to a static * field; see sections 2.17.4, 2.17.5, and 5.5 of the Java Virtual * Machine Specification).

* * mightHaveSideEffects() is declared package-private * so that it is available to unit tests that are part of this * package. * * @param u The unit whose potential for side effects is to be checked. * * @return whether or not u has the potential for side effects. */ static boolean mightHaveSideEffects(Unit u) { for (Iterator it = u.getUseBoxes().iterator(); it.hasNext(); ) { Value v = it.next().getValue(); if ((v instanceof StaticFieldRef) || (v instanceof InvokeExpr) || (v instanceof NewExpr)) { return true; } } return false; } /** * Utility method for checking if a Unit might throw an exception which * may be caught by a {@link Trap} within this method. * * @param u The unit for whose exceptions are to be checked * * @return whether or not u may throw an exception which may be * caught by a Trap in this method, */ private boolean mightThrowToIntraproceduralCatcher(Unit u) { Collection dests = getExceptionDests(u); for (Iterator i = dests.iterator(); i.hasNext(); ) { ExceptionDest dest = i.next(); if (dest.getTrap() != null) { return true; } } return false; } /** *

A placeholder that overrides {@link UnitGraph#buildHeadsAndTails()} * with a method which always throws an exception. The placeholder serves * to indicate that ExceptionalUnitGraph does not use * buildHeadsAndTails(), and to document the conditions under * which ExceptionalUnitGraph considers a node to be a head or * tail.

* *

ExceptionalUnitGraph defines the graph's set of * heads to include the first {@link Unit} in the graph's body, * together with the first Unit in any exception * handler which might catch an exception thrown by the first * Unit in the body (because any of those * Units might be the first to successfully complete * execution). ExceptionalUnitGraph defines the * graph's set of tails to include all Units which * represent some variety of return bytecode or an * athrow bytecode whose argument might escape the * method.

*/ protected void buildHeadsAndTails() throws IllegalStateException { throw new IllegalStateException("ExceptionalUnitGraph uses buildHeadsAndTails(List) instead of buildHeadsAndTails()"); } /** * Utility method, to be called only after the unitToPreds and * unitToSuccs maps have been built. It defines the graph's set of * heads to include the first {@link Unit} in the graph's body, * together with all the Units in * additionalHeads. It defines the graph's set of * tails to include all Units which represent some * sort of return bytecode or an athrow bytecode * which may escape the method. */ private void buildHeadsAndTails(Set additionalHeads) { List headList = new ArrayList(additionalHeads.size() + 1); headList.addAll(additionalHeads); Unit entryPoint = (Unit) unitChain.getFirst(); if (! headList.contains(entryPoint)) { headList.add(entryPoint); } List tailList = new ArrayList(); for (Iterator it = unitChain.iterator(); it.hasNext(); ) { Unit u = (Unit) it.next(); if (u instanceof soot.jimple.ReturnStmt || u instanceof soot.jimple.ReturnVoidStmt) { tailList.add(u); } else if (u instanceof soot.jimple.ThrowStmt) { Collection dests = getExceptionDests(u); int escapeMethodCount = 0; for (Iterator destIt = dests.iterator(); destIt.hasNext(); ) { ExceptionDest dest = destIt.next(); if (dest.getTrap() == null) { escapeMethodCount++; } } if (escapeMethodCount > 0) { tailList.add(u); } } } tails = Collections.unmodifiableList(tailList); heads = Collections.unmodifiableList(headList); } /** * Returns a collection of * {@link ExceptionalUnitGraph.ExceptionDest ExceptionDest} * objects which represent how exceptions thrown by a specified * unit will be handled. * * @param u The unit for which to provide exception information. * (u must be a Unit, though the parameter is * declared as an Object to satisfy the interface of * {@link soot.toolkits.graph.ExceptionalGraph ExceptionalGraph}. * * @return a collection of ExceptionDest objects describing * the traps, if any, which catch the exceptions * which may be thrown by u. */ public Collection getExceptionDests(Unit u) { Collection result = (Collection) unitToExceptionDests.get(u); if (result == null) { result = new LinkedList(); result.add(new ExceptionDest(null, throwAnalysis.mightThrow((Unit) u))); } return result; } public static class ExceptionDest implements ExceptionalGraph.ExceptionDest { private Trap trap; private ThrowableSet throwables; protected ExceptionDest(Trap trap, ThrowableSet throwables) { this.trap = trap; this.throwables = throwables; } public Trap getTrap() { return trap; } public ThrowableSet getThrowables() { return throwables; } public Unit getHandlerNode() { if (trap == null) { return null; } else { return trap.getHandlerUnit(); } } public String toString() { StringBuffer buf = new StringBuffer(); buf.append(throwables.toString()); buf.append(" -> "); if (trap == null) { buf.append("(escapes)"); } else { buf.append(trap.toString()); } return buf.toString(); } } public List getUnexceptionalPredsOf(Unit u) { if (!unitToUnexceptionalPreds.containsKey(u)) throw new RuntimeException("Invalid unit " + u); return (List) unitToUnexceptionalPreds.get(u); } public List getUnexceptionalSuccsOf(Unit u) { if (!unitToUnexceptionalSuccs.containsKey(u)) throw new RuntimeException("Invalid unit " + u); return (List) unitToUnexceptionalSuccs.get(u); } public List getExceptionalPredsOf(Unit u) { if (!unitToExceptionalPreds.containsKey(u)) { return Collections.emptyList(); } else { return (List) unitToExceptionalPreds.get(u); } } public List getExceptionalSuccsOf(Unit u) { if (!unitToExceptionalSuccs.containsKey(u)) { return Collections.emptyList(); } else { return (List) unitToExceptionalSuccs.get(u); } } /** *

Return the {@link ThrowAnalysis} used to construct this * graph, if the graph contains no {@link Trap}s, or * null if the graph does contain * Traps. A reference to the * ThrowAnalysis is kept when there are no * Traps so that the graph can generate responses to * {@link #getExceptionDests(Object)} on the fly, rather than precomputing * information that may never be needed.

* *

This method is package-private because it exposes a detail * of the implementation of ExceptionalUnitGraph so * that the * {@link soot.toolkits.graph.ExceptionalBlockGraph ExceptionalBlockGraph} * constructor can cache the same ThrowAnalysis for * the same purpose. * * @return the {@link ThrowAnalysis} used to generate this graph if the * graph contains no {@link Trap}s, or null if the graph * contains one or more {@link Trap}s. */ ThrowAnalysis getThrowAnalysis() { return throwAnalysis; } public String toString() { Iterator it = unitChain.iterator(); StringBuffer buf = new StringBuffer(); while(it.hasNext()) { Unit u = it.next(); buf.append(" preds: "+getPredsOf(u)+"\n"); buf.append(" unexceptional preds: "+getUnexceptionalPredsOf(u)+"\n"); buf.append(" exceptional preds: "+getExceptionalPredsOf(u)+"\n"); buf.append(u.toString() + '\n'); buf.append(" exception destinations: "+getExceptionDests(u)+"\n"); buf.append(" unexceptional succs: "+getUnexceptionalSuccsOf(u)+"\n"); buf.append(" exceptional succs: "+getExceptionalSuccsOf(u)+"\n"); buf.append(" succs "+getSuccsOf(u)+"\n\n"); } return buf.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy