1 21 package proguard.classfile.util; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.*; 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.util.ClassNameListMatcher; 31 32 47 public class DynamicClassReferenceInitializer 48 extends SimplifiedVisitor 49 implements InstructionVisitor, 50 ConstantVisitor, 51 AttributeVisitor 52 { 53 public static final int X = InstructionSequenceMatcher.X; 54 public static final int Y = InstructionSequenceMatcher.Y; 55 public static final int Z = InstructionSequenceMatcher.Z; 56 57 public static final int A = InstructionSequenceMatcher.A; 58 public static final int B = InstructionSequenceMatcher.B; 59 public static final int C = InstructionSequenceMatcher.C; 60 public static final int D = InstructionSequenceMatcher.D; 61 62 63 private Constant[] CLASS_FOR_NAME_CONSTANTS = new Constant[] 64 { 65 new MethodrefConstant(1, 2, null, null), 67 new ClassConstant(3, null), 68 new NameAndTypeConstant(4, 5), 69 new Utf8Constant(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS), 70 new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_FOR_NAME), 71 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_FOR_NAME), 72 73 new MethodrefConstant(1, 7, null, null), 75 new NameAndTypeConstant(8, 9), 76 new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_INSTANCE), 77 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_INSTANCE), 78 79 new MethodrefConstant(1, 11, null, null), 81 new NameAndTypeConstant(12, 13), 82 new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_COMPONENT_TYPE), 83 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_COMPONENT_TYPE), 84 }; 85 86 private Instruction[] CONSTANT_CLASS_FOR_NAME_INSTRUCTIONS = new Instruction[] 88 { 89 new ConstantInstruction(InstructionConstants.OP_LDC, X), 90 new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), 91 }; 92 93 private Instruction[] CLASS_FOR_NAME_CAST_INSTRUCTIONS = new Instruction[] 95 { 96 new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), 97 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 6), 98 new ConstantInstruction(InstructionConstants.OP_CHECKCAST, X), 99 }; 100 101 102 110 private Constant[] DOT_CLASS_JAVAC_CONSTANTS = new Constant[] 111 { 112 new MethodrefConstant(A, 1, null, null), 113 new NameAndTypeConstant(B, 2), 114 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC), 115 }; 116 117 private Instruction[] DOT_CLASS_JAVAC_INSTRUCTIONS = new Instruction[] 119 { 120 new ConstantInstruction(InstructionConstants.OP_LDC, X), 121 new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), 122 }; 123 124 125 133 private Constant[] DOT_CLASS_JIKES_CONSTANTS = new Constant[] 134 { 135 new MethodrefConstant(A, 1, null, null), 136 new NameAndTypeConstant(B, 2), 137 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES), 138 }; 139 140 private Instruction[] DOT_CLASS_JIKES_INSTRUCTIONS = new Instruction[] 142 { 143 new ConstantInstruction(InstructionConstants.OP_LDC, X), 144 new SimpleInstruction(InstructionConstants.OP_ICONST_0), 145 new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), 146 }; 147 148 private Instruction[] DOT_CLASS_JAVAC_IMPLEMENTATION_INSTRUCTIONS = new Instruction[] 150 { 151 new VariableInstruction(InstructionConstants.OP_ALOAD_0), 152 new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), 153 new SimpleInstruction(InstructionConstants.OP_ARETURN), 154 }; 155 156 private Instruction[] DOT_CLASS_JIKES_IMPLEMENTATION_INSTRUCTIONS = new Instruction[] 158 { 159 new VariableInstruction(InstructionConstants.OP_ALOAD_0), 160 new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), 161 new VariableInstruction(InstructionConstants.OP_ALOAD_1), 162 new BranchInstruction(InstructionConstants.OP_IFNE, +6), 163 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 10), 164 new SimpleInstruction(InstructionConstants.OP_ARETURN), 165 }; 166 167 private Instruction[] DOT_CLASS_JIKES_IMPLEMENTATION_INSTRUCTIONS2 = new Instruction[] 169 { 170 new VariableInstruction(InstructionConstants.OP_ALOAD_0), 171 new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), 172 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 10), 173 new SimpleInstruction(InstructionConstants.OP_ARETURN), 174 }; 175 176 177 private ClassPool programClassPool; 178 private ClassPool libraryClassPool; 179 private WarningPrinter notePrinter; 180 private ClassNameListMatcher noteExceptionMatcher; 181 182 183 private InstructionSequenceMatcher constantClassForNameMatcher = 184 new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, 185 CONSTANT_CLASS_FOR_NAME_INSTRUCTIONS); 186 187 private InstructionSequenceMatcher classForNameCastMatcher = 188 new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, 189 CLASS_FOR_NAME_CAST_INSTRUCTIONS); 190 191 private InstructionSequenceMatcher dotClassJavacMatcher = 192 new InstructionSequenceMatcher(DOT_CLASS_JAVAC_CONSTANTS, 193 DOT_CLASS_JAVAC_INSTRUCTIONS); 194 195 private InstructionSequenceMatcher dotClassJikesMatcher = 196 new InstructionSequenceMatcher(DOT_CLASS_JIKES_CONSTANTS, 197 DOT_CLASS_JIKES_INSTRUCTIONS); 198 199 private InstructionSequenceMatcher dotClassJavacImplementationMatcher = 200 new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, 201 DOT_CLASS_JAVAC_IMPLEMENTATION_INSTRUCTIONS); 202 203 private InstructionSequenceMatcher dotClassJikesImplementationMatcher = 204 new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, 205 DOT_CLASS_JIKES_IMPLEMENTATION_INSTRUCTIONS); 206 207 private InstructionSequenceMatcher dotClassJikesImplementationMatcher2 = 208 new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, 209 DOT_CLASS_JIKES_IMPLEMENTATION_INSTRUCTIONS2); 210 211 212 private boolean isClassForNameInvocation; 214 215 216 220 public DynamicClassReferenceInitializer(ClassPool programClassPool, 221 ClassPool libraryClassPool, 222 WarningPrinter notePrinter, 223 ClassNameListMatcher noteExceptionMatcher) 224 { 225 this.programClassPool = programClassPool; 226 this.libraryClassPool = libraryClassPool; 227 this.notePrinter = notePrinter; 228 this.noteExceptionMatcher = noteExceptionMatcher; 229 } 230 231 232 234 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) 235 { 236 instruction.accept(clazz, method, codeAttribute, offset, 238 constantClassForNameMatcher); 239 240 if (constantClassForNameMatcher.isMatching()) 242 { 243 clazz.constantPoolEntryAccept(constantClassForNameMatcher.matchedConstantIndex(X), this); 245 246 classForNameCastMatcher.reset(); 248 } 249 250 instruction.accept(clazz, method, codeAttribute, offset, 253 classForNameCastMatcher); 254 255 if (classForNameCastMatcher.isMatching()) 257 { 258 clazz.constantPoolEntryAccept(classForNameCastMatcher.matchedConstantIndex(X), this); 260 } 261 262 instruction.accept(clazz, method, codeAttribute, offset, 264 dotClassJavacMatcher); 265 266 if (dotClassJavacMatcher.isMatching() && 268 isDotClassMethodref(clazz, dotClassJavacMatcher.matchedConstantIndex(0))) 269 { 270 clazz.constantPoolEntryAccept(dotClassJavacMatcher.matchedConstantIndex(X), this); 272 } 273 274 instruction.accept(clazz, method, codeAttribute, offset, 276 dotClassJikesMatcher); 277 278 if (dotClassJikesMatcher.isMatching() && 280 isDotClassMethodref(clazz, dotClassJikesMatcher.matchedConstantIndex(0))) 281 { 282 clazz.constantPoolEntryAccept(dotClassJikesMatcher.matchedConstantIndex(X), this); 284 } 285 } 286 287 288 290 293 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 294 { 295 String externalClassName = stringConstant.getString(clazz); 297 String internalClassName = ClassUtil.internalClassName(externalClassName); 298 299 stringConstant.referencedClass = findClass(internalClassName); 300 } 301 302 303 306 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 307 { 308 if (notePrinter != null && 310 (noteExceptionMatcher == null || 311 !noteExceptionMatcher.matches(classConstant.getName(clazz)))) 312 { 313 notePrinter.print("Note: " + 314 ClassUtil.externalClassName(clazz.getName()) + 315 " calls '(" + 316 ClassUtil.externalClassName(classConstant.getName(clazz)) + 317 ")Class.forName(variable).newInstance()'"); 318 } 319 } 320 321 322 325 public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) 326 { 327 String methodType = methodrefConstant.getType(clazz); 328 329 if (methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC) || 331 methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES)) 332 { 333 String methodName = methodrefConstant.getName(clazz); 334 335 isClassForNameInvocation = 337 methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_DOT_CLASS_JAVAC) || 338 methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_DOT_CLASS_JIKES); 339 340 if (isClassForNameInvocation) 341 { 342 return; 343 } 344 345 String className = methodrefConstant.getClassName(clazz); 346 347 Clazz referencedClass = programClassPool.getClass(className); 350 if (referencedClass != null) 351 { 352 referencedClass.methodAccept(methodName, 356 methodType, 357 new AllAttributeVisitor(this)); 358 } 359 } 360 } 361 362 363 365 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 366 367 368 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 369 { 370 isClassForNameInvocation = 374 isDotClassMethodCode(clazz, method, codeAttribute, 375 dotClassJavacImplementationMatcher, 5) || 376 isDotClassMethodCode(clazz, method, codeAttribute, 377 dotClassJikesImplementationMatcher, 12) || 378 isDotClassMethodCode(clazz, method, codeAttribute, 379 dotClassJikesImplementationMatcher2, 8); 380 } 381 382 383 385 389 private boolean isDotClassMethodref(Clazz clazz, int methodrefConstantIndex) 390 { 391 isClassForNameInvocation = false; 392 393 clazz.constantPoolEntryAccept(methodrefConstantIndex, this); 395 396 return isClassForNameInvocation; 397 } 398 399 400 404 private boolean isDotClassMethodCode(Clazz clazz, 405 Method method, 406 CodeAttribute codeAttribute, 407 InstructionSequenceMatcher codeMatcher, 408 int codeLength) 409 { 410 if (codeAttribute.u4codeLength < codeLength) 412 { 413 return false; 414 } 415 416 codeMatcher.reset(); 418 codeAttribute.instructionsAccept(clazz, method, 0, codeLength, codeMatcher); 419 return codeMatcher.isMatching(); 420 } 421 422 423 427 private Clazz findClass(String name) 428 { 429 Clazz clazz = programClassPool.getClass(name); 431 432 if (clazz == null) 434 { 435 clazz = libraryClassPool.getClass(name); 436 } 437 438 return clazz; 439 } 440 } 441 | Popular Tags |