001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2004 Jennifer Lhotak
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.jimple.toolkits.base;
021:
022: import soot.*;
023: import soot.jimple.*;
024: import soot.util.*;
025: import java.util.*;
026: import soot.jimple.toolkits.scalar.*;
027:
028: public class ThisInliner extends BodyTransformer {
029:
030: public void internalTransform(Body b, String phaseName, Map options) {
031:
032: // assure body is a constructor
033: if (!b.getMethod().getName().equals("<init>"))
034: return;
035:
036: // if the first invoke is a this() and not a super() inline the this()
037: InvokeStmt invokeStmt = getFirstSpecialInvoke(b);
038: if (invokeStmt == null)
039: return;
040: SpecialInvokeExpr specInvokeExpr = (SpecialInvokeExpr) invokeStmt
041: .getInvokeExpr();
042: if (specInvokeExpr.getMethod().getDeclaringClass().equals(
043: b.getMethod().getDeclaringClass())) {
044:
045: // put locals from inlinee into container
046: if (!specInvokeExpr.getMethod().hasActiveBody()) {
047: specInvokeExpr.getMethod().retrieveActiveBody();
048: }
049:
050: HashMap oldLocalsToNew = new HashMap();
051:
052: Iterator localsIt = specInvokeExpr.getMethod()
053: .getActiveBody().getLocals().iterator();
054: while (localsIt.hasNext()) {
055: Local l = (Local) localsIt.next();
056: Local newLocal = (Local) l.clone();
057: b.getLocals().add(newLocal);
058: oldLocalsToNew.put(l, newLocal);
059: }
060:
061: //find identity stmt of original method
062: IdentityStmt origIdStmt = findIdentityStmt(b);
063:
064: HashMap<Stmt, Stmt> oldStmtsToNew = new HashMap<Stmt, Stmt>();
065:
066: //System.out.println("locals: "+b.getLocals());
067: Chain containerUnits = b.getUnits();
068: Iterator inlineeIt = specInvokeExpr.getMethod()
069: .getActiveBody().getUnits().iterator();
070: while (inlineeIt.hasNext()) {
071: Stmt inlineeStmt = (Stmt) inlineeIt.next();
072:
073: // handle identity stmts
074: if (inlineeStmt instanceof IdentityStmt) {
075: IdentityStmt idStmt = (IdentityStmt) inlineeStmt;
076:
077: if (idStmt.getRightOp() instanceof ThisRef) {
078: Stmt newThis = Jimple.v().newAssignStmt(
079: (Local) oldLocalsToNew.get(idStmt
080: .getLeftOp()),
081: origIdStmt.getLeftOp());
082: containerUnits
083: .insertBefore(newThis, invokeStmt);
084: oldStmtsToNew.put(inlineeStmt, newThis);
085: }
086:
087: else if (idStmt.getRightOp() instanceof CaughtExceptionRef) {
088: Stmt newInlinee = (Stmt) inlineeStmt.clone();
089: Iterator localsToPatch = newInlinee
090: .getUseAndDefBoxes().iterator();
091: while (localsToPatch.hasNext()) {
092: ValueBox next = (ValueBox) localsToPatch
093: .next();
094: if (next.getValue() instanceof Local) {
095: next.setValue((Local) oldLocalsToNew
096: .get(next.getValue()));
097: }
098: }
099:
100: containerUnits.insertBefore(newInlinee,
101: invokeStmt);
102: oldStmtsToNew.put(inlineeStmt, newInlinee);
103: } else if (idStmt.getRightOp() instanceof ParameterRef) {
104: Stmt newParam = Jimple.v().newAssignStmt(
105: (Local) oldLocalsToNew.get(idStmt
106: .getLeftOp()),
107: specInvokeExpr
108: .getArg(((ParameterRef) idStmt
109: .getRightOp())
110: .getIndex()));
111: containerUnits.insertBefore(newParam,
112: invokeStmt);
113: oldStmtsToNew.put(inlineeStmt, newParam);
114: }
115: }
116:
117: // handle return void stmts (cannot return anything else
118: // from a constructor)
119: else if (inlineeStmt instanceof ReturnVoidStmt) {
120: Stmt newRet = Jimple.v()
121: .newGotoStmt(
122: (Stmt) containerUnits
123: .getSuccOf(invokeStmt));
124: containerUnits.insertBefore(newRet, invokeStmt);
125: System.out.println("adding to stmt map: "
126: + inlineeStmt + " and " + newRet);
127: oldStmtsToNew.put(inlineeStmt, newRet);
128: }
129:
130: else {
131: Stmt newInlinee = (Stmt) inlineeStmt.clone();
132: Iterator localsToPatch = newInlinee
133: .getUseAndDefBoxes().iterator();
134: while (localsToPatch.hasNext()) {
135: ValueBox next = (ValueBox) localsToPatch.next();
136: if (next.getValue() instanceof Local) {
137: next.setValue((Local) oldLocalsToNew
138: .get(next.getValue()));
139: }
140: }
141:
142: containerUnits.insertBefore(newInlinee, invokeStmt);
143: oldStmtsToNew.put(inlineeStmt, newInlinee);
144: }
145:
146: }
147:
148: // handleTraps
149: Iterator trapsIt = specInvokeExpr.getMethod()
150: .getActiveBody().getTraps().iterator();
151: while (trapsIt.hasNext()) {
152: Trap t = (Trap) trapsIt.next();
153: System.out.println("begin: " + t.getBeginUnit());
154: Stmt newBegin = oldStmtsToNew.get(t.getBeginUnit());
155: System.out.println("end: " + t.getEndUnit());
156: Stmt newEnd = oldStmtsToNew.get(t.getEndUnit());
157: System.out.println("handler: " + t.getHandlerUnit());
158: Stmt newHandler = oldStmtsToNew.get(t.getHandlerUnit());
159:
160: if (newBegin == null || newEnd == null
161: || newHandler == null)
162: throw new RuntimeException("couldn't map trap!");
163:
164: b.getTraps().add(
165: Jimple.v().newTrap(t.getException(), newBegin,
166: newEnd, newHandler));
167: }
168:
169: // patch gotos
170: inlineeIt = specInvokeExpr.getMethod().getActiveBody()
171: .getUnits().iterator();
172: while (inlineeIt.hasNext()) {
173: Stmt inlineeStmt = (Stmt) inlineeIt.next();
174: if (inlineeStmt instanceof GotoStmt) {
175: System.out.println("inlinee goto target: "
176: + ((GotoStmt) inlineeStmt).getTarget());
177: ((GotoStmt) oldStmtsToNew.get(inlineeStmt))
178: .setTarget(oldStmtsToNew
179: .get(((GotoStmt) inlineeStmt)
180: .getTarget()));
181: }
182:
183: }
184:
185: // remove original invoke
186: containerUnits.remove(invokeStmt);
187:
188: // resolve name collisions
189: LocalNameStandardizer.v().transform(b, "ji.lns");
190:
191: }
192: //System.out.println("locals: "+b.getLocals());
193: //System.out.println("units: "+b.getUnits());
194: }
195:
196: private InvokeStmt getFirstSpecialInvoke(Body b) {
197: Iterator it = b.getUnits().iterator();
198: while (it.hasNext()) {
199: Stmt s = (Stmt) it.next();
200: if (!(s instanceof InvokeStmt))
201: continue;
202:
203: InvokeExpr invokeExpr = ((InvokeStmt) s).getInvokeExpr();
204: if (!(invokeExpr instanceof SpecialInvokeExpr))
205: continue;
206:
207: return (InvokeStmt) s;
208: }
209: // but there will always be either a call to this() or to super()
210: // from the constructor
211: return null;
212: }
213:
214: private IdentityStmt findIdentityStmt(Body b) {
215: Iterator it = b.getUnits().iterator();
216: while (it.hasNext()) {
217: Stmt s = (Stmt) it.next();
218: if ((s instanceof IdentityStmt)
219: && (((IdentityStmt) s).getRightOp() instanceof ThisRef)) {
220: return (IdentityStmt) s;
221: }
222: }
223: return null;
224: }
225: }
|