/* Soot - a J*va Optimization Framework * Copyright (C) 1997-1999 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. */ package soot.jbco.bafTransformations; import java.util.*; import soot.*; import soot.baf.*; import soot.jbco.IJbcoTransform; import soot.jbco.util.*; /** * @author Michael Batchelder * * Created on 22-Mar-2006 * * This transformer transforms gotos/ifs into JSRS, but not all of them. */ public class AddJSRs extends BodyTransformer implements IJbcoTransform { int jsrcount = 0; public static String dependancies[] = new String[] { "jtp.jbco_jl", "bb.jbco_cb2ji", "bb.jbco_ful", "bb.lp" }; public String[] getDependancies() { return dependancies; } public static String name = "bb.jbco_cb2ji"; public String getName() { return name; } public void outputSummary() { out.println("If/Gotos replaced with JSRs: " + jsrcount); } protected void internalTransform(Body b, String phaseName, Map options) { int weight = soot.jbco.Main.getWeight(phaseName, b.getMethod().getSignature()); if (weight == 0) return; // TODO: introduce switch statement to all pops which never happens? // TODO: introduce if-jsr opaque jumps that never happen? boolean fallsthrough = false; HashMap<Trap,Unit> trapsToHandler = new HashMap<Trap,Unit>(); Iterator it = b.getTraps().iterator(); while (it.hasNext()) { Trap t = (Trap) it.next(); trapsToHandler.put(t, t.getHandlerUnit()); } ArrayList<Unit> targets = new ArrayList<Unit>(); ArrayList seenUts = new ArrayList(); HashMap<Unit,List<Unit>> switches = new HashMap<Unit,List<Unit>>(); HashMap<Unit,Unit> switchDefs = new HashMap<Unit,Unit>(); HashMap<TargetArgInst,Unit> ignoreJumps = new HashMap<TargetArgInst,Unit>(); PatchingChain u = b.getUnits(); it = u.snapshotIterator(); while (it.hasNext()) { Unit unit = (Unit) it.next(); if (unit instanceof TargetArgInst) { TargetArgInst ti = (TargetArgInst) unit; Unit tu = ti.getTarget(); // test if we've already seen the target - if so, it might be a loop so // let's not slow things down if (Rand.getInt(10) > weight) //seenUts.contains(tu)) { ignoreJumps.put(ti, tu); else if (!targets.contains(tu)) targets.add(tu); } if (unit instanceof TableSwitchInst) { List targs = new ArrayList(); TableSwitchInst ts = (TableSwitchInst) unit; targs.addAll(ts.getTargets()); switches.put(unit, targs); switchDefs.put(unit, ts.getDefaultTarget()); } else if (unit instanceof LookupSwitchInst) { List targs = new ArrayList(); LookupSwitchInst ls = (LookupSwitchInst) unit; targs.addAll(ls.getTargets()); switches.put(unit, targs); switchDefs.put(unit, ls.getDefaultTarget()); } seenUts.add(unit); } it = u.snapshotIterator(); ArrayList<Unit> processedLabels = new ArrayList<Unit>(); HashMap<Unit, JSRInst> builtJsrs = new HashMap<Unit, JSRInst>(); HashMap<Unit,Unit> popsBuilt = new HashMap<Unit,Unit>(); Unit prev = null; while (it.hasNext()) { Unit unit = (Unit) it.next(); // check if prev unit falls through to this unit (non-jump). If so, and // it's ALSO a target // we need to make a jsr from previous unit to this one, to deal with pop. // ignore GOTOs as they will, themselves, become a jsr. if (targets.contains(unit)) { if (fallsthrough) { JSRInst ji = Baf.v().newJSRInst(unit); builtJsrs.put(unit, ji); u.insertAfter(ji, prev); jsrcount++; } PopInst pop = Baf.v().newPopInst(RefType.v()); u.insertBefore(pop, unit); processedLabels.add(unit); popsBuilt.put(pop, unit); } fallsthrough = unit.fallsThrough(); prev = unit; } it = u.snapshotIterator(); while (it.hasNext()) { Unit unit = (Unit) it.next(); if (builtJsrs.containsValue(unit)) continue; if (unit instanceof TargetArgInst && !ignoreJumps.containsKey(unit)) { TargetArgInst ti = (TargetArgInst) unit; Unit tu = ti.getTarget(); // if we haven't dealt with a target yet, add the pop inst if (!popsBuilt.containsKey(tu)) throw new RuntimeException("It appears a target was found that was not updated with a POP.\n\"This makes no sense,\" said the bug as it flew through the code."); JSRInst ji = builtJsrs.get(popsBuilt.get(tu)); if (BodyBuilder.isBafIf(unit)) { if (Rand.getInt(10) > weight) { ti.setTarget(popsBuilt.get(tu)); } else if (ji != null) { ti.setTarget(ji); } else { ji = Baf.v().newJSRInst(tu); u.insertAfter(ji, u.getPredOf(tu)); ti.setTarget(ji); builtJsrs.put(popsBuilt.get(tu), ji); jsrcount++; } } else if (unit instanceof GotoInst) { if (ji != null) { if (Rand.getInt(10) < weight) ((GotoInst) unit).setTarget(ji); else ((GotoInst) unit).setTarget(popsBuilt.get(tu)); } else { ((GotoInst) unit).setTarget(popsBuilt.get(tu)); } } } } it = trapsToHandler.keySet().iterator(); while (it.hasNext()) { Trap t = (Trap) it.next(); t.setHandlerUnit(trapsToHandler.get(t)); } it = ignoreJumps.keySet().iterator(); while (it.hasNext()) { TargetArgInst ti = (TargetArgInst) it.next(); if (popsBuilt.containsKey(ti.getTarget())) ti.setTarget(popsBuilt.get(ti.getTarget())); } targets.clear(); it = u.snapshotIterator(); while (it.hasNext()) { Unit unit = (Unit) it.next(); if (!(unit instanceof TargetArgInst)) continue; Unit targ = ((TargetArgInst) unit).getTarget(); if (!targets.contains(targ)) targets.add(targ); } it = popsBuilt.keySet().iterator(); while (it.hasNext()) { Unit pop = (Unit) it.next(); if (!targets.contains(pop)) u.remove(pop); } it = switches.keySet().iterator(); while (it.hasNext()) { Unit sw = (Unit) it.next(); List<Unit> targs = switches.get(sw); for (int i = 0; i < targs.size(); i++) { if (Rand.getInt(10) > weight) continue; Unit unit = targs.get(i); Unit ji = builtJsrs.get(unit); if (ji != null) targs.set(i, ji); } Unit def = switchDefs.get(sw); if (Rand.getInt(10) < weight && builtJsrs.get(def) != null) def = builtJsrs.get(def); if (sw instanceof TableSwitchInst) { ((TableSwitchInst) sw).setTargets(targs); ((TableSwitchInst) sw).setDefaultTarget(def); } else if (sw instanceof LookupSwitchInst) { ((LookupSwitchInst) sw).setTargets(targs); ((LookupSwitchInst) sw).setDefaultTarget(def); } } if (debug) StackTypeHeightCalculator.calculateStackHeights(b); } }