KickJava   Java API By Example, From Geeks To Geeks.

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


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 import soot.options.*;
28
29 import soot.*;
30 import soot.jimple.*;
31 import soot.jimple.toolkits.scalar.*;
32 import soot.jimple.toolkits.callgraph.*;
33 import soot.toolkits.scalar.*;
34 import soot.toolkits.graph.*;
35 import java.util.*;
36 import soot.util.*;
37
38 /** Uses the Scene's currently-active InvokeGraph to statically bind monomorphic call sites. */
39 public class StaticMethodBinder extends SceneTransformer
40 {
41     public StaticMethodBinder( Singletons.Global g ) {}
42     public static StaticMethodBinder v() { return G.v().soot_jimple_toolkits_invoke_StaticMethodBinder(); }
43
44     protected void internalTransform(String JavaDoc phaseName, Map opts)
45     {
46         Filter instanceInvokesFilter = new Filter( new InstanceInvokeEdgesPred() );
47         SMBOptions options = new SMBOptions( opts );
48         String JavaDoc modifierOptions = PhaseOptions.getString( opts, "allowed-modifier-changes");
49         HashMap instanceToStaticMap = new HashMap();
50
51         CallGraph cg = Scene.v().getCallGraph();
52         Hierarchy hierarchy = Scene.v().getActiveHierarchy();
53
54         Iterator classesIt = Scene.v().getApplicationClasses().iterator();
55         while (classesIt.hasNext())
56         {
57             SootClass c = (SootClass)classesIt.next();
58             
59             LinkedList methodsList = new LinkedList();
60             for( Iterator it = c.methodIterator(); it.hasNext(); ) {
61                 methodsList.add(it.next());
62             }
63
64             while (!methodsList.isEmpty())
65             {
66                 SootMethod container = (SootMethod)methodsList.removeFirst();
67
68                 if (!container.isConcrete())
69                     continue;
70
71                 if (!instanceInvokesFilter.wrap( cg.edgesOutOf(container) ).hasNext())
72                     continue;
73
74                 JimpleBody b = (JimpleBody)container.getActiveBody();
75                 
76                 List unitList = new ArrayList(); unitList.addAll(b.getUnits());
77                 Iterator unitIt = unitList.iterator();
78
79                 while (unitIt.hasNext())
80                 {
81                     Stmt s = (Stmt)unitIt.next();
82                     if (!s.containsInvokeExpr())
83                         continue;
84
85
86                     InvokeExpr ie = (InvokeExpr)s.getInvokeExpr();
87
88                     if (ie instanceof StaticInvokeExpr ||
89                         ie instanceof SpecialInvokeExpr)
90                         continue;
91
92                     Iterator targets = new Targets(
93                             instanceInvokesFilter.wrap( cg.edgesOutOf(s) ) );
94                     if( !targets.hasNext() ) continue;
95                     SootMethod target = (SootMethod)targets.next();
96                     if( targets.hasNext() ) continue;
97
98                     // Ok, we have an Interface or VirtualInvoke going to 1.
99

100                     
101                     if (!AccessManager.ensureAccess(container, target, modifierOptions))
102                         continue;
103                     
104                     if (!target.getDeclaringClass().isApplicationClass() || !target.isConcrete())
105                         continue;
106
107                     // Don't modify java.lang.Object
108
if (target.getDeclaringClass()==Scene.v().getSootClass("java.lang.Object"))
109                         continue;
110
111                     boolean targetUsesThis = true; //methodUsesThis(target);
112
// targetUsesThis = true;
113

114                     if (!instanceToStaticMap.containsKey(target))
115                     {
116                         List newParameterTypes = new ArrayList();
117                         if (targetUsesThis)
118                             newParameterTypes.add
119                                 (RefType.v(target.getDeclaringClass().getName()));
120
121                         newParameterTypes.addAll(target.getParameterTypes());
122
123                         // Check for signature conflicts.
124
String JavaDoc newName = target.getName() + "_static";
125                         while (target.getDeclaringClass().declaresMethod(newName,
126                                                 newParameterTypes,
127                                                 target.getReturnType()))
128                             newName = newName + "_static";
129
130                         SootMethod ct = new SootMethod(newName, newParameterTypes,
131                                                        target.getReturnType(), target.getModifiers() | Modifier.STATIC,
132                                                        target.getExceptions());
133                         target.getDeclaringClass().addMethod(ct);
134
135                         methodsList.addLast(ct);
136
137                         ct.setActiveBody((Body)target.getActiveBody().clone());
138
139                         // Make the invoke graph take into account the newly-cloned body.
140
{
141                             Iterator oldUnits = target.getActiveBody().getUnits().iterator();
142                             Iterator newUnits = ct.getActiveBody().getUnits().iterator();
143
144                             while (newUnits.hasNext())
145                             {
146                                 Stmt oldStmt, newStmt;
147                                 oldStmt = (Stmt)oldUnits.next();
148                                 newStmt = (Stmt)newUnits.next();
149
150                                 Iterator edges = cg.edgesOutOf( oldStmt );
151                                 while( edges.hasNext() ) {
152                                     Edge e = (Edge) edges.next();
153                                     cg.addEdge( new Edge(
154                                         ct, newStmt, e.tgt(), e.kind() ) );
155                                     cg.removeEdge( e );
156                                 }
157                             }
158                         }
159
160                         // Shift the parameter list to apply to the new this parameter.
161
// If the method uses this, then we replace
162
// the r0 := @this with r0 := @parameter0 & shift.
163
// Otherwise, just zap the r0 := @this.
164
{
165                             Body newBody = ct.getActiveBody();
166
167                             Chain units = newBody.getUnits();
168
169                             Iterator unitsIt = newBody.getUnits().snapshotIterator();
170                             while (unitsIt.hasNext())
171                             {
172                                 Stmt st = (Stmt)unitsIt.next();
173                                 if (st instanceof IdentityStmt)
174                                 {
175                                     IdentityStmt is = (IdentityStmt)st;
176                                     if (is.getRightOp() instanceof ThisRef)
177                                     {
178                                         if (targetUsesThis)
179                                             units.swapWith(st, Jimple.v().newIdentityStmt(is.getLeftOp(),
180                                                     Jimple.v().newParameterRef(is.getRightOp().getType(), 0)));
181                                         else
182                                             { units.remove(st); break; }
183                                     }
184                                     else if (targetUsesThis)
185                                     {
186                                         if (is.getRightOp() instanceof ParameterRef)
187                                         {
188                                             ParameterRef ro = (ParameterRef)is.getRightOp();
189                                             ro.setIndex(ro.getIndex() + 1);
190                                         }
191                                     }
192                                 }
193                             }
194                             
195                         }
196
197                         instanceToStaticMap.put(target, ct);
198                     }
199
200                     SootMethod clonedTarget = (SootMethod)instanceToStaticMap.get(target);
201                     Value thisToAdd = ((InstanceInvokeExpr)ie).getBase();
202
203                     // Insert casts to please the verifier.
204
if (options.insert_redundant_casts() && targetUsesThis)
205                     {
206                         // The verifier will complain if targetUsesThis, and:
207
// the argument passed to the method is not the same type.
208
// For instance, Bottle.price_static takes a cost.
209
// Cost is an interface implemented by Bottle.
210
SootClass localType, parameterType;
211                         localType = ((RefType)((InstanceInvokeExpr)ie).getBase().getType()).getSootClass();
212                         parameterType = target.getDeclaringClass();
213
214                         if (localType.isInterface() ||
215                              hierarchy.isClassSuperclassOf(localType, parameterType))
216                         {
217                             Local castee = Jimple.v().newLocal("__castee", parameterType.getType());
218                             b.getLocals().add(castee);
219                             b.getUnits().insertBefore(Jimple.v().newAssignStmt(castee,
220                                                          Jimple.v().newCastExpr(((InstanceInvokeExpr)ie).getBase(),
221                                                                                 parameterType.getType())), s);
222                             thisToAdd = castee;
223                         }
224                     }
225
226                     // Now rebind the method call & fix the invoke graph.
227
{
228                         List newArgs = new ArrayList();
229                         if (targetUsesThis)
230                             newArgs.add(thisToAdd);
231                         newArgs.addAll(ie.getArgs());
232
233                         StaticInvokeExpr sie = Jimple.v().newStaticInvokeExpr
234                             (clonedTarget.makeRef(), newArgs);
235                         
236                         ValueBox ieBox = s.getInvokeExprBox();
237                         ieBox.setValue(sie);
238
239                         cg.addEdge( new Edge( container, s, clonedTarget ) );
240                     }
241
242                     // (If enabled), add a null pointer check.
243
if (options.insert_null_checks())
244                     {
245                         boolean caught = TrapManager.isExceptionCaughtAt
246                             (Scene.v().getSootClass("java.lang.NullPointerException"), s, b);
247
248                         /* Ah ha. Caught again! */
249                         if (caught)
250                         {
251                             /* In this case, we don't use throwPoint;
252                              * instead, put the code right there. */

253                             Stmt insertee = Jimple.v().newIfStmt(Jimple.v().newNeExpr(((InstanceInvokeExpr)ie).getBase(),
254                                 NullConstant.v()), s);
255
256                             b.getUnits().insertBefore(insertee, s);
257
258                             // This sucks (but less than before).
259
((IfStmt)insertee).setTarget(s);
260
261                             ThrowManager.addThrowAfter(b, insertee);
262                         }
263                         else
264                         {
265                             Stmt throwPoint =
266                                 ThrowManager.getNullPointerExceptionThrower(b);
267                             b.getUnits().insertBefore
268                                 (Jimple.v().newIfStmt(Jimple.v().newEqExpr(((InstanceInvokeExpr)ie).getBase(),
269                                 NullConstant.v()), throwPoint),
270                                  s);
271                         }
272                     }
273                     
274                     // Add synchronizing stuff.
275
{
276                         if (target.isSynchronized())
277                         {
278                             clonedTarget.setModifiers(clonedTarget.getModifiers() & ~Modifier.SYNCHRONIZED);
279                             SynchronizerManager.v().synchronizeStmtOn(s, b, (Local)((InstanceInvokeExpr)ie).getBase());
280                         }
281                     }
282
283                     // Resolve name collisions.
284
LocalNameStandardizer.v().transform(b, phaseName + ".lns");
285                 }
286             }
287         }
288     }
289
290     private static boolean methodUsesThis(SootMethod m)
291     {
292         JimpleBody b = (JimpleBody)m.getActiveBody();
293         ExceptionalUnitGraph g = new ExceptionalUnitGraph(b);
294         LocalDefs ld = new SmartLocalDefs(g, new SimpleLiveLocals(g));
295         LocalUses lu = new SimpleLocalUses(g, ld);
296
297         // Look for the first identity stmt assigning from @this.
298
{
299             Iterator unitsIt = b.getUnits().iterator();
300             while (unitsIt.hasNext())
301             {
302                 Stmt s = (Stmt)unitsIt.next();
303                 if (s instanceof IdentityStmt &&
304                     ((IdentityStmt)s).getRightOp() instanceof ThisRef)
305                     return lu.getUsesOf(s).size() != 0;
306             }
307         }
308
309         throw new RuntimeException JavaDoc("couldn't find identityref!");
310     }
311 }
312
313
314
Popular Tags