diff --git a/src/main/java/soot/toolkits/exceptions/ThrowableSet.java b/src/main/java/soot/toolkits/exceptions/ThrowableSet.java index 7e4c44ebd58..4e71b7b404d 100644 --- a/src/main/java/soot/toolkits/exceptions/ThrowableSet.java +++ b/src/main/java/soot/toolkits/exceptions/ThrowableSet.java @@ -87,11 +87,15 @@ * with a given name. *

*/ - public class ThrowableSet { private static final boolean INSTRUMENTING = false; - private final SootClass JAVA_LANG_OBJECT_CLASS = Scene.v().getObjectType().getSootClass(); + + // This pattern allows for the field to be static but to delay it's + // initialization until it's first use. + private static final class LazyInit { + static final SootClass JAVA_LANG_OBJECT_CLASS = Scene.v().getObjectType().getSootClass(); + } /** * Set of exception types included within the set. @@ -121,24 +125,23 @@ public class ThrowableSet { * @param exclude * The set of {@link AnySubType} objects representing the types to be excluded from the set. */ - protected ThrowableSet(Set include, Set exclude) { + private ThrowableSet(Set include, Set exclude) { exceptionsIncluded = getImmutable(include); exceptionsExcluded = getImmutable(exclude); - // We don't need to clone include and exclude to guarantee - // immutability since ThrowableSet(Set,Set) is private to this - // class, where it is only called (via - // Manager.v().registerSetIfNew()) with arguments which the + // We don't need to clone include and exclude to guarantee immutability + // since ThrowableSet(Set,Set) is private to this class, where it is only + // called (via Manager.v().registerSetIfNew()) with arguments which the // callers do not subsequently modify. } private static Set getImmutable(Set in) { - if ((null == in) || in.isEmpty()) { + if (in == null || in.isEmpty()) { return Collections.emptySet(); - } - if (1 == in.size()) { + } else if (in.size() == 1) { return Collections.singleton(in.iterator().next()); + } else { + return Collections.unmodifiableSet(in); } - return Collections.unmodifiableSet(in); } /** @@ -201,9 +204,9 @@ private void addToMemoizedAdds(Object key, ThrowableSet value) { * * @return a set containing e as well as the exceptions in this set. * - * @throws {@link - * ThrowableSet.IllegalStateException} if this ThrowableSet is the result of a - * {@link #whichCatchableAs(RefType)} operation and, thus, unable to represent the addition of e. + * @throws IllegalStateException + * if this ThrowableSet is the result of a {@link #whichCatchableAs(RefType)} operation and, thus, + * unable to represent the addition of e. */ public ThrowableSet add(RefType e) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { @@ -275,7 +278,7 @@ public ThrowableSet add(RefType e) throws ThrowableSet.AlreadyHasExclusionsExcep private boolean hasNoHierarchy(RefType type) { final SootClass sootClass = type.getSootClass(); - return !(sootClass.hasSuperclass() || JAVA_LANG_OBJECT_CLASS == sootClass); + return !(sootClass.hasSuperclass() || LazyInit.JAVA_LANG_OBJECT_CLASS == sootClass); } /** @@ -535,14 +538,7 @@ private ThrowableSet add(Set addedExceptions) { } } } - - ThrowableSet result = null; - if (changes > 0) { - result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); - } else { - result = this; - } - return result; + return (changes > 0) ? Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded) : this; } /** @@ -570,14 +566,7 @@ private ThrowableSet remove(Set removedExceptions) { } } } - - ThrowableSet result = null; - if (changes > 0) { - result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); - } else { - result = this; - } - return result; + return (changes > 0) ? Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded) : this; } /** @@ -646,7 +635,7 @@ public boolean catchableAs(RefType catcher) { if (exceptionsIncluded.contains(catcher)) { if (INSTRUMENTING) { - if (exceptionsExcluded.size() == 0) { + if (exceptionsExcluded.isEmpty()) { Manager.v().catchableAsFromMap++; } else { Manager.v().catchableAsFromSearch++; @@ -655,7 +644,7 @@ public boolean catchableAs(RefType catcher) { return true; } else { if (INSTRUMENTING) { - if (exceptionsExcluded.size() == 0) { + if (exceptionsExcluded.isEmpty()) { Manager.v().catchableAsFromSearch++; } } @@ -671,13 +660,11 @@ public boolean catchableAs(RefType catcher) { } else { RefType thrownBase = ((AnySubType) thrownType).getBase(); if (catcherHasNoHierarchy) { - if (thrownBase.equals(catcher) || thrownBase.getClassName().equals("java.lang.Throwable")) { + if (thrownBase.equals(catcher) || "java.lang.Throwable".equals(thrownBase.getClassName())) { return true; } - } - // At runtime, thrownType might be instantiated by any - // of thrownBase's subtypes, so: - else if (h.canStoreType(thrownBase, catcher) || h.canStoreType(catcher, thrownBase)) { + } else if (h.canStoreType(thrownBase, catcher) || h.canStoreType(catcher, thrownBase)) { + // At runtime, thrownType might be instantiated by any of thrownBase's subtypes return true; } } @@ -760,7 +747,7 @@ public Pair whichCatchableAs(RefType catcher) { if (base.equals(catcher)) { caughtIncluded = addExceptionToSet(inclusion, caughtIncluded); } else { - if (base.getClassName().equals("java.lang.Throwable")) { + if ("java.lang.Throwable".equals(base.getClassName())) { caughtIncluded = addExceptionToSet(catcher, caughtIncluded); } uncaughtIncluded = addExceptionToSet(inclusion, uncaughtIncluded); @@ -818,7 +805,7 @@ private Set addExceptionToSet(T e, Set set) { */ @Override public String toString() { - StringBuffer buffer = new StringBuffer(this.toBriefString()); + StringBuilder buffer = new StringBuilder(this.toBriefString()); buffer.append(":\n "); for (RefLikeType ei : exceptionsIncluded) { buffer.append('+'); @@ -882,7 +869,7 @@ private String toAbbreviatedString(Set s, char connector) Collection vmErrorThrowables = ThrowableSet.Manager.v().VM_ERRORS.exceptionsIncluded; boolean containsAllVmErrors = s.containsAll(vmErrorThrowables); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); if (containsAllVmErrors) { buf.append(connector); @@ -1161,7 +1148,8 @@ public static Manager v() { * @return a ThrowableSet representing the set of exceptions corresponding to include - * exclude. */ - protected ThrowableSet registerSetIfNew(Set include, Set exclude) { + private ThrowableSet registerSetIfNew(Set include, Set exclude) { + //NOTE: This method must be private in accordance with the comment in the ThrowableSet constructor. if (INSTRUMENTING) { registrationCalls++; } @@ -1181,9 +1169,7 @@ protected ThrowableSet registerSetIfNew(Set include, SetThrowableSet.Pair. @@ -1270,10 +1257,7 @@ public boolean equals(Object o) { return false; } Pair tsp = (Pair) o; - if (this.caught.equals(tsp.caught) && this.uncaught.equals(tsp.uncaught)) { - return true; - } - return false; + return this.caught.equals(tsp.caught) && this.uncaught.equals(tsp.uncaught); } @Override @@ -1287,7 +1271,6 @@ public int hashCode() { /** * Comparator used to implement sortedThrowableIterator(). - * */ private static class ThrowableComparator implements java.util.Comparator { @@ -1322,6 +1305,5 @@ public int compare(T o1, T o2) { return t1.toString().compareTo(t2.toString()); } } - } } diff --git a/src/main/java/soot/toolkits/graph/ExceptionalUnitGraph.java b/src/main/java/soot/toolkits/graph/ExceptionalUnitGraph.java index 32ebac07cf4..63d2729c50f 100644 --- a/src/main/java/soot/toolkits/graph/ExceptionalUnitGraph.java +++ b/src/main/java/soot/toolkits/graph/ExceptionalUnitGraph.java @@ -255,47 +255,50 @@ protected void initialize(ThrowAnalysis throwAnalysis, boolean omitExceptingUnit * 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 nullUnit's exceptions escape the method, it will be mapped to null, rather than to a * Collection 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 LinkedHashMap(units.size()); Map> result = null; - // Record the caught exceptions. - for (Trap trap : body.getTraps()) { - 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); - } + final Chain traps = body.getTraps(); + if (!traps.isEmpty()) { + final ThrowableSet EMPTY = ThrowableSet.Manager.v().EMPTY; + final Chain units = body.getUnits(); + final Map unitToUncaughtThrowables = new LinkedHashMap(units.size()); + + // Record the caught exceptions. + for (Trap trap : traps) { + RefType catcher = trap.getException().getType(); + for (Iterator it = units.iterator(trap.getBeginUnit(), units.getPredOf(trap.getEndUnit())); it.hasNext();) { + Unit unit = it.next(); + ThrowableSet thrownSet = unitToUncaughtThrowables.get(unit); + if (thrownSet == null) { + thrownSet = throwAnalysis.mightThrow(unit); + } - ThrowableSet.Pair catchableAs = thrownSet.whichCatchableAs(catcher); - if (!catchableAs.getCaught().equals(ThrowableSet.Manager.v().EMPTY)) { - result = addDestToMap(result, unit, trap, catchableAs.getCaught()); - unitToUncaughtThrowables.put(unit, catchableAs.getUncaught()); - } else { - assert thrownSet.equals(catchableAs.getUncaught()) : "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(); + ThrowableSet.Pair catchableAs = thrownSet.whichCatchableAs(catcher); + if (!EMPTY.equals(catchableAs.getCaught())) { + result = addDestToMap(result, unit, trap, catchableAs.getCaught()); + unitToUncaughtThrowables.put(unit, catchableAs.getUncaught()); + } else { + assert thrownSet.equals(catchableAs.getUncaught()) : "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 = entry.getKey(); - ThrowableSet escaping = entry.getValue(); - if (escaping != ThrowableSet.Manager.v().EMPTY) { - result = addDestToMap(result, unit, null, escaping); + for (Map.Entry entry : unitToUncaughtThrowables.entrySet()) { + ThrowableSet escaping = entry.getValue(); + if (escaping != EMPTY) { + result = addDestToMap(result, entry.getKey(), null, escaping); + } } } return result == null ? Collections.emptyMap() : result; @@ -322,8 +325,8 @@ protected Map> buildExceptionDests(ThrowAnalysis * @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) { + protected Map> addDestToMap(Map> map, Unit u, + Trap t, ThrowableSet caught) { Collection dests = (map == null ? null : map.get(u)); if (dests == null) { if (t == null) { @@ -546,7 +549,7 @@ public int hashCode() { /** *

* 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 + * a method directly or which might invoke static initializers indirectly (by creating a new object or by referring to a * static field; see sections 2.17.4, 2.17.5, and 5.5 of the Java Virtual Machine Specification). *

* @@ -667,8 +670,6 @@ public Collection getExceptionDests(final Unit u) { Collection result = unitToExceptionDests.get(u); if (result == null) { ExceptionDest e = new ExceptionDest(null, null) { - private ThrowableSet throwables; - @Override public ThrowableSet getThrowables() { if (null == throwables) { @@ -677,14 +678,14 @@ public ThrowableSet getThrowables() { return throwables; } }; - return Collections.singletonList(e); + result = Collections.singletonList(e); } return result; } public static class ExceptionDest implements ExceptionalGraph.ExceptionDest { - private Trap trap; - private ThrowableSet throwables; + private final Trap trap; + ThrowableSet throwables; protected ExceptionDest(Trap trap, ThrowableSet throwables) { this.trap = trap; @@ -712,7 +713,7 @@ public Unit getHandlerNode() { @Override public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append(getThrowables()); buf.append(" -> "); if (trap == null) {