KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > optimize > MethodDescriptorShrinker


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 program 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 program 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 General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.optimize;
22
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.visitor.AttributeVisitor;
26 import proguard.classfile.attribute.annotation.*;
27 import proguard.classfile.editor.*;
28 import proguard.classfile.util.*;
29 import proguard.classfile.visitor.MemberVisitor;
30 import proguard.optimize.info.*;
31 import proguard.optimize.peephole.VariableShrinker;
32
33 /**
34  * This MemberVisitor removes unused parameters in the descriptors of the
35  * methods that it visits.
36  *
37  * @see ParameterUsageMarker
38  * @see VariableUsageMarker
39  * @see VariableShrinker
40  * @author Eric Lafortune
41  */

42 public class MethodDescriptorShrinker
43 extends SimplifiedVisitor
44 implements MemberVisitor,
45              AttributeVisitor
46 {
47     private static final boolean DEBUG = false;
48
49
50     private MemberVisitor extraParameterMemberVisitor;
51
52     private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
53
54
55     /**
56      * Creates a new MethodDescriptorShrinker.
57      */

58     public MethodDescriptorShrinker()
59     {
60         this(null);
61     }
62
63
64     /**
65      * Creates a new MethodDescriptorShrinker with an extra visitor.
66      * @param extraParameterMemberVisitor an optional extra visitor for all
67      * methods whose parameters have been
68      * simplified.
69      */

70     public MethodDescriptorShrinker(MemberVisitor extraParameterMemberVisitor)
71     {
72         this.extraParameterMemberVisitor = extraParameterMemberVisitor;
73     }
74
75
76     // Implementations for MemberVisitor.
77

78     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
79     {
80         // Update the descriptor if it has any unused parameters.
81
String JavaDoc descriptor = programMethod.getDescriptor(programClass);
82         String JavaDoc newDescriptor = shrinkDescriptor(programClass, programMethod);
83         if (!descriptor.equals(newDescriptor))
84         {
85             // Shrink the parameter annotations.
86
programMethod.attributesAccept(programClass, this);
87
88             String JavaDoc name = programMethod.getName(programClass);
89             String JavaDoc newName;
90
91             // Is it a class instance initializer?
92
if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
93             {
94                 // Is there already another initializer with the same descriptor?
95
if (programClass.findMethod(name, newDescriptor) != null)
96                 {
97                     // Cancel the shrinking. Mark all parameters.
98
ParameterUsageMarker.markUsedParameters(programMethod, -1L);
99
100                     return;
101                 }
102
103                 // We have to keep the initializer's name.
104
newName = name;
105             }
106             else
107             {
108                 // Create a unique name.
109
newName = name + ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode()));
110             }
111
112             if (DEBUG)
113             {
114                 System.out.println("MethodDescriptorShrinker:");
115                 System.out.println(" Class file = "+programClass.getName());
116                 System.out.println(" Method name = "+name);
117                 System.out.println(" -> "+newName);
118                 System.out.println(" Method descriptor = "+descriptor);
119                 System.out.println(" -> "+newDescriptor);
120             }
121
122             // Update the name, if necessary.
123
if (!newName.equals(name))
124             {
125                 programMethod.u2nameIndex =
126                 constantPoolEditor.addUtf8Constant(programClass, newName);
127             }
128
129             // Clear the unused referenced classes.
130
shrinkReferencedClasses(programClass, programMethod);
131
132             // Update the descriptor.
133
programMethod.u2descriptorIndex =
134                 constantPoolEditor.addUtf8Constant(programClass, newDescriptor);
135
136             // Visit the method, if required.
137
if (extraParameterMemberVisitor != null)
138             {
139                 extraParameterMemberVisitor.visitProgramMethod(programClass, programMethod);
140             }
141         }
142     }
143
144
145     // Implementations for AttributeVisitor.
146

