KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > classfile > editor > MethodInvocationFixer


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.classfile.editor;
22
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.visitor.AttributeVisitor;
26 import proguard.classfile.constant.*;
27 import proguard.classfile.constant.visitor.ConstantVisitor;
28 import proguard.classfile.instruction.*;
29 import proguard.classfile.instruction.visitor.InstructionVisitor;
30 import proguard.classfile.util.*;
31 import proguard.classfile.visitor.*;
32
33 /**
34  * This AttributeVisitor fixes all inappropriate special/virtual/static/interface
35  * invocations of the code attributes that it visits.
36  *
37  * @author Eric Lafortune
38  */

39 public class MethodInvocationFixer
40 extends SimplifiedVisitor
41 implements AttributeVisitor,
42              InstructionVisitor,
43              ConstantVisitor,
44              ClassVisitor,
45              MemberVisitor
46 {
47     private static final boolean DEBUG = false;
48
49
50     private CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
51
52     // Return values for the visitor methods.
53
private Clazz referencedClass;
54     private Clazz referencedMethodClass;
55     private Member referencedMethod;
56
57
58     // Implementations for AttributeVisitor.
59

60     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
61
62
63     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
64     {
65         // Reset the code attribute editor.
66
codeAttributeEditor.reset(codeAttribute.u4codeLength);
67
68         // Remap the variables of the instructions.
69
codeAttribute.instructionsAccept(clazz, method, this);
70
71         // Apply the code atribute editor.
72
codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
73     }
74
75
76     // Implementations for InstructionVisitor.
77

78     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
79
80
81     public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
82     {
83         int constantIndex = constantInstruction.constantIndex;
84
85         // Get information on the called class and method, if present.
86
referencedMethod = null;
87
88         clazz.constantPoolEntryAccept(constantIndex, this);
89
90         // Did we find the called class and method?
91
if (referencedMethod != null)
92         {
93             // Do we need to update the opcode?
94
byte opcode = constantInstruction.opcode;
95
96             // Is the method static?
97
if ((referencedMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0)
98             {
99                 // But is it not a static invocation?
100
if (opcode != InstructionConstants.OP_INVOKESTATIC)
101                 {
102                     // Replace the invocation by an invokestatic instruction.
103
Instruction replacementInstruction =
104                         new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC,
105                                                 constantIndex).shrink();
106
107                     codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
108
109                     if (DEBUG)
110                     {
111                         debug(clazz, method, offset, constantInstruction, replacementInstruction);
112                     }
113                 }
114             }
115
116             // Is the method private, or an instance initializer?
117
else if ((referencedMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_PRIVATE) != 0 ||
118                      referencedMethod.getName(referencedMethodClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
119             {
120                 // But is it not a special invocation?
121
if (opcode != InstructionConstants.OP_INVOKESPECIAL)
122                 {
123                     // Replace the invocation by an invokespecial instruction.
124
Instruction replacementInstruction =
125                         new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL,
126                                                 constantIndex).shrink();
127
128                     codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
129
130                     if (DEBUG)
131                     {
132                         debug(clazz, method, offset, constantInstruction, replacementInstruction);
133                     }
134                 }
135             }
136
137             // Is the method an interface method?
138
else if ((referencedClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0)
139             {
140                 int invokeinterfaceConstant =
141                     (ClassUtil.internalMethodParameterSize(referencedMethod.getDescriptor(referencedMethodClass)) + 1) << 8;
142
143                 // But is it not an interface invocation, or is the parameter
144
// size incorrect?
145
if (opcode != InstructionConstants.OP_INVOKEINTERFACE ||
146                     constantInstruction.constant != invokeinterfaceConstant)
147                 {
148                     // Fix the parameter size of the interface invocation.
149
Instruction replacementInstruction =
150                         new ConstantInstruction(InstructionConstants.OP_INVOKEINTERFACE,
151                                                 constantIndex,
152                                                 invokeinterfaceConstant).shrink();
153
154                     codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
155
156                     if (DEBUG)
157                     {
158                         debug(clazz, method, offset, constantInstruction, replacementInstruction);
159                     }
160                 }
161             }
162
163             // The method is not static, private, an instance initializer, or
164
// an interface method.
165
else
166             {
167                 // But is it not a virtual invocation (or a special invocation,
168
// but not a super call)?
169
if (opcode != InstructionConstants.OP_INVOKEVIRTUAL &&
170                     (opcode != InstructionConstants.OP_INVOKESPECIAL ||
171                      !clazz.extends_(referencedClass)))
172                 {
173                     // Replace the invocation by an invokevirtual instruction.
174
Instruction replacementInstruction =
175                         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL,
176                                                 constantIndex).shrink();
177
178                     codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
179
180                     if (DEBUG)
181                     {
182                         debug(clazz, method, offset, constantInstruction, replacementInstruction);
183                     }
184                 }
185             }
186         }
187     }
188
189
190     // Implementations for ConstantVisitor.
191

192     public void visitAnyConstant(Clazz clazz, Constant constant) {}
193
194
195     public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
196     {
197         // Check if this is an interface method. Note that we're interested in
198
// the class of the method reference, not in the class in which the
199
// method was actually found.
200
//refConstant.referencedClassAccept(this);
201
clazz.constantPoolEntryAccept(refConstant.u2classIndex, this);
202
203         // Get the referenced access flags and names.
204
refConstant.referencedMemberAccept(this);
205     }
206
207
208     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
209     {
210         // Check if this is an interface class.
211
classConstant.referencedClassAccept(this);
212     }
213
214
215     // Implementations for ClassVisitor.
216

217     public void visitAnyClass(Clazz clazz)
218     {
219         // Remember the referenced class.
220
referencedClass = clazz;
221     }
222
223
224     // Implementations for MemberVisitor.
225

226     public void visitAnyMember(Clazz clazz, Member member)
227     {
228         // Remember the referenced method.
229
referencedMethodClass = clazz;
230         referencedMethod = member;
231     }
232
233
234     // Small utility methods.
235

236     private void debug(Clazz clazz,
237                        Method method,
238                        int offset,
239                        ConstantInstruction constantInstruction,
240                        Instruction replacementInstruction)
241     {
242         System.out.println("MethodInvocationFixer:");
243         System.out.println(" Class = "+clazz.getName());
244         System.out.println(" Method = "+method.getName(clazz)+method.getDescriptor(clazz));
245         System.out.println(" Instruction = "+constantInstruction.toString(offset));
246         System.out.println(" -> Class = "+referencedClass);
247         System.out.println(" Method = "+referencedMethod);
248         if ((referencedClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0)
249         {
250             System.out.println(" Parameter size = "+(ClassUtil.internalMethodParameterSize(referencedMethod.getDescriptor(referencedMethodClass)+1)));
251         }
252         System.out.println(" Replacement instruction = "+replacementInstruction.toString(offset));
253     }
254 }
255
Popular Tags