KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > jimple > toolkits > invoke > SiteInliner


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 1999 Patrick Lam, Raja Vallee-Rai
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */

19
20 /*
21  * Modified by the Sable Research Group and others 1997-1999.
22  * See the 'credits' file distributed with Soot for the complete list of
23  * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
24  */

25
26 package soot.jimple.toolkits.invoke;
27
28 import soot.*;
29 import soot.jimple.*;
30 import soot.jimple.toolkits.scalar.*;
31 import java.util.*;
32 import soot.util.*;
33
34 /** Provides methods to inline a given invoke site. */
35 public class SiteInliner
36 {
37     public String JavaDoc getDefaultOptions()
38     {
39         return "insert-null-checks insert-redundant-casts";
40     }
41
42     public static void inlineSites(List sites)
43     {
44         inlineSites(sites, new HashMap());
45     }
46
47     /** Iterates over a list of sites, inlining them in order.
48      * Each site is given as a 3-element list (inlinee, toInline, container). */

49     public static void inlineSites(List sites, Map options)
50     {
51         Iterator it = sites.iterator();
52         while (it.hasNext())
53         {
54             List l = (List)it.next();
55             SootMethod inlinee = (SootMethod)l.get(0);
56             Stmt toInline = (Stmt)l.get(1);
57             SootMethod container = (SootMethod)l.get(2);
58
59             inlineSite(inlinee, toInline, container, options);
60         }
61     }
62
63     /** Inlines the method <code>inlinee</code> into the <code>container</code>
64      * at the point <code>toInline</code>. */

65     public static void inlineSite(SootMethod inlinee, Stmt toInline,
66                                     SootMethod container)
67     {
68         inlineSite(inlinee, toInline, container, new HashMap());
69     }
70
71     /**
72         Inlines the given site. Note that this method does
73         not actually check if it's safe (with respect to access modifiers and special invokes)
74         for it to be inlined. That functionality is handled by the InlinerSafetyManager.
75          
76      */

77     public static List inlineSite(SootMethod inlinee, Stmt toInline,
78                                     SootMethod container, Map options)
79     {
80
81         boolean enableNullPointerCheckInsertion = PhaseOptions.getBoolean(options, "insert-null-checks");
82         boolean enableRedundantCastInsertion = PhaseOptions.getBoolean(options, "insert-redundant-casts");
83
84         Hierarchy hierarchy = Scene.v().getActiveHierarchy();
85
86         JimpleBody containerB = (JimpleBody)container.getActiveBody();
87         Chain containerUnits = containerB.getUnits();
88
89         if (!(inlinee.getDeclaringClass().isApplicationClass() ||
90               inlinee.getDeclaringClass().isLibraryClass()))
91             return null;
92
93         Body inlineeB = (JimpleBody)inlinee.getActiveBody();
94         Chain inlineeUnits = inlineeB.getUnits();
95
96         InvokeExpr ie = (InvokeExpr)toInline.getInvokeExpr();
97
98         Value thisToAdd = null;
99         if (ie instanceof InstanceInvokeExpr)
100             thisToAdd = ((InstanceInvokeExpr)ie).getBase();
101
102         // Insert casts to please the verifier.
103
{
104             boolean targetUsesThis = true;
105             if (enableRedundantCastInsertion && ie instanceof InstanceInvokeExpr && targetUsesThis)
106             {
107                 // The verifier will complain if targetUsesThis, and:
108
// the argument passed to the method is not the same type.
109
// For instance, Bottle.price_static takes a cost.
110
// Cost is an interface implemented by Bottle.
111
SootClass localType, parameterType;
112                 localType = ((RefType)((InstanceInvokeExpr)ie).getBase().getType()).getSootClass();
113                 parameterType = inlinee.getDeclaringClass();
114
115                 if (localType.isInterface() ||
116                     hierarchy.isClassSuperclassOf(localType, parameterType))
117                 {
118                     Local castee = Jimple.v().newLocal("__castee", parameterType.getType());
119                     containerB.getLocals().add(castee);
120                     containerB.getUnits().insertBefore(Jimple.v().newAssignStmt(castee,
121                                   Jimple.v().newCastExpr(((InstanceInvokeExpr)ie).getBase(),
122                                                          parameterType.getType())), toInline);
123                     thisToAdd = castee;
124                 }
125             }
126         }
127
128         // (If enabled), add a null pointer check.
129
{
130             if (enableNullPointerCheckInsertion && ie instanceof InstanceInvokeExpr)
131             {
132                 boolean caught = TrapManager.isExceptionCaughtAt
133                     (Scene.v().getSootClass("java.lang.NullPointerException"), toInline, containerB);
134
135                 /* Ah ha. Caught again! */
136                 if (caught)
137                 {
138                     /* In this case, we don't use throwPoint;
139                      * instead, put the code right there. */

140                     Stmt insertee = Jimple.v().newIfStmt(Jimple.v().newNeExpr(((InstanceInvokeExpr)ie).getBase(),
141                                                   NullConstant.v()), toInline);
142
143                     containerB.getUnits().insertBefore(insertee, toInline);
144
145                     // This sucks (but less than before).
146
((IfStmt)insertee).setTarget(toInline);
147
148                     ThrowManager.addThrowAfter(containerB, insertee);
149                 }
150                 else
151                 {
152                     Stmt throwPoint =
153                         ThrowManager.getNullPointerExceptionThrower(containerB);
154                     containerB.getUnits().insertBefore
155                         (Jimple.v().newIfStmt(Jimple.v().newEqExpr(((InstanceInvokeExpr)ie).getBase(),
156                                          NullConstant.v()), throwPoint), toInline);
157                 }
158             }
159         }
160                     
161         // Add synchronizing stuff.
162
{
163             if (inlinee.isSynchronized())
164             {
165                 // Need to get the class object if ie is a static invoke.
166
if (ie instanceof InstanceInvokeExpr)
167                     SynchronizerManager.v().synchronizeStmtOn(toInline, containerB, (Local)((InstanceInvokeExpr)ie).getBase());
168                 else
169                 {
170                     // If we're in an interface, we must be in a
171
// <clinit> method, which surely needs no
172
// synchronization.
173
if (!container.getDeclaringClass().isInterface())
174                     {
175                         // Whew!
176
Local l = SynchronizerManager.v().addStmtsToFetchClassBefore(containerB, toInline);
177                         SynchronizerManager.v().synchronizeStmtOn(toInline, containerB, l);
178                     }
179                 }
180             }
181         }
182
183         Stmt exitPoint = (Stmt)containerUnits.getSuccOf(toInline);
184
185         // First, clone all of the inlinee's units & locals.
186
HashMap oldLocalsToNew = new HashMap();
187         HashMap oldUnitsToNew = new HashMap();
188         {
189             Stmt cursor = toInline;
190             for( Iterator currIt = inlineeUnits.iterator(); currIt.hasNext(); ) {
191                 final Stmt curr = (Stmt) currIt.next();
192                 Stmt currPrime = (Stmt)curr.clone();
193                 if (currPrime == null)
194                     throw new RuntimeException JavaDoc("getting null from clone!");
195                 currPrime.addAllTagsOf(curr);
196
197                 containerUnits.insertAfter(currPrime, cursor);
198                 cursor = currPrime;
199
200                 oldUnitsToNew.put(curr, currPrime);
201             }
202
203             for( Iterator lIt = inlineeB.getLocals().iterator(); lIt.hasNext(); ) {
204
205                 final Local l = (Local) lIt.next();
206                 Local lPrime = (Local)l.clone();
207                 if (lPrime == null)
208                     throw new RuntimeException JavaDoc("getting null from local clone!");
209
210                 containerB.getLocals().add(lPrime);
211                 oldLocalsToNew.put(l, lPrime);
212             }
213         }
214
215         // Backpatch the newly-inserted units using newly-constructed maps.
216
{
217             Iterator it = containerUnits.iterator
218                 (containerUnits.getSuccOf(toInline),
219                  containerUnits.getPredOf(exitPoint));
220
221             while (it.hasNext())
222             {
223                 Stmt patchee = (Stmt)it.next();
224
225                 Iterator duBoxes = patchee.getUseAndDefBoxes().iterator();
226                 while (duBoxes.hasNext())
227                 {
228                     ValueBox box = (ValueBox)duBoxes.next();
229                     if (!(box.getValue() instanceof Local))
230                         continue;
231
232                     Local lPrime = (Local)(oldLocalsToNew.get(box.getValue()));
233                     if (lPrime != null)
234                         box.setValue(lPrime);
235                     else
236                         throw new RuntimeException JavaDoc("local has no clone!");
237                 }
238
239                 Iterator unitBoxes = patchee.getUnitBoxes().iterator();
240                 while (unitBoxes.hasNext())
241                 {
242                     UnitBox box = (UnitBox)unitBoxes.next();
243                     Unit uPrime = (Unit)(oldUnitsToNew.get(box.getUnit()));
244                     if (uPrime != null)
245                         box.setUnit(uPrime);
246                     else
247                         throw new RuntimeException JavaDoc("inlined stmt has no clone!");
248                 }
249             }
250         }
251
252         // Copy & backpatch the traps; preserve their same order.
253
{
254             Iterator trapsIt = inlineeB.getTraps().iterator();
255             Trap prevTrap = null;
256
257             while (trapsIt.hasNext())
258             {
259                 Trap t = (Trap)trapsIt.next();
260                 Stmt newBegin = (Stmt)oldUnitsToNew.get(t.getBeginUnit()),
261                     newEnd = (Stmt)oldUnitsToNew.get(t.getEndUnit()),
262                     newHandler = (Stmt)oldUnitsToNew.get(t.getHandlerUnit());
263
264                 if (newBegin == null || newEnd == null || newHandler == null)
265                     throw new RuntimeException JavaDoc("couldn't map trap!");
266
267                 Trap trap = Jimple.v().newTrap(t.getException(),
268                                                newBegin, newEnd, newHandler);
269                 if (prevTrap == null)
270                     containerB.getTraps().addFirst(trap);
271                 else
272                     containerB.getTraps().insertAfter(trap, prevTrap);
273                 prevTrap = trap;
274             }
275         }
276
277         // Handle identity stmt's and returns.
278
{
279             Iterator it = containerUnits.iterator
280                 (containerUnits.getSuccOf(toInline),
281                  containerUnits.getPredOf(exitPoint));
282             ArrayList cuCopy = new ArrayList();
283
284             while (it.hasNext())
285             {
286                 cuCopy.add(it.next());
287             }
288
289             it = cuCopy.iterator();
290             while (it.hasNext())
291             {
292                 Stmt s = (Stmt)it.next();
293
294                 if (s instanceof IdentityStmt)
295                 {
296                     IdentityRef rhs = (IdentityRef)((IdentityStmt)s).getRightOp();
297                     if (rhs instanceof CaughtExceptionRef)
298                         continue;
299                     else if (rhs instanceof ThisRef)
300                     {
301                         if (!(ie instanceof InstanceInvokeExpr))
302                             throw new RuntimeException JavaDoc("thisref with no receiver!");
303
304                         containerUnits.swapWith(s, Jimple.v().newAssignStmt(((IdentityStmt)s).getLeftOp(),
305                                                                             thisToAdd));
306                     }
307                     else if (rhs instanceof ParameterRef)
308                     {
309                         ParameterRef pref = (ParameterRef)rhs;
310                         containerUnits.swapWith(s, Jimple.v().newAssignStmt(((IdentityStmt)s).getLeftOp(),
311                                                                             ie.getArg(pref.getIndex())));
312                     }
313                 }
314                 else if (s instanceof ReturnStmt)
315                 {
316                     if (toInline instanceof InvokeStmt)
317                     {
318                         // munch, munch.
319
containerUnits.swapWith(s, Jimple.v().newGotoStmt(exitPoint));
320                         continue;
321                     }
322
323                     if (!(toInline instanceof AssignStmt))
324                         throw new RuntimeException JavaDoc
325                             ("invoking stmt neither InvokeStmt nor AssignStmt!??!?!");
326                     Value ro = ((ReturnStmt)s).getOp();
327                     Value lhs = ((AssignStmt)toInline).getLeftOp();
328                     AssignStmt as = Jimple.v().newAssignStmt(lhs, ro);
329                     containerUnits.insertBefore(as, s);
330                     containerUnits.swapWith(s, Jimple.v().newGotoStmt(exitPoint));
331                 }
332                 else if (s instanceof ReturnVoidStmt)
333                     containerUnits.swapWith(s, Jimple.v().newGotoStmt(exitPoint));
334             }
335         }
336
337         List newStmts = new ArrayList();
338         for(Iterator i = containerUnits.iterator(containerUnits.getSuccOf(toInline), containerUnits.getPredOf(exitPoint)); i.hasNext();) {
339             newStmts.add(i.next());
340         }
341         
342         // Remove the original statement toInline.
343
containerUnits.remove(toInline);
344
345         // Resolve name collisions.
346
LocalNameStandardizer.v().transform(containerB, "ji.lns");
347         
348         return newStmts;
349     }
350 }
351
Popular Tags