KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > dava > toolkits > base > AST > transformations > LocalVariableCleaner


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  * Maintained by Nomair A. Naeem
22  */

23
24 /*
25  * Change log: * November 23rd, 2005 Class Created
26  */

27
28 package soot.dava.toolkits.base.AST.transformations;
29
30 import soot.*;
31 import java.util.*;
32 import soot.jimple.*;
33 import soot.util.Chain;
34 //import soot.dava.internal.javaRep.*;
35
import soot.dava.DavaBody;
36 import soot.dava.DecompilationException;
37 import soot.dava.internal.AST.*;
38 import soot.dava.internal.asg.*;
39 import soot.dava.toolkits.base.AST.analysis.*;
40 //import soot.dava.toolkits.base.AST.structuredAnalysis.*;
41
import soot.dava.toolkits.base.AST.traversals.*;
42
43 /**
44  * The class is aimed to target cleaning up of unused local variables.
45  * Should be invoked after executing CopyPropagation
46  *
47  * Another thing that this class does which perhaps should have been implemented separatly
48  * is to check whether there is an assignment which never gets used later on.
49  * If there exists such an assignment this assignment is removed first and then all the useless
50  * locals checks should be reapplied (until a fixed point)
51  */

52
53 public class LocalVariableCleaner extends DepthFirstAdapter {
54     public final boolean DEBUG = false;
55     
56     
57     ASTNode AST;
58
59     ASTUsesAndDefs useDefs;
60
61     ASTParentNodeFinder parentOf;
62
63     public LocalVariableCleaner(ASTNode AST) {
64         super();
65         this.AST = AST;
66         parentOf = new ASTParentNodeFinder();
67         AST.apply(parentOf);
68     }
69
70     public LocalVariableCleaner(boolean verbose, ASTNode AST) {
71         super(verbose);
72         this.AST = AST;
73         parentOf = new ASTParentNodeFinder();
74         AST.apply(parentOf);
75     }
76
77     /*
78      * Get all locals declared in the method
79      * If the local is never defined (and hence never used) remove it
80      * If the local is defined BUT never used then you may remove it IF AND ONLY IF
81      * The definition is either a copy stmt or an assignment of a constant (i.e. no side effects)
82      */

83     public void outASTMethodNode(ASTMethodNode node) {
84         boolean redo = false;
85
86         useDefs = new ASTUsesAndDefs(AST); //create the uD and dU chains
87
AST.apply(useDefs);
88
89         //get all local variables declared in this method
90
Iterator decIt = node.getDeclaredLocals().iterator();
91
92         ArrayList removeList = new ArrayList();
93         while (decIt.hasNext()) {
94             //going through each local declared
95

96             Local var = (Local) decIt.next();
97
98             List defs = getDefs(var);
99
100             //if defs is 0 it means var never got defined
101
if (defs.size() == 0) {
102                 //var is never defined and hence is certainly not used anywhere
103
removeList.add(var);
104             } else {
105                 //if a var is defined but not used then in some conditions we can remove it
106

107                 //check that each def is removable
108
Iterator defIt = defs.iterator();
109
110                 while (defIt.hasNext()) {
111                     DefinitionStmt ds = (DefinitionStmt) defIt.next();
112
113                     if (canRemoveDef(ds)) {
114                         //if removeStmt is successful since something change we need to redo
115
//everything hoping something else might be removed....
116
//in this case method returns true
117
redo = removeStmt(ds);
118                     }
119                 }//while going through defs
120

121             }//end else defs was not zero
122
}//going through each stmt
123

124         //go through the removeList and remove all locals
125
Iterator remIt = removeList.iterator();
126         while (remIt.hasNext()) {
127             Local removeLocal = (Local) remIt.next();
128             node.removeDeclaredLocal(removeLocal);
129             
130             /*
131              * Nomair A. Naeem 7th Feb 2005
132              * these have to be removed from the legacy lists in DavaBody also
133              *
134              */

135             //retrieve DavaBody
136
if(AST instanceof ASTMethodNode){
137                 //this should always be true but whatever
138
DavaBody body = ((ASTMethodNode)AST).getDavaBody();
139                 if(DEBUG){
140                     System.out.println("body information");
141                     System.out.println("Control local is: "+body.get_ControlLocal());
142                     System.out.println("his locals are: "+body.get_ThisLocals());
143                     System.out.println("Param Map is: "+body.get_ParamMap());
144                     System.out.println("Locals are:"+body.getLocals());
145                 }
146                 Chain localChain = body.getLocals();
147                 localChain.remove(removeLocal);
148             }
149             else
150                 throw new DecompilationException("found AST which is not a methodNode");
151             
152             
153             
154             
155             if(DEBUG)
156                 System.out.println("Removed"+removeLocal);
157             redo = true;
158         }
159
160         if (redo) {
161             //redo the whole function
162
outASTMethodNode(node);
163         }
164     }
165
166     /*
167      * A def can be removed if and only if:
168      * 1, there are no uses of this definition
169      * 2, the right hand size is either a local or a constant i.e. no need to worry about side effects
170      */

171     public boolean canRemoveDef(DefinitionStmt ds) {
172         List uses = useDefs.getDUChain(ds);
173
174         if (uses.size() != 0)
175             return false;
176
177         //there is no use of this def, we can remove it if it is copy stmt or a constant assignment
178
if (ds.getRightOp() instanceof Local
179                 || ds.getRightOp() instanceof Constant)
180             return true;
181
182         return false;
183     }
184
185     /*
186      * This method looks up all defs and returns those of this local
187      */

188     public List getDefs(Local var) {
189         List toReturn = new ArrayList();
190
191         HashMap dU = useDefs.getDUHashMap();
192         Iterator it = dU.keySet().iterator();
193         while (it.hasNext()) {
194             DefinitionStmt s = (DefinitionStmt) it.next();
195             Value left = s.getLeftOp();
196             if (left instanceof Local) {
197                 if (((Local) left).getName().compareTo(var.getName()) == 0)
198                     toReturn.add(s);
199             }
200         }
201         return toReturn;
202     }
203
204     public boolean removeStmt(Stmt stmt) {
205         Object JavaDoc tempParent = parentOf.getParentOf(stmt);
206         if (tempParent == null) {
207             //System.out.println("NO PARENT FOUND CANT DO ANYTHING");
208
return false;
209         }
210
211         //parents are always ASTNodes, hence safe to cast
212
ASTNode parent = (ASTNode) tempParent;
213
214         //REMOVING STMT
215
if (!(parent instanceof ASTStatementSequenceNode)) {
216             //parent of a statement should always be a ASTStatementSequenceNode
217
return false;
218         }
219         ASTStatementSequenceNode parentNode = (ASTStatementSequenceNode) parent;
220
221         ArrayList newSequence = new ArrayList();
222         List stmts = parentNode.getStatements();
223         int size = stmts.size();
224         Iterator it = stmts.iterator();
225         while (it.hasNext()) {
226             AugmentedStmt as = (AugmentedStmt) it.next();
227             Stmt s = as.get_Stmt();
228             if (s.toString().compareTo(stmt.toString()) != 0) {
229                 //this is not the stmt to be removed
230
newSequence.add(as);
231             }
232         }
233         //System.out.println("STMT REMOVED---------------->"+stmt);
234
parentNode.setStatements(newSequence);
235         if (newSequence.size() < size)
236             return true; //size of new node is smaller than orignal size
237

238         return false;//didnt actually delete anything for some weird reason...shouldnt happen
239
}
240
241 }
Popular Tags