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 */ 21package proguard.evaluation; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.CodeAttribute; 25import proguard.classfile.constant.*; 26import proguard.classfile.constant.visitor.ConstantVisitor; 27import proguard.classfile.instruction.*; 28import proguard.classfile.util.*; 29import proguard.classfile.visitor.MemberVisitor; 30import 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 */ 39public class BasicInvocationUnit 40extends SimplifiedVisitor 41implements 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 */ 57 public BasicInvocationUnit(ValueFactory valueFactory) 58 { 59 this.valueFactory = valueFactory; 60 } 61 62 63 // Implementations for InvocationUnit. 64 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 132 public void exitMethod(Clazz clazz, Method method, Value returnValue) 133 { 134 setMethodReturnValue(clazz, method, returnValue); 135 } 136 137 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 345 public void visitProgramField(ProgramClass programClass, ProgramField programField) 346 { 347 returnTypeClass = programField.referencedClass; 348 } 349 350 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 361 public void visitLibraryField(LibraryClass programClass, LibraryField programField) 362 { 363 returnTypeClass = programField.referencedClass; 364 } 365 366 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