147     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
148
149
150     public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
151     {
152         int[] annotationsCounts = parameterAnnotationsAttribute.u2parameterAnnotationsCount;
153         Annotation[][] annotations = parameterAnnotationsAttribute.parameterAnnotations;
154
155         // All parameters of non-static methods are shifted by one in the local
156
// variable frame.
157
int parameterIndex =
158             (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
159                 0 : 1;
160
161         int annotationIndex = 0;
162         int newAnnotationIndex = 0;
163
164         // Go over the parameters.
165
String JavaDoc descriptor = method.getDescriptor(clazz);
166         InternalTypeEnumeration internalTypeEnumeration =
167             new InternalTypeEnumeration(descriptor);
168
169         while (internalTypeEnumeration.hasMoreTypes())
170         {
171             String JavaDoc type = internalTypeEnumeration.nextType();
172             if (ParameterUsageMarker.isParameterUsed(method, parameterIndex))
173             {
174                 annotationsCounts[newAnnotationIndex] = annotationsCounts[annotationIndex];
175                 annotations[newAnnotationIndex++] = annotations[annotationIndex];
176             }
177
178             annotationIndex++;
179
180             parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
181         }
182
183         // Update the number of parameters.
184
parameterAnnotationsAttribute.u2parametersCount = newAnnotationIndex;
185
186         // Clear the unused entries.
187
while (newAnnotationIndex < annotationIndex)
188         {
189             annotationsCounts[newAnnotationIndex] = 0;
190             annotations[newAnnotationIndex++] = null;
191         }
192     }
193
194
195     // Small utility methods.
196

197     /**
198      * Returns a shrunk descriptor of the given method.
199      */

200     public static String JavaDoc shrinkDescriptor(ProgramClass clazz,
201                                           ProgramMethod method)
202     {
203         // All parameters of non-static methods are shifted by one in the local
204
// variable frame.
205
int parameterIndex =
206             (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
207                 0 : 1;
208
209         // Go over the parameters.
210
InternalTypeEnumeration internalTypeEnumeration =
211             new InternalTypeEnumeration(method.getDescriptor(clazz));
212
213         StringBuffer JavaDoc newDescriptorBuffer = new StringBuffer JavaDoc();
214         newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN);
215
216         if (DEBUG)
217         {
218             System.out.println("MethodDescriptorShrinker: "+method.getName(clazz)+method.getDescriptor(clazz));
219             System.out.println(" parameter size = " + ParameterUsageMarker.getParameterSize(method));
220         }
221
222         while (internalTypeEnumeration.hasMoreTypes())
223         {
224             String JavaDoc type = internalTypeEnumeration.nextType();
225             if (ParameterUsageMarker.isParameterUsed(method, parameterIndex))
226             {
227                 newDescriptorBuffer.append(type);
228             }
229             else if (DEBUG)
230             {
231                 System.out.println(" Deleting parameter #"+parameterIndex+" ("+type+")");
232             }
233
234             parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
235         }
236
237         newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
238         newDescriptorBuffer.append(internalTypeEnumeration.returnType());
239
240         return newDescriptorBuffer.toString();
241     }
242
243
244     /**
245      * Shrinks the array of referenced classes of the given method.
246      */

247     private static void shrinkReferencedClasses(ProgramClass clazz,
248                                                 ProgramMethod method)
249     {
250         Clazz[] referencedClasses = method.referencedClasses;
251
252         if (referencedClasses != null)
253         {
254             // All parameters of non-static methods are shifted by one in the local
255
// variable frame.
256
int parameterIndex =
257                 (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
258                     0 : 1;
259
260             int referencedClassIndex = 0;
261             int newReferencedClassIndex = 0;
262
263             // Go over the parameters.
264
String JavaDoc descriptor = method.getDescriptor(clazz);
265             InternalTypeEnumeration internalTypeEnumeration =
266                 new InternalTypeEnumeration(descriptor);
267
268             while (internalTypeEnumeration.hasMoreTypes())
269             {
270                 String JavaDoc type = internalTypeEnumeration.nextType();
271                 if (ClassUtil.isInternalArrayType(type))
272                 {
273                     type = ClassUtil.internalTypeFromArrayType(type);
274                 }
275
276                 if (ClassUtil.isInternalClassType(type))
277                 {
278                     if (ParameterUsageMarker.isParameterUsed(method, parameterIndex))
279                     {
280                         referencedClasses[newReferencedClassIndex++] =
281                             referencedClasses[referencedClassIndex];
282                     }
283
284                     referencedClassIndex++;
285                 }
286
287                 parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
288             }
289
290             // Also look at the return value.
291
String JavaDoc type = internalTypeEnumeration.returnType();
292             if (ClassUtil.isInternalArrayType(type))
293             {
294                 type = ClassUtil.internalTypeFromArrayType(type);
295             }
296
297             if (ClassUtil.isInternalClassType(type))
298             {
299                 referencedClasses[newReferencedClassIndex++] =
300                     referencedClasses[referencedClassIndex];
301
302                 referencedClassIndex++;
303             }
304
305             // Clear the unused entries.
306
while (newReferencedClassIndex < referencedClassIndex)
307             {
308                 referencedClasses[newReferencedClassIndex++] = null;
309             }
310         }
311     }
312 }
313
Popular Tags