📄 classfilereferenceinitializer.java
字号:
public void visitInstruction(ClassFile classFile, Instruction instruction) { // Just ignore generic instructions and reset the constant pool indices. switch (instruction.getOpcode()) { case Instruction.OP_ICONST_0: case Instruction.OP_ICONST_1: // Still remember any loaded string; it might be the argument of // class$(String, boolean). break; default: ldcStringCpIndex = -1; break; } invokestaticMethodRefCpIndex = -1; invokevirtualMethodRefCpIndex = -1; } public void visitCpInstruction(ClassFile classFile, CpInstruction cpInstruction) { int currentCpIndex = cpInstruction.getCpIndex(); switch (cpInstruction.getOpcode()) { case Instruction.OP_LDC: case Instruction.OP_LDC_WIDE: // Are we loading a constant String? int currentCpTag = classFile.getCpTag(currentCpIndex); if (currentCpTag == ClassConstants.CONSTANT_String) { // Remember it; it might be the argument of // Class.forName(String), class$(String), or // class$(String, boolean). ldcStringCpIndex = currentCpIndex; } invokestaticMethodRefCpIndex = -1; invokevirtualMethodRefCpIndex = -1; break; case Instruction.OP_INVOKESTATIC: // Are we invoking a static method that might have a constant // String argument? if (ldcStringCpIndex > 0) { classForNameFinder.reset(); // First check whether the method reference points to Class.forName. classFile.constantPoolEntryAccept(classForNameFinder, currentCpIndex); // Then fill out the class file reference in the String, if applicable. classFile.constantPoolEntryAccept(classForNameFinder, ldcStringCpIndex); invokestaticMethodRefCpIndex = -1; } else { // Just remember it; it might still be a Class.forName. invokestaticMethodRefCpIndex = currentCpIndex; } ldcStringCpIndex = -1; invokevirtualMethodRefCpIndex = -1; break; case Instruction.OP_INVOKEVIRTUAL: // Are we invoking a virtual method right after a static method? if (invokestaticMethodRefCpIndex > 0) { // Remember it; it might be Class.newInstance after a Class.forName. invokevirtualMethodRefCpIndex = currentCpIndex; } else { invokestaticMethodRefCpIndex = -1; invokevirtualMethodRefCpIndex = -1; } ldcStringCpIndex = -1; break; case Instruction.OP_CHECKCAST: // Are we checking a cast right after a static method and a // virtual method? if (invokestaticMethodRefCpIndex > 0 && invokevirtualMethodRefCpIndex > 0) { classForNameFinder.reset(); // First check whether the first method reference points to Class.forName. classFile.constantPoolEntryAccept(classForNameFinder, invokestaticMethodRefCpIndex); // Then check whether the second method reference points to Class.newInstance. classFile.constantPoolEntryAccept(classForNameFinder, invokevirtualMethodRefCpIndex); // Then figure out which class is being cast to. classFile.constantPoolEntryAccept(classForNameFinder, currentCpIndex); } ldcStringCpIndex = -1; invokestaticMethodRefCpIndex = -1; invokevirtualMethodRefCpIndex = -1; break; default: // Nothing interesting; just forget about previous indices. ldcStringCpIndex = -1; invokestaticMethodRefCpIndex = -1; invokevirtualMethodRefCpIndex = -1; break; } } /** * This CpInfoVisitor is designed to visit one or two method references first, * and then a string or a class reference. * If the method reference is Class.forName or .class, the class file * reference of the string is filled out. * If the method reference is Class.forName and then Class.newInstance, * a note of it is printed. */ private class MyClassForNameFinder implements CpInfoVisitor { private boolean isClassForNameInvocation; private boolean isDotClassInvocation; private boolean isClassForNameInstanceInvocation; public void reset() { isClassForNameInvocation = false; isDotClassInvocation = false; isClassForNameInstanceInvocation = false; } public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {} public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {} public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {} public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {} public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {} public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {} public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {} public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {} public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) { String className = methodrefCpInfo.getClassName(classFile); String methodName = methodrefCpInfo.getName(classFile); String methodType = methodrefCpInfo.getType(classFile); // Is it a reference to Class.newInstance, following a reference to // Class.forName? isClassForNameInstanceInvocation = isClassForNameInvocation && className .equals(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS) && methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_NEW_INSTANCE) && methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_NEW_INSTANCE); // Is it a reference to Class.forName? isClassForNameInvocation = className .equals(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS) && methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_CLASS_FOR_NAME) && methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_FOR_NAME); // Is it a reference to .class? // Note that .class is implemented as "static Class class$(String)" // or as "static Class class$(String, boolean)". isDotClassInvocation = methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_DOT_CLASS) && (methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC) || methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES)); } public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) { if (isClassForNameInvocation || isDotClassInvocation) { // Save a reference to the corresponding class file. String externalClassName = stringCpInfo.getString(classFile); String internalClassName = ClassUtil.internalClassName(externalClassName); stringCpInfo.referencedClassFile = programClassPool.getClass(internalClassName); } } public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) { if (isClassForNameInstanceInvocation) { if (note) { noteCount++; System.err.println("Note: " + ClassUtil.externalClassName(classFile.getName()) + " calls '(" + ClassUtil.externalClassName(classCpInfo.getName(classFile)) + ")Class.forName(variable).newInstance()'"); } } } } // Small utility methods. /** * Returns an array of class files referenced by the given descriptor, or * <code>null</code> if there aren't any useful references. */ private ClassFile[] findReferencedClassFiles(String aDescriptor) { DescriptorClassEnumeration enumeration = new DescriptorClassEnumeration(aDescriptor); int classCount = enumeration.classCount(); if (classCount > 0) { ClassFile[] referencedClassFiles = new ClassFile[classCount]; boolean foundReferencedClassFiles = false; for (int i = 0; i < classCount; i++) { String name = enumeration.nextClassName(); ClassFile referencedClassFile = programClassPool.getClass(name); if (referencedClassFile != null) { referencedClassFiles[i] = referencedClassFile; foundReferencedClassFiles = true; } } if (foundReferencedClassFiles) { return referencedClassFiles; } } return null; } /** * A utility class that throws a MemberFoundException whenever it visits * a member. For program class files, it then also stores the class file * and member info. */ private static class MyMemberFinder implements MemberInfoVisitor { private static class MemberFoundException extends IllegalArgumentException {}; private static final MemberFoundException MEMBER_FOUND = new MemberFoundException(); private ProgramClassFile programClassFile; private ProgramMemberInfo programMemberInfo; // Implementations for MemberInfoVisitor public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) { this.programClassFile = programClassFile; this.programMemberInfo = programFieldInfo; throw MEMBER_FOUND; } public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo) { this.programClassFile = programClassFile; this.programMemberInfo = programMethodInfo; throw MEMBER_FOUND; } public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) { throw MEMBER_FOUND; } public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) { throw MEMBER_FOUND; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -