001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 1997-1999 Raja Vallee-Rai
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: */
019:
020: package soot.jbco.bafTransformations;
021:
022: import java.util.*;
023: import soot.*;
024: import soot.baf.*;
025: import soot.jbco.IJbcoTransform;
026: import soot.jbco.util.*;
027:
028: /**
029: * @author Michael Batchelder
030: *
031: * Created on 22-Mar-2006
032: *
033: * This transformer transforms gotos/ifs into JSRS, but not all of them.
034: */
035: public class AddJSRs extends BodyTransformer implements IJbcoTransform {
036:
037: int jsrcount = 0;
038:
039: public static String dependancies[] = new String[] { "jtp.jbco_jl",
040: "bb.jbco_cb2ji", "bb.jbco_ful", "bb.lp" };
041:
042: public String[] getDependancies() {
043: return dependancies;
044: }
045:
046: public static String name = "bb.jbco_cb2ji";
047:
048: public String getName() {
049: return name;
050: }
051:
052: public void outputSummary() {
053: out.println("If/Gotos replaced with JSRs: " + jsrcount);
054: }
055:
056: protected void internalTransform(Body b, String phaseName,
057: Map options) {
058: int weight = soot.jbco.Main.getWeight(phaseName, b.getMethod()
059: .getSignature());
060: if (weight == 0)
061: return;
062:
063: // TODO: introduce switch statement to all pops which never happens?
064: // TODO: introduce if-jsr opaque jumps that never happen?
065:
066: boolean fallsthrough = false;
067: HashMap<Trap, Unit> trapsToHandler = new HashMap<Trap, Unit>();
068: Iterator it = b.getTraps().iterator();
069: while (it.hasNext()) {
070: Trap t = (Trap) it.next();
071: trapsToHandler.put(t, t.getHandlerUnit());
072: }
073:
074: ArrayList<Unit> targets = new ArrayList<Unit>();
075: ArrayList seenUts = new ArrayList();
076: HashMap<Unit, List<Unit>> switches = new HashMap<Unit, List<Unit>>();
077: HashMap<Unit, Unit> switchDefs = new HashMap<Unit, Unit>();
078: HashMap<TargetArgInst, Unit> ignoreJumps = new HashMap<TargetArgInst, Unit>();
079: PatchingChain u = b.getUnits();
080: it = u.snapshotIterator();
081: while (it.hasNext()) {
082: Unit unit = (Unit) it.next();
083: if (unit instanceof TargetArgInst) {
084: TargetArgInst ti = (TargetArgInst) unit;
085: Unit tu = ti.getTarget();
086:
087: // test if we've already seen the target - if so, it might be a loop so
088: // let's not slow things down
089: if (Rand.getInt(10) > weight) //seenUts.contains(tu)) {
090: ignoreJumps.put(ti, tu);
091: else if (!targets.contains(tu))
092: targets.add(tu);
093: }
094:
095: if (unit instanceof TableSwitchInst) {
096: List targs = new ArrayList();
097: TableSwitchInst ts = (TableSwitchInst) unit;
098: targs.addAll(ts.getTargets());
099: switches.put(unit, targs);
100: switchDefs.put(unit, ts.getDefaultTarget());
101: } else if (unit instanceof LookupSwitchInst) {
102: List targs = new ArrayList();
103: LookupSwitchInst ls = (LookupSwitchInst) unit;
104: targs.addAll(ls.getTargets());
105: switches.put(unit, targs);
106: switchDefs.put(unit, ls.getDefaultTarget());
107: }
108:
109: seenUts.add(unit);
110: }
111:
112: it = u.snapshotIterator();
113: ArrayList<Unit> processedLabels = new ArrayList<Unit>();
114: HashMap<Unit, JSRInst> builtJsrs = new HashMap<Unit, JSRInst>();
115: HashMap<Unit, Unit> popsBuilt = new HashMap<Unit, Unit>();
116: Unit prev = null;
117: while (it.hasNext()) {
118: Unit unit = (Unit) it.next();
119:
120: // check if prev unit falls through to this unit (non-jump). If so, and
121: // it's ALSO a target
122: // we need to make a jsr from previous unit to this one, to deal with pop.
123: // ignore GOTOs as they will, themselves, become a jsr.
124: if (targets.contains(unit)) {
125: if (fallsthrough) {
126: JSRInst ji = Baf.v().newJSRInst(unit);
127: builtJsrs.put(unit, ji);
128: u.insertAfter(ji, prev);
129: jsrcount++;
130: }
131: PopInst pop = Baf.v().newPopInst(RefType.v());
132: u.insertBefore(pop, unit);
133: processedLabels.add(unit);
134: popsBuilt.put(pop, unit);
135: }
136: fallsthrough = unit.fallsThrough();
137: prev = unit;
138: }
139:
140: it = u.snapshotIterator();
141: while (it.hasNext()) {
142: Unit unit = (Unit) it.next();
143: if (builtJsrs.containsValue(unit))
144: continue;
145:
146: if (unit instanceof TargetArgInst
147: && !ignoreJumps.containsKey(unit)) {
148: TargetArgInst ti = (TargetArgInst) unit;
149: Unit tu = ti.getTarget();
150: // if we haven't dealt with a target yet, add the pop inst
151: if (!popsBuilt.containsKey(tu))
152: throw new RuntimeException(
153: "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.");
154:
155: JSRInst ji = builtJsrs.get(popsBuilt.get(tu));
156: if (BodyBuilder.isBafIf(unit)) {
157: if (Rand.getInt(10) > weight) {
158: ti.setTarget(popsBuilt.get(tu));
159: } else if (ji != null) {
160: ti.setTarget(ji);
161: } else {
162: ji = Baf.v().newJSRInst(tu);
163: u.insertAfter(ji, u.getPredOf(tu));
164: ti.setTarget(ji);
165:
166: builtJsrs.put(popsBuilt.get(tu), ji);
167: jsrcount++;
168: }
169: } else if (unit instanceof GotoInst) {
170: if (ji != null) {
171: if (Rand.getInt(10) < weight)
172: ((GotoInst) unit).setTarget(ji);
173: else
174: ((GotoInst) unit).setTarget(popsBuilt
175: .get(tu));
176: } else {
177: ((GotoInst) unit).setTarget(popsBuilt.get(tu));
178: }
179: }
180: }
181: }
182:
183: it = trapsToHandler.keySet().iterator();
184: while (it.hasNext()) {
185: Trap t = (Trap) it.next();
186: t.setHandlerUnit(trapsToHandler.get(t));
187: }
188:
189: it = ignoreJumps.keySet().iterator();
190: while (it.hasNext()) {
191: TargetArgInst ti = (TargetArgInst) it.next();
192: if (popsBuilt.containsKey(ti.getTarget()))
193: ti.setTarget(popsBuilt.get(ti.getTarget()));
194: }
195:
196: targets.clear();
197: it = u.snapshotIterator();
198: while (it.hasNext()) {
199: Unit unit = (Unit) it.next();
200: if (!(unit instanceof TargetArgInst))
201: continue;
202: Unit targ = ((TargetArgInst) unit).getTarget();
203: if (!targets.contains(targ))
204: targets.add(targ);
205: }
206:
207: it = popsBuilt.keySet().iterator();
208: while (it.hasNext()) {
209: Unit pop = (Unit) it.next();
210: if (!targets.contains(pop))
211: u.remove(pop);
212: }
213:
214: it = switches.keySet().iterator();
215: while (it.hasNext()) {
216: Unit sw = (Unit) it.next();
217: List<Unit> targs = switches.get(sw);
218:
219: for (int i = 0; i < targs.size(); i++) {
220: if (Rand.getInt(10) > weight)
221: continue;
222:
223: Unit unit = targs.get(i);
224: Unit ji = builtJsrs.get(unit);
225: if (ji != null)
226: targs.set(i, ji);
227: }
228:
229: Unit def = switchDefs.get(sw);
230: if (Rand.getInt(10) < weight && builtJsrs.get(def) != null)
231: def = builtJsrs.get(def);
232:
233: if (sw instanceof TableSwitchInst) {
234: ((TableSwitchInst) sw).setTargets(targs);
235: ((TableSwitchInst) sw).setDefaultTarget(def);
236: } else if (sw instanceof LookupSwitchInst) {
237: ((LookupSwitchInst) sw).setTargets(targs);
238: ((LookupSwitchInst) sw).setDefaultTarget(def);
239: }
240: }
241:
242: if (debug)
243: StackTypeHeightCalculator.calculateStackHeights(b);
244: }
245: }
|