/** * Traverse the statements in the given body, looking for aggregation possibilities; that is, * given a def d and a use u, d has no other uses, u has no other defs, collapse d and u. * * <p>option: only-stack-locals; if this is true, only aggregate variables starting with $ */ protected void internalTransform(Body b, String phaseName, Map<String, String> options) { StmtBody body = (StmtBody) b; boolean onlyStackVars = PhaseOptions.getBoolean(options, "only-stack-locals"); int aggregateCount = 1; if (Options.v().time()) Timers.v().aggregationTimer.start(); boolean changed = false; Map<ValueBox, Zone> boxToZone = new HashMap<ValueBox, Zone>(body.getUnits().size() * 2 + 1, 0.7f); // Determine the zone of every box { Zonation zonation = new Zonation(body); for (Unit u : body.getUnits()) { Zone zone = zonation.getZoneOf(u); for (ValueBox box : u.getUseBoxes()) { boxToZone.put(box, zone); } for (ValueBox box : u.getDefBoxes()) { boxToZone.put(box, zone); } } } do { if (Options.v().verbose()) G.v() .out .println( "[" + body.getMethod().getName() + "] Aggregating iteration " + aggregateCount + "..."); // body.printTo(new java.io.PrintWriter(G.v().out, true)); changed = internalAggregate(body, boxToZone, onlyStackVars); aggregateCount++; } while (changed); if (Options.v().time()) Timers.v().aggregationTimer.end(); }
/** * Returns a <code>ThrowableSet</code> representing the set of exceptions included in <code> * include</code> minus the set of exceptions included in <code>exclude</code>. Creates a new * <code>ThrowableSet</code> only if there was not already one whose contents correspond to * <code>include</code> - <code>exclude</code>. * * @param include A set of {@link RefLikeType} objects representing exception types included in * the result; may be <code>null</code> if there are no included types. * @param exclude A set of {@link AnySubType} objects representing exception types excluded from * the result; may be <code>null</code> if there are no excluded types. * @return a <code>ThrowableSet</code> representing the set of exceptions corresponding to * <code>include</code> - <code>exclude</code>. */ private ThrowableSet registerSetIfNew(Set include, Set exclude) { if (INSTRUMENTING) { registrationCalls++; } if (include == null) { include = Collections.EMPTY_SET; } if (exclude == null) { exclude = Collections.EMPTY_SET; } int size = include.size() + exclude.size(); Integer sizeKey = new Integer(size); List sizeList = (List) sizeToSets.get(sizeKey); if (sizeList == null) { sizeList = new LinkedList(); sizeToSets.put(sizeKey, sizeList); } for (Iterator i = sizeList.iterator(); i.hasNext(); ) { ThrowableSet set = (ThrowableSet) i.next(); if (set.exceptionsIncluded.equals(include) && set.exceptionsExcluded.equals(exclude)) { return set; } } if (INSTRUMENTING) { registeredSets++; } ThrowableSet result = new ThrowableSet(include, exclude); sizeList.add(result); return result; }
/** * Utility method that produces a new map from the {@link Unit}s of this graph's body to the union * of the values stored in the two argument {@link Map}s, used to combine the maps of exceptional * and unexceptional predecessors and successors into maps of all predecessors and successors. The * values stored in both argument maps must be {@link List}s of {@link Unit}s, which are assumed * not to contain any duplicate <tt>Unit</tt>s. * * @param mapA The first map to be combined. * @param mapB The second map to be combined. */ protected Map combineMapValues(Map mapA, Map mapB) { // The duplicate screen Map result = new HashMap(mapA.size() * 2 + 1, 0.7f); for (Iterator chainIt = unitChain.iterator(); chainIt.hasNext(); ) { Unit unit = (Unit) chainIt.next(); List listA = (List) mapA.get(unit); if (listA == null) { listA = Collections.EMPTY_LIST; } List listB = (List) mapB.get(unit); if (listB == null) { listB = Collections.EMPTY_LIST; } int resultSize = listA.size() + listB.size(); if (resultSize == 0) { result.put(unit, Collections.EMPTY_LIST); } else { List resultList = new ArrayList(resultSize); Iterator listIt = null; // As a minor optimization of the duplicate screening, // copy the longer list first. if (listA.size() >= listB.size()) { resultList.addAll(listA); listIt = listB.iterator(); } else { resultList.addAll(listB); listIt = listA.iterator(); } while (listIt.hasNext()) { Object element = listIt.next(); // It is possible for there to be both an exceptional // and an unexceptional edge connecting two Units // (though probably not in a class generated by // javac), so we need to screen for duplicates. On the // other hand, we expect most of these lists to have // only one or two elements, so it doesn't seem worth // the cost to build a Set to do the screening. if (!resultList.contains(element)) { resultList.add(element); } } result.put(unit, Collections.unmodifiableList(resultList)); } } return result; }
/** * Utility method for adding an edge to maps representing the CFG. * * @param unitToSuccs The {@link Map} from {@link Unit}s to {@link List}s of their successors. * @param unitToPreds The {@link Map} from {@link Unit}s to {@link List}s of their successors. * @param head The {@link Unit} from which the edge starts. * @param tail The {@link Unit} to which the edge flows. */ protected void addEdge(Map unitToSuccs, Map unitToPreds, Unit head, Unit tail) { List headsSuccs = (List) unitToSuccs.get(head); if (headsSuccs == null) { headsSuccs = new ArrayList(3); // We expect this list to // remain short. unitToSuccs.put(head, headsSuccs); } if (!headsSuccs.contains(tail)) { headsSuccs.add(tail); List tailsPreds = (List) unitToPreds.get(tail); if (tailsPreds == null) { tailsPreds = new ArrayList(); unitToPreds.put(tail, tailsPreds); } tailsPreds.add(head); } }
private void addBoxToPatch(String aLabelName, UnitBox aUnitBox) { List patchList = (List) mLabelToPatchList.get(aLabelName); if (patchList == null) { patchList = new ArrayList(); mLabelToPatchList.put(aLabelName, patchList); } patchList.add(aUnitBox); }
/** * Utility method for <tt>UnitGraph</tt> constructors. It computes the edges corresponding to * unexceptional control flow. * * @param unitToSuccs A {@link Map} from {@link Unit}s to {@link List}s of {@link Unit}s. This is * an ``out parameter''; callers must pass an empty {@link Map}. * <tt>buildUnexceptionalEdges</tt> will add a mapping for every <tt>Unit</tt> in the body to * a list of its unexceptional successors. * @param unitToPreds A {@link Map} from {@link Unit}s to {@link List}s of {@link Unit}s. This is * an ``out parameter''; callers must pass an empty {@link Map}. * <tt>buildUnexceptionalEdges</tt> will add a mapping for every <tt>Unit</tt> in the body to * a list of its unexceptional predecessors. */ protected void buildUnexceptionalEdges(Map unitToSuccs, Map unitToPreds) { // Initialize the predecessor sets to empty for (Iterator unitIt = unitChain.iterator(); unitIt.hasNext(); ) { unitToPreds.put(unitIt.next(), new ArrayList()); } Iterator unitIt = unitChain.iterator(); Unit currentUnit, nextUnit; nextUnit = unitIt.hasNext() ? (Unit) unitIt.next() : null; while (nextUnit != null) { currentUnit = nextUnit; nextUnit = unitIt.hasNext() ? (Unit) unitIt.next() : null; List successors = new ArrayList(); if (currentUnit.fallsThrough()) { // Add the next unit as the successor if (nextUnit != null) { successors.add(nextUnit); ((List) unitToPreds.get(nextUnit)).add(currentUnit); } } if (currentUnit.branches()) { for (Iterator targetIt = currentUnit.getUnitBoxes().iterator(); targetIt.hasNext(); ) { Unit target = ((UnitBox) targetIt.next()).getUnit(); // Arbitrary bytecode can branch to the same // target it falls through to, so we screen for duplicates: if (!successors.contains(target)) { successors.add(target); ((List) unitToPreds.get(target)).add(currentUnit); } } } // Store away successors unitToSuccs.put(currentUnit, successors); } }
/** Prints the given <code>JimpleBody</code> to the specified <code>PrintWriter</code>. */ private void printLocalsInBody(Body body, UnitPrinter up) { // Print out local variables { Map typeToLocals = new DeterministicHashMap(body.getLocalCount() * 2 + 1, 0.7f); // Collect locals { Iterator localIt = body.getLocals().iterator(); while (localIt.hasNext()) { Local local = (Local) localIt.next(); List localList; Type t = local.getType(); if (typeToLocals.containsKey(t)) localList = (List) typeToLocals.get(t); else { localList = new ArrayList(); typeToLocals.put(t, localList); } localList.add(local); } } // Print locals { Iterator typeIt = typeToLocals.keySet().iterator(); while (typeIt.hasNext()) { Type type = (Type) typeIt.next(); List localList = (List) typeToLocals.get(type); Object[] locals = localList.toArray(); up.type(type); up.literal(" "); for (int k = 0; k < locals.length; k++) { if (k != 0) up.literal(", "); up.local((Local) locals[k]); } up.literal(";"); up.newline(); } } if (!typeToLocals.isEmpty()) { up.newline(); } } }
public void outADeclaration(ADeclaration node) { List localNameList = (List) mProductions.removeLast(); Type type = (Type) mProductions.removeLast(); Iterator it = localNameList.iterator(); List localList = new ArrayList(); while (it.hasNext()) { Local l = Jimple.v().newLocal((String) it.next(), type); mLocals.put(l.getName(), l); localList.add(l); } mProductions.addLast(localList); }
/** * Returns a <code>ThrowableSet</code> which contains all the exceptions in <code>s</code> in * addition to those in this <code>ThrowableSet</code>. * * @param s set of exceptions to add to this set. * @return the union of this set with <code>s</code> * @throws ThrowableSet.AlreadyHasExclusionsException if this <code>ThrowableSet</code> or <code>s * </code> is the result of a {@link #whichCatchableAs(RefType)} operation, so that it is not * possible to represent the addition of <code>s</code> to this <code>ThrowableSet</code>. */ public ThrowableSet add(ThrowableSet s) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfSet++; } if (exceptionsExcluded.size() > 0 || s.exceptionsExcluded.size() > 0) { throw new AlreadyHasExclusionsException( "ThrowableSet.Add(ThrowableSet): attempt to add to [" + this.toString() + "] after removals recorded."); } ThrowableSet result = getMemoizedAdds(s); if (result == null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; Manager.v().addsExclusionWithoutSearch++; } result = this.add(s.exceptionsIncluded); memoizedAdds.put(s, result); } else if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; }
/** * Returns a <code>ThrowableSet</code> which contains <code>e</code> and all of its subclasses as * well as the exceptions in this set. * * <p><code>e</code> should be an instance of {@link AnySubType} if you know that the compile-time * type of the exception you are representing is <code>e</code>, but the exception may be * instantiated at run-time by a subclass of <code>e</code>. * * <p>For example, if you were recording the type of the exception thrown by * * <pre> * catch (IOException e) { * throw e; * } * </pre> * * you would call * * <pre> * <code>add(AnySubtype.v(Scene.v().getRefType("java.lang.Exception.IOException")))</code> * </pre> * * since the handler might rethrow any subclass of <code>IOException</code>. * * @param e represents a subtree of the exception class hierarchy to add to this set. * @return a set containing <code>e</code> and all its subclasses, as well as the exceptions * represented by this set. * @throws ThrowableSet.AlreadyHasExclusionsException if this <code>ThrowableSet</code> is the * result of a {@link #whichCatchableAs(RefType)} operation and, thus, unable to represent the * addition of <code>e</code>. */ public ThrowableSet add(AnySubType e) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfAnySubType++; } ThrowableSet result = getMemoizedAdds(e); if (result != null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; } else { FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy(); RefType newBase = e.getBase(); if (INSTRUMENTING) { if (exceptionsExcluded.size() != 0) { Manager.v().addsExclusionWithSearch++; } else { Manager.v().addsExclusionWithoutSearch++; } } for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) { RefType exclusionBase = ((AnySubType) i.next()).getBase(); if (hierarchy.canStoreType(newBase, exclusionBase) || hierarchy.canStoreType(exclusionBase, newBase)) { if (INSTRUMENTING) { // To ensure that the subcategories total properly: Manager.v().addsInclusionInterrupted++; } throw new AlreadyHasExclusionsException( "ThrowableSet.add(" + e.toString() + ") to the set [ " + this.toString() + "] where " + exclusionBase.toString() + " is excluded."); } } if (this.exceptionsIncluded.contains(e)) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMap++; } return this; } else { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; } int changes = 0; boolean addNewException = true; Set resultSet = new HashSet(); for (Iterator i = this.exceptionsIncluded.iterator(); i.hasNext(); ) { RefLikeType incumbent = (RefLikeType) i.next(); if (incumbent instanceof RefType) { if (hierarchy.canStoreType(incumbent, newBase)) { // Omit incumbent from result. changes++; } else { resultSet.add(incumbent); } } else if (incumbent instanceof AnySubType) { RefType incumbentBase = ((AnySubType) incumbent).getBase(); // We have to use the base types in these hierarchy calls // because we want to know if _all_ possible // types represented by e can be represented by // the incumbent, or vice versa. if (hierarchy.canStoreType(newBase, incumbentBase)) { addNewException = false; resultSet.add(incumbent); } else if (hierarchy.canStoreType(incumbentBase, newBase)) { // Omit incumbent from result; changes++; } else { resultSet.add(incumbent); } } else { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(AnySubType): Set element " + incumbent.toString() + " is neither a RefType nor an AnySubType."); } } if (addNewException) { resultSet.add(e); changes++; } if (changes > 0) { result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); } else { result = this; } memoizedAdds.put(e, result); return result; } } }
/** * Returns a <code>ThrowableSet</code> which contains <code>e</code> in addition to the exceptions * in this <code>ThrowableSet</code>. * * <p>Add <code>e</code> as a {@link RefType} when you know that the run-time class of the * exception you are representing is necessarily <code>e</code> and cannot be a subclass of <code> * e</code>. * * <p>For example, if you were recording the type of the exception thrown by * * <pre> * throw new IOException("Permission denied"); * </pre> * * you would call * * <pre> * <code>add(Scene.v().getRefType("java.lang.Exception.IOException"))</code> * </pre> * * since the class of the exception is necessarily <code>IOException</code>. * * @param e the exception class * @return a set containing <code>e</code> as well as the exceptions in this set. * @throws {@link ThrowableSet.IllegalStateException} if this <code>ThrowableSet</code> is the * result of a {@link #whichCatchableAs(RefType)} operation and, thus, unable to represent the * addition of <code>e</code>. */ public ThrowableSet add(RefType e) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfRefType++; } if (this.exceptionsIncluded.contains(e)) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMap++; Manager.v().addsExclusionWithoutSearch++; } return this; } else { ThrowableSet result = getMemoizedAdds(e); if (result != null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; } else { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; if (exceptionsExcluded.size() != 0) { Manager.v().addsExclusionWithSearch++; } else { Manager.v().addsExclusionWithoutSearch++; } } FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy(); for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) { RefType exclusionBase = ((AnySubType) i.next()).getBase(); if (hierarchy.canStoreType(e, exclusionBase)) { throw new AlreadyHasExclusionsException( "ThrowableSet.add(RefType): adding" + e.toString() + " to the set [ " + this.toString() + "] where " + exclusionBase.toString() + " is excluded."); } } for (Iterator i = exceptionsIncluded.iterator(); i.hasNext(); ) { RefLikeType incumbent = (RefLikeType) i.next(); if (incumbent instanceof AnySubType) { // Need to use incumbent.getBase() because // hierarchy.canStoreType() assumes that parent // is not an AnySubType. RefType incumbentBase = ((AnySubType) incumbent).getBase(); if (hierarchy.canStoreType(e, incumbentBase)) { memoizedAdds.put(e, this); return this; } } else if (!(incumbent instanceof RefType)) { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(RefType): Set element " + incumbent.toString() + " is neither a RefType nor an AnySubType."); } } Set resultSet = new HashSet(this.exceptionsIncluded); resultSet.add(e); result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); memoizedAdds.put(e, result); return result; } } }
public void outAFullMethodBody(AFullMethodBody node) { Object catchClause = null; JimpleBody jBody = Jimple.v().newBody(); if (node.getCatchClause() != null) { int size = node.getCatchClause().size(); for (int i = 0; i < size; i++) jBody.getTraps().addFirst((Trap) mProductions.removeLast()); } if (node.getStatement() != null) { int size = node.getStatement().size(); Unit lastStmt = null; for (int i = 0; i < size; i++) { Object o = mProductions.removeLast(); if (o instanceof Unit) { jBody.getUnits().addFirst(o); lastStmt = (Unit) o; } else if (o instanceof String) { if (lastStmt == null) throw new RuntimeException("impossible"); mLabelToStmtMap.put(o, lastStmt); } else throw new RuntimeException("impossible"); } } if (node.getDeclaration() != null) { int size = node.getDeclaration().size(); for (int i = 0; i < size; i++) { List localList = (List) mProductions.removeLast(); int listSize = localList.size(); for (int j = listSize - 1; j >= 0; j--) jBody.getLocals().addFirst(localList.get(j)); } } Iterator it = mLabelToPatchList.keySet().iterator(); while (it.hasNext()) { String label = (String) it.next(); Unit target = (Unit) mLabelToStmtMap.get(label); Iterator patchIt = ((List) mLabelToPatchList.get(label)).iterator(); while (patchIt.hasNext()) { UnitBox box = (UnitBox) patchIt.next(); box.setUnit(target); } } /* Iterator it = mLabelToStmtMap.keySet().iterator(); while(it.hasNext()) { String label = (String) it.next(); Unit target = (Unit) mLabelToStmtMap.get(label); List l = (List) mLabelToPatchList.get(label); if(l != null) { Iterator patchIt = l.iterator(); while(patchIt.hasNext()) { UnitBox box = (UnitBox) patchIt.next(); box.setUnit(target); } } } */ mProductions.addLast(jBody); }