• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2009 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.evaluation;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.CodeAttribute;
25 import proguard.classfile.constant.*;
26 import proguard.classfile.constant.visitor.ConstantVisitor;
27 import proguard.classfile.instruction.*;
28 import proguard.classfile.util.*;
29 import proguard.classfile.visitor.MemberVisitor;
30 import proguard.evaluation.value.*;
31 
32 /**
33  * This InvocationUnit sets up the variables for entering a method,
34  * and it updates the stack for the invocation of a class member,
35  * using simple values.
36  *
37  * @author Eric Lafortune
38  */
39 public class BasicInvocationUnit
40 extends      SimplifiedVisitor
41 implements   InvocationUnit,
42              ConstantVisitor,
43              MemberVisitor
44 {
45     protected final ValueFactory valueFactory;
46 
47     // Fields acting as parameters between the visitor methods.
48     private boolean isStatic;
49     private boolean isLoad;
50     private Stack   stack;
51     private Clazz   returnTypeClass;
52 
53 
54     /**
55      * Creates a new BasicInvocationUnit with the given value factory.
56      */
BasicInvocationUnit(ValueFactory valueFactory)57     public BasicInvocationUnit(ValueFactory valueFactory)
58     {
59         this.valueFactory = valueFactory;
60     }
61 
62 
63     // Implementations for InvocationUnit.
64 
enterMethod(Clazz clazz, Method method, Variables variables)65     public void enterMethod(Clazz clazz, Method method, Variables variables)
66     {
67         String descriptor = method.getDescriptor(clazz);
68 
69         // Initialize the parameters.
70         boolean isStatic =
71             (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0;
72 
73         // Count the number of parameters, taking into account their categories.
74         int parameterSize = ClassUtil.internalMethodParameterSize(descriptor, isStatic);
75 
76         // Reuse the existing parameters object, ensuring the right size.
77         variables.reset(parameterSize);
78 
79         // Go over the parameters again.
80         InternalTypeEnumeration internalTypeEnumeration =
81             new InternalTypeEnumeration(descriptor);
82 
83         int parameterIndex = 0;
84         int variableIndex  = 0;
85 
86         // Put the 'this' reference in variable 0.
87         if (!isStatic)
88         {
89             // Get the reference value.
90             Value value = getMethodParameterValue(clazz,
91                                                   method,
92                                                   parameterIndex++,
93                                                   ClassUtil.internalTypeFromClassName(clazz.getName()),
94                                                   clazz);
95 
96             // Store the value in variable 0.
97             variables.store(variableIndex++, value);
98         }
99 
100         Clazz[] referencedClasses = ((ProgramMethod)method).referencedClasses;
101         int referencedClassIndex = 0;
102 
103         // Set up the variables corresponding to the parameter types and values.
104         while (internalTypeEnumeration.hasMoreTypes())
105         {
106             String type = internalTypeEnumeration.nextType();
107 
108             Clazz referencedClass = referencedClasses != null &&
109                                     ClassUtil.isInternalClassType(type) ?
110                 referencedClasses[referencedClassIndex++] :
111                 null;
112 
113             // Get the parameter value.
114             Value value = getMethodParameterValue(clazz,
115                                                   method,
116                                                   parameterIndex++,
117                                                   type,
118                                                   referencedClass);
119 
120             // Store the value in the corresponding variable.
121             variables.store(variableIndex++, value);
122 
123             // Increment the variable index again for Category 2 values.
124             if (value.isCategory2())
125             {
126                 variableIndex++;
127             }
128         }
129     }
130 
131 
exitMethod(Clazz clazz, Method method, Value returnValue)132     public void exitMethod(Clazz clazz, Method method, Value returnValue)
133     {
134         setMethodReturnValue(clazz, method, returnValue);
135     }
136 
137 
invokeMember(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction, Stack stack)138     public void invokeMember(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction, Stack stack)
139     {
140         int constantIndex = constantInstruction.constantIndex;
141 
142         switch (constantInstruction.opcode)
143         {
144             case InstructionConstants.OP_GETSTATIC:
145                 isStatic = true;
146                 isLoad   = true;
147                 break;
148 
149             case InstructionConstants.OP_PUTSTATIC:
150                 isStatic = true;
151                 isLoad   = false;
152                 break;
153 
154             case InstructionConstants.OP_GETFIELD:
155                 isStatic = false;
156                 isLoad   = true;
157                 break;
158 
159             case InstructionConstants.OP_PUTFIELD:
160                 isStatic = false;
161                 isLoad   = false;
162                 break;
163 
164             case InstructionConstants.OP_INVOKESTATIC:
165                 isStatic = true;
166                 break;
167 
168             case InstructionConstants.OP_INVOKEVIRTUAL:
169             case InstructionConstants.OP_INVOKESPECIAL:
170             case InstructionConstants.OP_INVOKEINTERFACE:
171                 isStatic = false;
172                 break;
173         }
174 
175         // Pop the parameters and push the return value.
176         this.stack = stack;
177         clazz.constantPoolEntryAccept(constantIndex, this);
178         this.stack = null;
179     }
180 
181 
182     // Implementations for ConstantVisitor.
183 
visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)184     public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
185     {
186         // Pop the field value, if applicable.
187         if (!isLoad)
188         {
189             setFieldValue(clazz, fieldrefConstant, stack.pop());
190         }
191 
192         // Pop the reference value, if applicable.
193         if (!isStatic)
194         {
195             setFieldClassValue(clazz, fieldrefConstant, stack.apop());
196         }
197 
198         // Push the field value, if applicable.
199         if (isLoad)
200         {
201             String type = fieldrefConstant.getType(clazz);
202 
203             stack.push(getFieldValue(clazz, fieldrefConstant, type));
204         }
205     }
206 
207 
visitAnyMethodrefConstant(Clazz clazz, RefConstant methodrefConstant)208     public void visitAnyMethodrefConstant(Clazz clazz, RefConstant methodrefConstant)
209     {
210         String type = methodrefConstant.getType(clazz);
211 
212         // Count the number of parameters.
213         int parameterCount = ClassUtil.internalMethodParameterCount(type);
214         if (!isStatic)
215         {
216             parameterCount++;
217         }
218 
219         // Pop the parameters and the class reference, in reverse order.
220         for (int parameterIndex = parameterCount-1; parameterIndex >= 0; parameterIndex--)
221         {
222             setMethodParameterValue(clazz, methodrefConstant, parameterIndex, stack.pop());
223         }
224 
225         // Push the return value, if applicable.
226         String returnType = ClassUtil.internalMethodReturnType(type);
227         if (returnType.charAt(0) != ClassConstants.INTERNAL_TYPE_VOID)
228         {
229             stack.push(getMethodReturnValue(clazz, methodrefConstant, returnType));
230         }
231     }
232 
233 
234     /**
235      * Sets the class through which the specified field is accessed.
236      */
setFieldClassValue(Clazz clazz, RefConstant refConstant, ReferenceValue value)237     protected void setFieldClassValue(Clazz          clazz,
238                                       RefConstant    refConstant,
239                                       ReferenceValue value)
240     {
241         // We don't care about the new value.
242     }
243 
244 
245     /**
246      * Returns the class though which the specified field is accessed.
247      */
getFieldClassValue(Clazz clazz, RefConstant refConstant, String type)248     protected Value getFieldClassValue(Clazz       clazz,
249                                        RefConstant refConstant,
250                                        String      type)
251     {
252         // Try to figure out the class of the return type.
253         returnTypeClass = null;
254         refConstant.referencedMemberAccept(this);
255 
256         return valueFactory.createValue(type,
257                                         returnTypeClass,
258                                         true);
259     }
260 
261 
262     /**
263      * Sets the value of the specified field.
264      */
setFieldValue(Clazz clazz, RefConstant refConstant, Value value)265     protected void setFieldValue(Clazz       clazz,
266                                  RefConstant refConstant,
267                                  Value       value)
268     {
269         // We don't care about the new field value.
270     }
271 
272 
273     /**
274      * Returns the value of the specified field.
275      */
getFieldValue(Clazz clazz, RefConstant refConstant, String type)276     protected Value getFieldValue(Clazz       clazz,
277                                   RefConstant refConstant,
278                                   String      type)
279     {
280         // Try to figure out the class of the return type.
281         returnTypeClass = null;
282         refConstant.referencedMemberAccept(this);
283 
284         return valueFactory.createValue(type,
285                                         returnTypeClass,
286                                         true);
287     }
288 
289 
290     /**
291      * Sets the value of the specified method parameter.
292      */
setMethodParameterValue(Clazz clazz, RefConstant refConstant, int parameterIndex, Value value)293     protected void setMethodParameterValue(Clazz       clazz,
294                                            RefConstant refConstant,
295                                            int         parameterIndex,
296                                            Value       value)
297     {
298         // We don't care about the parameter value.
299     }
300 
301 
302     /**
303      * Returns the value of the specified method parameter.
304      */
getMethodParameterValue(Clazz clazz, Method method, int parameterIndex, String type, Clazz referencedClass)305     protected Value getMethodParameterValue(Clazz  clazz,
306                                             Method method,
307                                             int    parameterIndex,
308                                             String type,
309                                             Clazz  referencedClass)
310     {
311         return valueFactory.createValue(type, referencedClass, true);
312     }
313 
314 
315     /**
316      * Sets the return value of the specified method.
317      */
setMethodReturnValue(Clazz clazz, Method method, Value value)318     protected void setMethodReturnValue(Clazz  clazz,
319                                         Method method,
320                                         Value  value)
321     {
322         // We don't care about the return value.
323     }
324 
325 
326     /**
327      * Returns the return value of the specified method.
328      */
getMethodReturnValue(Clazz clazz, RefConstant refConstant, String type)329     protected Value getMethodReturnValue(Clazz       clazz,
330                                          RefConstant refConstant,
331                                          String      type)
332     {
333         // Try to figure out the class of the return type.
334         returnTypeClass = null;
335         refConstant.referencedMemberAccept(this);
336 
337         return valueFactory.createValue(type,
338                                         returnTypeClass,
339                                         true);
340     }
341 
342 
343     // Implementations for MemberVisitor.
344 
visitProgramField(ProgramClass programClass, ProgramField programField)345     public void visitProgramField(ProgramClass programClass, ProgramField programField)
346     {
347         returnTypeClass = programField.referencedClass;
348     }
349 
350 
visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)351     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
352     {
353         Clazz[] referencedClasses = programMethod.referencedClasses;
354         if (referencedClasses != null)
355         {
356             returnTypeClass = referencedClasses[referencedClasses.length - 1];
357         }
358     }
359 
360 
visitLibraryField(LibraryClass programClass, LibraryField programField)361     public void visitLibraryField(LibraryClass programClass, LibraryField programField)
362     {
363         returnTypeClass = programField.referencedClass;
364     }
365 
366 
visitLibraryMethod(LibraryClass programClass, LibraryMethod programMethod)367     public void visitLibraryMethod(LibraryClass programClass, LibraryMethod programMethod)
368     {
369         Clazz[] referencedClasses = programMethod.referencedClasses;
370         if (referencedClasses != null)
371         {
372             returnTypeClass = referencedClasses[referencedClasses.length - 1];
373         }
374     }
375 
376 
377 //    public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember)
378 //    {
379 //    }
380 }
381