KickJava   Java API By Example, From Geeks To Geeks.

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


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 1999 Patrick Lam
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.util.*;
31 import java.util.*;
32
33 /** Utility methods for dealing with synchronization. */
34 public class SynchronizerManager
35 {
36     public SynchronizerManager( Singletons.Global g ) {}
37     public static SynchronizerManager v() { return G.v().soot_jimple_toolkits_invoke_SynchronizerManager(); }
38     /** Maps classes to class$ fields. Don't trust default. */
39     public HashMap classToClassField = new HashMap();
40
41     /** Adds code to fetch the static Class object to the given JimpleBody
42      * before the target Stmt.
43      *
44      * Uses our custom classToClassField field to cache the results.
45      *
46      * The code will look like this:
47      *
48 <pre>
49         $r3 = <quack: java.lang.Class class$quack>;
50         .if $r3 != .null .goto label2;
51
52         $r3 = .staticinvoke <quack: java.lang.Class class$(java.lang.String)>("quack");
53         <quack: java.lang.Class class$quack> = $r3;
54
55      label2:
56 </pre>
57      */

58     public Local addStmtsToFetchClassBefore(JimpleBody jb, Stmt target)
59     {
60         SootClass sc = jb.getMethod().getDeclaringClass();
61         SootField classCacher = (SootField)classToClassField.get(sc);
62         if (classCacher == null)
63         {
64             // Add a unique field named [__]class$name
65
String JavaDoc n = "class$"+sc.getName().replace('.', '$');
66             while (sc.declaresFieldByName(n))
67                 n = "_" + n;
68
69             classCacher = new SootField(n, RefType.v("java.lang.Class"), Modifier.STATIC);
70             sc.addField(classCacher);
71             classToClassField.put(sc, classCacher);
72         }
73
74         String JavaDoc lName = "$uniqueClass";
75
76         // Find unique name. Not strictly necessary unless we parse Jimple code.
77
while (true)
78         {
79             Iterator it = jb.getLocals().iterator();
80             boolean oops = false;
81             while (it.hasNext())
82             {
83                 Local jbLocal = (Local)it.next();
84                 if (jbLocal.getName().equals(lName))
85                     oops = true;
86             }
87             if (!oops)
88                 break;
89             lName = "_" + lName;
90         }
91
92         Local l = Jimple.v().newLocal(lName, RefType.v("java.lang.Class"));
93         jb.getLocals().add(l);
94         Chain units = jb.getUnits();
95         units.insertBefore(Jimple.v().newAssignStmt(l,
96                                   Jimple.v().newStaticFieldRef(classCacher.makeRef())),
97                            target);
98
99         IfStmt ifStmt;
100         units.insertBefore(ifStmt = Jimple.v().newIfStmt
101                            (Jimple.v().newNeExpr(l, NullConstant.v()),
102                             target), target);
103
104         units.insertBefore(Jimple.v().newAssignStmt
105             (l, Jimple.v().newStaticInvokeExpr(getClassFetcherFor(sc).makeRef(),
106             Arrays.asList(new Value[] {StringConstant.v(sc.getName())}))),
107                            target);
108         units.insertBefore(Jimple.v().newAssignStmt
109                            (Jimple.v().newStaticFieldRef(classCacher.makeRef()),
110                             l), target);
111
112         ifStmt.setTarget(target);
113         return l;
114     }
115
116     /** Finds a method which calls java.lang.Class.forName(String).
117      * Searches for names class$, _class$, __class$, etc.
118      * If no such method is found, creates one and returns it.
119      *
120      * Uses dumb matching to do search. Not worth doing symbolic
121      * analysis for this! */

122     public SootMethod getClassFetcherFor(SootClass c)
123     {
124         String JavaDoc methodName = "class$";
125         for ( ; true; methodName = "_" + methodName)
126         {
127             if (!c.declaresMethodByName(methodName))
128                 return createClassFetcherFor(c, methodName);
129
130             SootMethod m = c.getMethodByName(methodName);
131
132             // Check signature.
133
if (!m.getSignature().equals
134                      ("<"+c.getName().replace('.', '$')+": java.lang.Class "+
135                       methodName+"(java.lang.String)>"))
136                 continue;
137
138             Body b = null;
139             b = m.retrieveActiveBody();
140
141             Iterator unitsIt = b.getUnits().iterator();
142             
143             /* we now look for the following fragment: */
144             /* r0 := @parameter0: java.lang.String;
145              * $r2 = .staticinvoke <java.lang.Class: java.lang.Class forName(java.lang.String)>(r0);
146              * .return $r2;
147              *
148              * Ignore the catching code; this is enough. */

149
150             if (!unitsIt.hasNext())
151                 continue;
152
153             Stmt s = (Stmt)unitsIt.next();
154             if (!(s instanceof IdentityStmt))
155                 continue;
156
157             IdentityStmt is = (IdentityStmt)s;
158             Value lo = is.getLeftOp(), ro = is.getRightOp();
159
160             if (!(ro instanceof ParameterRef))
161                 continue;
162
163             ParameterRef pr = (ParameterRef)ro;
164             if (pr.getIndex() != 0)
165                 continue;
166
167             if (!unitsIt.hasNext())
168                 continue;
169
170             s = (Stmt)unitsIt.next();
171             if (!(s instanceof AssignStmt))
172                 continue;
173
174             AssignStmt as = (AssignStmt)s;
175             Value retVal = as.getLeftOp(), ie = as.getRightOp();
176
177             if (!ie.toString().equals(".staticinvoke <java.lang.Class: java.lang.Class forName(java.lang.String)>("+lo+")"))
178                 continue;
179            
180             if (!unitsIt.hasNext())
181                 continue;
182
183             s = (Stmt)unitsIt.next();
184             if (!(s instanceof ReturnStmt))
185                 continue;
186
187             ReturnStmt rs = (ReturnStmt) s;
188             if (!rs.getOp().equivTo(retVal))
189                 continue;
190
191             /* don't care about rest. we have sufficient code. */
192             /* in particular, it certainly returns Class.forName(arg). */
193             return m;
194         }
195     }
196
197     /** Creates a method which calls java.lang.Class.forName(String).
198      *
199      * The method should look like the following:
200 <pre>
201          .static java.lang.Class class$(java.lang.String)
202          {
203              java.lang.String r0, $r5;
204              java.lang.ClassNotFoundException r1, $r3;
205              java.lang.Class $r2;
206              java.lang.NoClassDefFoundError $r4;
207
208              r0 := @parameter0: java.lang.String;
209
210          label0:
211              $r2 = .staticinvoke <java.lang.Class: java.lang.Class forName(java.lang.String)>(r0);
212              .return $r2;
213
214          label1:
215              $r3 := @caughtexception;
216              r1 = $r3;
217              $r4 = .new java.lang.NoClassDefFoundError;
218              $r5 = .virtualinvoke r1.<java.lang.Throwable: java.lang.String getMessage()>();
219              .specialinvoke $r4.<java.lang.NoClassDefFoundError: .void <init>(java.lang.String)>($r5);
220              .throw $r4;
221
222              .catch java.lang.ClassNotFoundException .from label0 .to label1 .with label1;
223          }
224 </pre>
225     */

226     public SootMethod createClassFetcherFor(SootClass c,
227                                                    String JavaDoc methodName)
228     {
229         // Create the method
230
SootMethod method = new SootMethod(methodName,
231                 Arrays.asList(new Type[] {RefType.v("java.lang.String")}),
232                 RefType.v("java.lang.Class"), Modifier.STATIC);
233         
234            c.addMethod(method);
235            
236         // Create the method body
237
{
238             JimpleBody body = Jimple.v().newBody(method);
239             
240             method.setActiveBody(body);
241             Chain units = body.getUnits();
242             Local l_r0, l_r1, l_r2, l_r3, l_r4, l_r5;
243             
244             // Add some locals
245
l_r0 = Jimple.v().newLocal
246                     ("r0", RefType.v("java.lang.String"));
247                 l_r1 = Jimple.v().newLocal
248                     ("r1", RefType.v("java.lang.ClassNotFoundException"));
249                 l_r2 = Jimple.v().newLocal
250                     ("$r2", RefType.v("java.lang.Class"));
251                 l_r3 = Jimple.v().newLocal
252                     ("$r3", RefType.v("java.lang.ClassNotFoundException"));
253                 l_r4 = Jimple.v().newLocal
254                     ("$r4", RefType.v("java.lang.NoClassDefFoundError"));
255                 l_r5 = Jimple.v().newLocal
256                     ("$r5", RefType.v("java.lang.String"));
257
258                 body.getLocals().add(l_r0);
259                 body.getLocals().add(l_r1);
260                 body.getLocals().add(l_r2);
261                 body.getLocals().add(l_r3);
262                 body.getLocals().add(l_r4);
263                 body.getLocals().add(l_r5);
264
265             // add "r0 := @parameter0: java.lang.String"
266
units.add(Jimple.v().newIdentityStmt(l_r0,
267                       Jimple.v().newParameterRef
268                         (RefType.v("java.lang.String"), 0)));
269             
270             // add "$r2 = .staticinvoke <java.lang.Class: java.lang.Class forName(java.lang.String)>(r0);
271
AssignStmt asi;
272                 units.add(asi = Jimple.v().newAssignStmt(l_r2,
273                     Jimple.v().newStaticInvokeExpr(
274                           Scene.v().getMethod(
275                                "<java.lang.Class: java.lang.Class"+
276                                " forName(java.lang.String)>").makeRef(),
277                           Arrays.asList(new Value[] {l_r0}))));
278
279             // insert "return $r2;"
280
units.add(Jimple.v().newReturnStmt(l_r2));
281
282             // add "r3 := @caughtexception;"
283
Stmt handlerStart;
284                 units.add(handlerStart = Jimple.v().newIdentityStmt(l_r3,
285                         Jimple.v().newCaughtExceptionRef()));
286
287             // add "r1 = r3;"
288
units.add(Jimple.v().newAssignStmt(l_r1, l_r3));
289                             
290             // add "$r4 = .new java.lang.NoClassDefFoundError;"
291
units.add(Jimple.v().newAssignStmt(l_r4,
292                     Jimple.v().newNewExpr(RefType.v
293                               ("java.lang.NoClassDefFoundError"))));
294
295             // add "$r5 = virtualinvoke r1.<java.lang.Throwable: java.lang.String getMessage()>();"
296
units.add(Jimple.v().newAssignStmt(l_r5,
297                     Jimple.v().newVirtualInvokeExpr(l_r1,
298                           Scene.v().getMethod("<java.lang.Throwable: java.lang.String getMessage()>").makeRef(),
299                           new LinkedList())));
300
301             // add .specialinvoke $r4.<java.lang.NoClassDefFoundError: .void <init>(java.lang.String)>($r5);
302
units.add(Jimple.v().newInvokeStmt(
303                      Jimple.v().newSpecialInvokeExpr(l_r4,
304                           Scene.v().getMethod(
305                                "<java.lang.NoClassDefFoundError: void"+
306                                " <init>(java.lang.String)>").makeRef(),
307                           Arrays.asList(new Value[] {l_r5}))));
308
309             // add .throw $r4;
310
units.add(Jimple.v().newThrowStmt(l_r4));
311
312             body.getTraps().add(Jimple.v().newTrap
313                   (Scene.v().getSootClass("java.lang.ClassNotFoundException"),
314                     asi, handlerStart, handlerStart));
315         }
316
317         return method;
318     }
319
320     /** Wraps stmt around a monitor associated with local lock.
321      * When inlining or static method binding, this is the former
322      * base of the invoke expression. */

323     public void synchronizeStmtOn(Stmt stmt, JimpleBody b, Local lock)
324     {
325         Chain units = b.getUnits();
326
327 // TrapManager.splitTrapsAgainst(b, stmt, (Stmt)units.getSuccOf(stmt));
328

329         units.insertBefore(Jimple.v().newEnterMonitorStmt(lock), stmt);
330
331         Stmt exitMon = Jimple.v().newExitMonitorStmt(lock);
332         units.insertAfter(exitMon, stmt);
333
334         // Ok. That was the easy part.
335
// We also need to modify exception blocks to exit the monitor
336
// (they have conveniently been pre-split)
337
// Actually, we don't need to do this.
338
// {
339
// List traps = TrapManager.getTrapsAt(stmt, b);
340
// Iterator trapsIt = traps.iterator();
341

342 // while (trapsIt.hasNext())
343
// {
344
// Trap t = (Trap)trapsIt.next();
345

346 // Stmt s = (Stmt)units.getLast();
347
// Stmt newCaughtRef = (Stmt)t.getHandlerUnit().clone();
348

349 // List l = new ArrayList();
350

351 // l.add(newCaughtRef);
352
// l.add(exitMon.clone());
353
// l.add(Jimple.v().newGotoStmt((Stmt)units.getSuccOf((Stmt)t.getHandlerUnit())));
354

355 // units.insertAfter(l, s);
356
// t.setHandlerUnit(newCaughtRef);
357
// }
358
// }
359

360         // and also we must add a catch Throwable exception block in the appropriate place.
361
{
362             Stmt newGoto = Jimple.v().newGotoStmt((Stmt)units.getSuccOf(exitMon));
363             units.insertAfter(newGoto, exitMon);
364
365             List l = new ArrayList();
366             Local eRef = Jimple.v().newLocal("__exception", RefType.v("java.lang.Throwable"));
367             b.getLocals().add(eRef);
368             Stmt handlerStmt = Jimple.v().newIdentityStmt(eRef, Jimple.v().newCaughtExceptionRef());
369             l.add(handlerStmt);
370             l.add(exitMon.clone());
371             l.add(Jimple.v().newThrowStmt(eRef));
372             units.insertAfter(l, newGoto);
373
374             Trap newTrap = Jimple.v().newTrap(Scene.v().getSootClass("java.lang.Throwable"),
375                                               stmt, (Stmt)units.getSuccOf(stmt),
376                                               handlerStmt);
377             b.getTraps().addFirst(newTrap);
378         }
379     }
380 }
381
Popular Tags