KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > optimize > evaluation > VariableOptimizer


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.optimize.evaluation;
22
23 import proguard.classfile.util.*;
24 import proguard.classfile.attribute.visitor.AttributeVisitor;
25 import proguard.classfile.attribute.*;
26 import proguard.classfile.editor.*;
27 import proguard.classfile.*;
28
29 /**
30  * This AttributeVisitor optimizes variable allocation based on their the liveness,
31  * in the code attributes that it visits.
32  *
33  * @author Eric Lafortune
34  */

35 public class VariableOptimizer
36 extends SimplifiedVisitor
37 implements AttributeVisitor
38 {
39     //*
40
private static final boolean DEBUG = false;
41     /*/
42     private static boolean DEBUG = true;
43     //*/

44
45     private static final int MAX_VARIABLES_SIZE = 64;
46
47     private LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer();
48     private VariableRemapper variableRemapper = new VariableRemapper();
49
50     private int[] variableMap = new int[ClassConstants.TYPICAL_VARIABLES_SIZE];
51
52
53     // Implementations for AttributeVisitor.
54

55     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
56
57
58     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
59     {
60 // DEBUG =
61
// clazz.getName().equals("abc/Def") &&
62
// method.getName(clazz).equals("abc");
63

64         // Initialize the global arrays.
65
initializeArrays(codeAttribute);
66
67         // Analyze the liveness of the variables in the code.
68
livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute);
69
70         int parameterSize = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz));
71         if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0)
72         {
73             parameterSize++;
74         }
75
76         int variableSize = codeAttribute.u2maxLocals;
77         int codeLength = codeAttribute.u4codeLength;
78
79         boolean remapping = false;
80
81         // Loop over all variables.
82
for (int oldIndex = 0; oldIndex < variableSize; oldIndex++)
83         {
84             // By default, the variable will be mapped onto itself.
85
variableMap[oldIndex] = oldIndex;
86
87             // Only try remapping the variable if it's not a parameter.
88
if (oldIndex >= parameterSize &&
89                 oldIndex < MAX_VARIABLES_SIZE)
90             {
91                 // Try to remap the variable to a variable with a smaller index.
92
for (int newIndex = 0; newIndex < oldIndex; newIndex++)
93                 {
94                     if (areNonOverlapping(oldIndex, newIndex, codeLength))
95                     {
96                         variableMap[oldIndex] = newIndex;
97
98                         updateLiveness(oldIndex, newIndex, codeLength);
99
100                         remapping = true;
101
102                         // This variable has been remapped. Go to the next one.
103
break;
104                     }
105                 }
106             }
107         }
108
109         // Remap the variables.
110
if (remapping)
111         {
112             if (DEBUG)
113             {
114                 System.out.println("Remapping variables:");
115                 System.out.println(" Class "+ ClassUtil.externalClassName(clazz.getName()));
116                 System.out.println(" Method "+ClassUtil.externalFullMethodDescription(clazz.getName(),
117                                                                                        0,
118                                                                                        method.getName(clazz),
119                                                                                        method.getDescriptor(clazz)));
120                 for (int index = 0; index < variableSize; index++)
121                 {
122                     System.out.println(" ["+index+"] -> ["+variableMap[index]+"]");
123                 }
124             }
125
126             variableRemapper.setVariableMap(variableMap);
127             variableRemapper.visitCodeAttribute(clazz, method, codeAttribute);
128         }
129     }
130
131
132     // Small utility methods.
133

134     /**
135      * Initializes the global arrays.
136      */

137     private void initializeArrays(CodeAttribute codeAttribute)
138     {
139         int codeLength = codeAttribute.u4codeLength;
140
141         // Create new arrays for storing information at each instruction offset.
142
if (variableMap.length < codeLength)
143         {
144             variableMap = new int[codeLength];
145         }
146     }
147
148
149     /**
150      * Returns whether the given variables are never alive at the same time.
151      */

152     private boolean areNonOverlapping(int variableIndex1,
153                                       int variableIndex2,
154                                       int codeLength)
155     {
156         // Loop over all instructions.
157
for (int offset = 0; offset < codeLength; offset++)
158         {
159             if ((livenessAnalyzer.isAliveBefore(offset, variableIndex1) &&
160                  livenessAnalyzer.isAliveBefore(offset, variableIndex2)) ||
161
162                 (livenessAnalyzer.isAliveAfter(offset, variableIndex1) &&
163                  livenessAnalyzer.isAliveAfter(offset, variableIndex2)) ||
164
165                 // For now, exclude Category 2 variables.
166
livenessAnalyzer.isCategory2(offset, variableIndex1))
167             {
168                 return false;
169             }
170         }
171
172         return true;
173     }
174
175
176     /**
177      * Updates the liveness resulting from mapping the given old variable on
178      * the given new variable.
179      */

180     private void updateLiveness(int oldVariableIndex,
181                                 int newVariableIndex,
182                                 int codeLength)
183     {
184         // Loop over all instructions.
185
for (int offset = 0; offset < codeLength; offset++)
186         {
187             // Update the liveness before the instruction.
188
if (livenessAnalyzer.isAliveBefore(offset, oldVariableIndex))
189             {
190                 livenessAnalyzer.setAliveBefore(offset, oldVariableIndex, false);
191                 livenessAnalyzer.setAliveBefore(offset, newVariableIndex, true);
192             }
193
194             // Update the liveness after the instruction.
195
if (livenessAnalyzer.isAliveAfter(offset, oldVariableIndex))
196             {
197                 livenessAnalyzer.setAliveAfter(offset, oldVariableIndex, false);
198                 livenessAnalyzer.setAliveAfter(offset, newVariableIndex, true);
199             }
200         }
201     }
202 }
203
Popular Tags