KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > dava > MethodCallFinder


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 2005 Nomair A. Naeem
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  * This class is created by the DavaStaticBlockCleaner classes method staticBlockInlining
22  * It is only invoked for the bodies of clinit methods
23  */

24
25 package soot.dava;
26
27 import java.util.ArrayList JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import soot.RefType;
33 import soot.Scene;
34 import soot.SootClass;
35 import soot.SootMethod;
36 import soot.SootMethodRef;
37 import soot.dava.internal.AST.ASTDoWhileNode;
38 import soot.dava.internal.AST.ASTForLoopNode;
39 import soot.dava.internal.AST.ASTIfElseNode;
40 import soot.dava.internal.AST.ASTIfNode;
41 import soot.dava.internal.AST.ASTLabeledBlockNode;
42 import soot.dava.internal.AST.ASTMethodNode;
43 import soot.dava.internal.AST.ASTNode;
44 import soot.dava.internal.AST.ASTStatementSequenceNode;
45 import soot.dava.internal.AST.ASTSwitchNode;
46 import soot.dava.internal.AST.ASTSynchronizedBlockNode;
47 import soot.dava.internal.AST.ASTTryNode;
48 import soot.dava.internal.AST.ASTUnconditionalLoopNode;
49 import soot.dava.internal.AST.ASTWhileNode;
50 import soot.dava.internal.asg.AugmentedStmt;
51 import soot.dava.toolkits.base.AST.analysis.DepthFirstAdapter;
52 import soot.dava.toolkits.base.AST.traversals.ASTParentNodeFinder;
53 import soot.grimp.internal.GNewInvokeExpr;
54 import soot.grimp.internal.GThrowStmt;
55 import soot.jimple.InvokeExpr;
56 import soot.jimple.InvokeStmt;
57 import soot.jimple.Stmt;
58 import soot.jimple.StringConstant;
59
60 public class MethodCallFinder extends DepthFirstAdapter{
61     ASTMethodNode underAnalysis;
62
63     DavaStaticBlockCleaner cleaner;
64
65     public MethodCallFinder(DavaStaticBlockCleaner cleaner){
66         this.cleaner=cleaner;
67         underAnalysis=null;
68     }
69
70     public MethodCallFinder(boolean verbose,DavaStaticBlockCleaner cleaner){
71         super(verbose);
72         this.cleaner=cleaner;
73         underAnalysis=null;
74     }
75
76     public void inASTMethodNode(ASTMethodNode node){
77         underAnalysis=node;
78     }
79
80     /*
81      * some ASTConstuct{ ASTConstruct{
82      * Some bodies Some Bodies
83      * Statement SequenceNode New Stmt seq node with some stmts
84      * some stmts ----------> Body of method to inline
85      * the invoke stmt New Stmt seq node with other stmts
86      * some other stmts Some other bodies
87      * Some other bodies End ASTConstruct
88      * End ASTConstruct
89      */

90
91
92     /*
93      * Notice that since this class is only invoked for clinit methods this invoke statement is some
94      * invocation that occured within the clinit method
95      */

96     public void inInvokeStmt(InvokeStmt s){
97         InvokeExpr invokeExpr = s.getInvokeExpr();
98         SootMethod maybeInline = invokeExpr.getMethod();
99
100         //check whether we want to inline
101
ASTMethodNode toInlineASTMethod = cleaner.inline(maybeInline);
102         if(toInlineASTMethod ==null){
103             //not to inline
104
return;
105         }
106         else{//yes we want to inline
107
// we know that the method to be inlined has no declarations.
108
List JavaDoc subBodies = toInlineASTMethod.get_SubBodies();
109             if(subBodies.size() != 1){
110                 throw new RuntimeException JavaDoc ("Found ASTMEthod node with more than one subBodies");
111             }
112             List JavaDoc body = (List JavaDoc)subBodies.get(0);
113
114         
115             ASTParentNodeFinder finder = new ASTParentNodeFinder();
116             underAnalysis.apply(finder);
117         
118             List JavaDoc newChangedBodyPart = createChangedBodyPart(s,body,finder);
119
120
121             boolean replaced = replaceSubBody(s,newChangedBodyPart,finder);
122
123         
124             if(replaced){
125                 //so the invoke stmt has been replaced with the body of the method invoked
126

127                 /*
128                  * if the inlined method contained an assignment to a static field
129                  * we want to replace that with a throw stmt
130                  */

131                 StaticDefinitionFinder defFinder = new StaticDefinitionFinder(maybeInline);
132                 toInlineASTMethod.apply(defFinder);
133                 
134                 if(defFinder.anyFinalFieldDefined()){
135                     //create throw stmt to be added to inlined method
136

137                     //create a SootMethodRef
138
SootClass runtime = Scene.v().loadClassAndSupport("java.lang.RuntimeException");
139                     if(runtime.declaresMethod("void <init>(java.lang.String)")){
140             SootMethod sootMethod = runtime.getMethod("void <init>(java.lang.String)");
141             SootMethodRef methodRef = sootMethod.makeRef();
142             RefType myRefType = RefType.v(runtime);
143             StringConstant tempString = StringConstant.v("This method used to have a definition of a final variable. "+
144                                      "Dava inlined the definition into the static initializer");
145             List JavaDoc list = new ArrayList JavaDoc();
146             list.add(tempString);
147             
148             GNewInvokeExpr newInvokeExpr = new GNewInvokeExpr(myRefType,methodRef,list);
149
150             GThrowStmt throwStmt = new GThrowStmt(newInvokeExpr);
151                         
152             AugmentedStmt augStmt = new AugmentedStmt(throwStmt);
153             List JavaDoc sequence = new ArrayList JavaDoc();
154             sequence.add(augStmt);
155             ASTStatementSequenceNode seqNode = new ASTStatementSequenceNode(sequence);
156             List JavaDoc subBody = new ArrayList JavaDoc();
157             subBody.add(seqNode);
158
159             toInlineASTMethod.replaceBody(subBody);
160             }
161         }
162         }
163
164     }
165     }
166
167     public List JavaDoc getSubBodyFromSingleSubBodyNode(ASTNode node){
168         List JavaDoc subBodies = node.get_SubBodies();
169         if(subBodies.size() != 1)
170             throw new RuntimeException JavaDoc("Found a single subBody node with more than 1 subBodies");
171
172         return (List JavaDoc)subBodies.get(0);
173     }
174
175
176     public List JavaDoc createNewSubBody(List JavaDoc orignalBody, List JavaDoc partNewBody,Object JavaDoc stmtSeqNode){
177
178     List JavaDoc newBody = new ArrayList JavaDoc();
179
180     Iterator JavaDoc it = orignalBody.iterator();
181     while(it.hasNext()){
182         Object JavaDoc temp = it.next();
183         if(temp != stmtSeqNode)
184         newBody.add(temp);
185         else{
186         //breaks out of the loop as soon as stmtSeqNode is reached
187
break;
188         }
189     }
190     //dont add this stmt sequence node instead add the modified stmt seq nodes and the to be inline method
191
newBody.addAll(partNewBody);
192
193     //add remaining stuff drom the orignalBody
194
while(it.hasNext()){
195         newBody.add(it.next());
196     }
197     
198     return newBody;
199     }
200
201
202     public boolean replaceSubBody(InvokeStmt s, List JavaDoc newChangedBodyPart,ASTParentNodeFinder finder){
203
204     //get the stmt seq node of invoke stmt
205
Object JavaDoc stmtSeqNode = finder.getParentOf(s);
206     
207     // find the parent node of the stmt seq node
208
Object JavaDoc ParentOfStmtSeq = finder.getParentOf(stmtSeqNode);
209     
210     if(ParentOfStmtSeq ==null){
211         throw new RuntimeException JavaDoc ("MethodCall FInder: parent of stmt seq node not found");
212     }
213     
214     ASTNode node = (ASTNode)ParentOfStmtSeq;
215
216     //the decision what to replace and how to replace depends on the type of ASTNode
217

218     if(node instanceof ASTMethodNode){
219         //get the subBody to replace
220
List JavaDoc subBodyToReplace = getSubBodyFromSingleSubBodyNode(node);
221         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
222         ((ASTMethodNode)node).replaceBody(newBody);
223         return true;
224     }
225     else if(node instanceof ASTSynchronizedBlockNode){
226         //get the subBody to replace
227
List JavaDoc subBodyToReplace = getSubBodyFromSingleSubBodyNode(node);
228         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
229         ((ASTSynchronizedBlockNode)node).replaceBody(newBody);
230         return true;
231     }
232     else if(node instanceof ASTLabeledBlockNode){
233         //get the subBody to replace
234
List JavaDoc subBodyToReplace = getSubBodyFromSingleSubBodyNode(node);
235         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
236         ((ASTLabeledBlockNode)node).replaceBody(newBody);
237         return true;
238     }
239     else if(node instanceof ASTUnconditionalLoopNode){
240         //get the subBody to replace
241
List JavaDoc subBodyToReplace = getSubBodyFromSingleSubBodyNode(node);
242         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
243         ((ASTUnconditionalLoopNode)node).replaceBody(newBody);
244         return true;
245     }
246     else if(node instanceof ASTIfNode){
247         //get the subBody to replace
248
List JavaDoc subBodyToReplace = getSubBodyFromSingleSubBodyNode(node);
249         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
250         ((ASTIfNode)node).replaceBody(newBody);
251         return true;
252     }
253     else if(node instanceof ASTWhileNode){
254         //get the subBody to replace
255
List JavaDoc subBodyToReplace = getSubBodyFromSingleSubBodyNode(node);
256         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
257         ((ASTWhileNode)node).replaceBody(newBody);
258         return true;
259     }
260     else if(node instanceof ASTDoWhileNode){
261         //get the subBody to replace
262
List JavaDoc subBodyToReplace = getSubBodyFromSingleSubBodyNode(node);
263         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
264         ((ASTDoWhileNode)node).replaceBody(newBody);
265         return true;
266     }
267     else if(node instanceof ASTForLoopNode){
268         //get the subBody to replace
269
List JavaDoc subBodyToReplace = getSubBodyFromSingleSubBodyNode(node);
270         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
271         ((ASTForLoopNode)node).replaceBody(newBody);
272         return true;
273     }
274     else if(node instanceof ASTIfElseNode){
275         List JavaDoc subBodies = node.get_SubBodies();
276         if(subBodies.size() != 2)
277         throw new RuntimeException JavaDoc("Found an ifelse ASTNode which does not have two bodies");
278         List JavaDoc ifBody = (List JavaDoc)subBodies.get(0);
279         List JavaDoc elseBody = (List JavaDoc)subBodies.get(1);
280
281         //find out which of these bodies has the stmt seq node with the invoke stmt
282
int subBodyNumber=-1;
283         Iterator JavaDoc it = ifBody.iterator();
284         while(it.hasNext()){
285         Object JavaDoc temp = it.next();
286         if(temp == stmtSeqNode){
287             subBodyNumber=0;
288             break;
289         }
290         }
291         if(subBodyNumber!= 0){
292         it = elseBody.iterator();
293         while(it.hasNext()){
294             Object JavaDoc temp = it.next();
295             if(temp == stmtSeqNode){
296             subBodyNumber=1;
297             break;
298             }
299         }
300         }
301         
302         List JavaDoc subBodyToReplace = null;
303         if(subBodyNumber==0)
304         subBodyToReplace=ifBody;
305         else if (subBodyNumber==1)
306         subBodyToReplace=elseBody;
307         else
308         throw new RuntimeException JavaDoc("Could not find the related ASTNode in the method");
309         
310         List JavaDoc newBody = createNewSubBody(subBodyToReplace,newChangedBodyPart,stmtSeqNode);
311
312         if(subBodyNumber==0){
313         ((ASTIfElseNode)node).replaceBody(newBody,elseBody);
314         return true;
315         }
316         else if(subBodyNumber==1){
317         ((ASTIfElseNode)node).replaceBody(ifBody,newBody);
318         return true;
319         }
320     }
321     else if(node instanceof ASTTryNode){
322
323         //NOTE THAT method INLINING Is currently only done in the tryBody and not the catchBody
324
//THe only reason for this being that mostly method calls are made in the try and not the catch
325

326         //get try body
327
List JavaDoc tryBody = ((ASTTryNode)node).get_TryBody();
328         Iterator JavaDoc it = tryBody.iterator();
329         
330         //find whether stmtSeqNode is in the tryBody
331
boolean inTryBody = false;
332         while (it.hasNext()){
333         ASTNode temp = (ASTNode) it.next();
334         if(temp == stmtSeqNode){
335             inTryBody=true;
336             break;
337         }
338         }
339         if(!inTryBody){
340         //return without making any changes
341
return false;
342         }
343         
344         
345         List JavaDoc newBody = createNewSubBody(tryBody,newChangedBodyPart,stmtSeqNode);
346         ((ASTTryNode)node).replaceTryBody(newBody);
347         return true;
348     }
349     else if (node instanceof ASTSwitchNode){
350
351         List JavaDoc indexList = ((ASTSwitchNode)node).getIndexList();
352         Map JavaDoc index2BodyList = ((ASTSwitchNode)node).getIndex2BodyList();
353                     
354         Iterator JavaDoc it = indexList.iterator();
355         while (it.hasNext()) {//going through all the cases of the switch statement
356
Object JavaDoc currentIndex = it.next();
357         List JavaDoc body = (List JavaDoc) index2BodyList.get( currentIndex);
358                     
359         if (body != null){
360             //this body is a list of ASTNodes
361

362             //see if it contains stmtSeqNode
363
boolean found=false;
364             Iterator JavaDoc itBody = body.iterator();
365             while (itBody.hasNext()){
366             ASTNode temp = (ASTNode) itBody.next();
367             if(temp == stmtSeqNode){
368                 found=true;
369                 break;
370             }
371             }
372             if(found){
373             //this is the body which has the stmt seq node
374
List JavaDoc newBody = createNewSubBody(body,newChangedBodyPart,stmtSeqNode);
375
376             //put this body in the Map
377
index2BodyList.put(currentIndex,newBody);
378             //replace in actual switchNode
379
((ASTSwitchNode)node).replaceIndex2BodyList(index2BodyList);
380             return true;
381             }
382         }//if body not null
383
}//going through all cases
384
}
385     return false;
386     }
387
388
389
390     /*
391      * Given an invoke stmt this method finds the parent of this stmt which should always be a StatementSequenceNode
392      * Then the sequence is broken into three parts.
393      * The first part contains stmts till above the invoke stmt. The second part contains the body argument which is the
394      * body of the inlined method and the third part are the stmts below the invoke stmt
395      */

396     
397     public List JavaDoc createChangedBodyPart(InvokeStmt s, List JavaDoc body, ASTParentNodeFinder finder){
398     //get parent node of invoke stmt
399
Object JavaDoc parent = finder.getParentOf(s);
400     if(parent == null){
401         throw new RuntimeException JavaDoc ("MethodCall FInder: parent of invoke stmt not found");
402     }
403     
404     ASTNode parentNode = (ASTNode)parent;
405     if(!(parentNode instanceof ASTStatementSequenceNode)){
406         throw new RuntimeException JavaDoc ("MethodCall FInder: parent node not a stmt seq node");
407     }
408     
409     ASTStatementSequenceNode orignal = (ASTStatementSequenceNode)parentNode;
410
411
412     //copying the stmts till above the inoke stmt into one stmt sequence node
413
List JavaDoc newInitialNode = new ArrayList JavaDoc();
414     Iterator JavaDoc it = orignal.getStatements().iterator();
415     while(it.hasNext()){
416         AugmentedStmt as = (AugmentedStmt)it.next();
417         Stmt tempStmt = as.get_Stmt();
418         if(tempStmt != s){
419             newInitialNode.add(as);
420         }
421         else{
422             //the first time we get to a stmt which points to the invoke stmt we break
423
break;
424         }
425     }
426     
427     //copy remaining stmts into the AFTER stmt sequence node
428
List JavaDoc newSecondNode = new ArrayList JavaDoc();
429     while(it.hasNext()){
430         newSecondNode.add(it.next());
431     }
432     
433     List JavaDoc toReturn = new ArrayList JavaDoc();
434
435     if(newInitialNode.size()!=0)
436         toReturn.add(new ASTStatementSequenceNode(newInitialNode));
437     
438     //add inline methods body
439
toReturn.addAll(body);
440     
441     if(newSecondNode.size()!=0)
442         toReturn.add(new ASTStatementSequenceNode(newSecondNode));
443     
444     return toReturn;
445     }
446
447         
448
449 }
Popular Tags