final MethodComparator comp = new MethodComparator(); boolean result = comp.equivalent( "evaluate", new ClassReader( getClassData( MethodCompareA.class ) ), "evaluate", new ClassReader( getClassData( MethodCompareB.class ) ) ); assertEquals( true, result ); new ClassReader( getClassData( MethodCompareA.class ) ), "evaluate2", new ClassReader( getClassData( MethodCompareA.class ) ) ); assertEquals( false, result ); new ClassReader( getClassData( MethodCompareB.class ) ), "evaluate2", new ClassReader( getClassData( MethodCompareA.class ) ) ); assertEquals( false, result ); new ClassReader( getClassData( MethodCompareB.class ) ), "evaluate", new ClassReader( getClassData( MethodCompareA.class ) ) ); assertEquals( true, result ); new ClassReader( getClassData( MethodCompareA.class ) ), "evaluate", new ClassReader( getClassData( MethodCompareA.class ) ) );
/** * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this * {@link ClassReader}. * * @param classVisitor the visitor that must visit this class. * @param parsingOptions the options to use to parse this class. One or more of {@link * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. */ public void accept(final ClassVisitor classVisitor, final int parsingOptions) { accept(classVisitor, new Attribute[0], parsingOptions); }
/** * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}). * * @return the internal names of the directly implemented interfaces. Inherited implemented * interfaces are not returned. * @see ClassVisitor#visit(int, int, String, String, String, String[]) */ public String[] getInterfaces() { // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each). int currentOffset = header + 6; int interfacesCount = readUnsignedShort(currentOffset); String[] interfaces = new String[interfacesCount]; if (interfacesCount > 0) { char[] charBuffer = new char[maxStringLength]; for (int i = 0; i < interfacesCount; ++i) { currentOffset += 2; interfaces[i] = readClass(currentOffset, charBuffer); } } return interfaces; }
/** * Read a stringish constant item (CONSTANT_Class, CONSTANT_String, * CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package * @param index * @param buf * @return */ private String readStringish(final int index, final char[] buf) { // computes the start index of the item in b // and reads the CONSTANT_Utf8 item designated by // the first two bytes of this item return readUTF8(items[readUnsignedShort(index)], buf); }
/** * Returns the start index of the attribute_info structure of this class. * * @return the start index of the attribute_info structure of this class. */ private int getAttributes() { // skips the header int u = header + 8 + readUnsignedShort(header + 6) * 2; // skips fields and methods for (int i = readUnsignedShort(u); i > 0; --i) { for (int j = readUnsignedShort(u + 8); j > 0; --j) { u += 6 + readInt(u + 12); } u += 8; } u += 2; for (int i = readUnsignedShort(u); i > 0; --i) { for (int j = readUnsignedShort(u + 8); j > 0; --j) { u += 6 + readInt(u + 12); } u += 8; } // the attribute_info structure starts just after the methods return u + 2; }
final int maxStack = readUnsignedShort(currentOffset); final int maxLocals = readUnsignedShort(currentOffset + 2); final int codeLength = readInt(currentOffset + 4); currentOffset += 8; case Constants.IFNULL: case Constants.IFNONNULL: createLabel(bytecodeOffset + readShort(currentOffset + 1), labels); currentOffset += 3; break; case Constants.ASM_IFNULL: case Constants.ASM_IFNONNULL: createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels); currentOffset += 3; break; case Constants.JSR_W: case Constants.ASM_GOTO_W: createLabel(bytecodeOffset + readInt(currentOffset + 1), labels); currentOffset += 5; break; createLabel(bytecodeOffset + readInt(currentOffset), labels); int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1; currentOffset += 12; createLabel(bytecodeOffset + readInt(currentOffset), labels); currentOffset += 4;
access = readUnsignedShort(u); name = readClass(u + 2, c); v = items[readUnsignedShort(u + 4)]; String superClassName = v == 0 ? null : readUTF8(v, c); String[] implementedItfs = new String[readUnsignedShort(u + 6)]; w = 0; u += 8; for (i = 0; i < implementedItfs.length; ++i) { implementedItfs[i] = readClass(u, c); u += 2; i = readUnsignedShort(v); v += 2; for (; i > 0; --i) { j = readUnsignedShort(v + 6); v += 8; for (; j > 0; --j) { v += 6 + readInt(v + 2); i = readUnsignedShort(v); v += 2; for (; i > 0; --i) { j = readUnsignedShort(v + 6); v += 8; for (; j > 0; --j) { v += 6 + readInt(v + 2); i = readUnsignedShort(v); v += 2;
int maxStack = readUnsignedShort(u); int maxLocals = readUnsignedShort(u + 2); int codeLength = readInt(u + 4); u += 8; int codeEnd = u + codeLength; Label[] labels = context.labels = new Label[codeLength + 2]; createLabel(codeLength + 1, labels); while (u < codeEnd) { int offset = u - codeStart; break; case ClassWriter.LABEL_INSN: createLabel(offset + readShort(u + 1), labels); u += 3; break; case ClassWriter.ASM_LABEL_INSN: createLabel(offset + readUnsignedShort(u + 1), labels); u += 3; break; case ClassWriter.LABELW_INSN: case ClassWriter.ASM_LABELW_INSN: createLabel(offset + readInt(u + 1), labels); u += 5; break; createLabel(offset + readInt(u), labels); for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { createLabel(offset + readInt(u + 12), labels);
/** * This will return a series of bytecode instructions which can be used to compare one method with another. * debug info like local var declarations and line numbers are ignored, so the focus is on the content. */ public static List getMethodBytecode(final String methodName, final byte[] bytes) { final Tracer visit = new Tracer( methodName ); final ClassReader classReader = new ClassReader( bytes ); classReader.accept( visit, ClassReader.SKIP_DEBUG ); final TraceMethodVisitor trace = visit.getTrace(); return trace.getText(); }
int access = readUnsignedShort(u); String name = readClass(u + 2, c); String superClass = readClass(u + 4, c); String[] interfaces = new String[readUnsignedShort(u + 6)]; u += 8; for (int i = 0; i < interfaces.length; ++i) { interfaces[i] = readClass(u, c); u += 2; u = getAttributes(); for (int i = readUnsignedShort(u); i > 0; --i) { String attrName = readUTF8(u + 2, c); sourceFile = readUTF8(u + 8, c); } else if ("InnerClasses".equals(attrName)) { innerClasses = u + 8; } else if ("EnclosingMethod".equals(attrName)) { enclosingOwner = readClass(u + 8, c); int item = readUnsignedShort(u + 10); if (item != 0) { enclosingName = readUTF8(items[item], c); enclosingDesc = readUTF8(items[item] + 2, c); signature = readUTF8(u + 8, c); } else if ("RuntimeVisibleAnnotations".equals(attrName)) { anns = u + 8; | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; } else if ("SourceDebugExtension".equals(attrName)) {
context.currentMethodAccessFlags = readUnsignedShort(currentOffset); context.currentMethodName = readUTF8(currentOffset + 2, charBuffer); context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer); currentOffset += 6; int attributesCount = readUnsignedShort(currentOffset); currentOffset += 2; while (attributesCount-- > 0) { String attributeName = readUTF8(currentOffset, charBuffer); int attributeLength = readInt(currentOffset + 2); currentOffset += 6; exceptions = new String[readUnsignedShort(exceptionsOffset)]; int currentExceptionOffset = exceptionsOffset + 2; for (int i = 0; i < exceptions.length; ++i) { exceptions[i] = readClass(currentExceptionOffset, charBuffer); currentExceptionOffset += 2; signatureIndex = readUnsignedShort(currentOffset); } else if (Constants.DEPRECATED.equals(attributeName)) { context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED; } else { Attribute attribute = readAttribute( context.attributePrototypes, attributeName,
context.access = readUnsignedShort(u); context.name = readUTF8(u + 2, c); context.desc = readUTF8(u + 4, c); u += 6; for (int i = readUnsignedShort(u); i > 0; --i) { String attrName = readUTF8(u + 2, c); exceptions = new String[readUnsignedShort(u + 8)]; exception = u + 10; for (int j = 0; j < exceptions.length; ++j) { exceptions[j] = readClass(exception, c); exception += 2; signature = readUTF8(u + 8, c); } else if ("Deprecated".equals(attrName)) { context.access |= Opcodes.ACC_DEPRECATED; methodParameters = u + 8; } else { Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); if (attr != null) { attr.next = attributes; u += 6 + readInt(u + 4); for (int j = exceptions.length - 1; j >= 0; --j) { exception -= 2;
int accessFlags = readUnsignedShort(currentOffset); String thisClass = readClass(currentOffset + 2, charBuffer); String superClass = readClass(currentOffset + 4, charBuffer); String[] interfaces = new String[readUnsignedShort(currentOffset + 6)]; currentOffset += 8; for (int i = 0; i < interfaces.length; ++i) { interfaces[i] = readClass(currentOffset, charBuffer); currentOffset += 2; int currentAttributeOffset = getFirstAttributeOffset(); for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { String attributeName = readUTF8(currentAttributeOffset, charBuffer); int attributeLength = readInt(currentAttributeOffset + 2); currentAttributeOffset += 6; sourceFile = readUTF8(currentAttributeOffset, charBuffer); } else if (Constants.INNER_CLASSES.equals(attributeName)) { innerClassesOffset = currentAttributeOffset; enclosingMethodOffset = currentAttributeOffset; } else if (Constants.NEST_HOST.equals(attributeName)) { nestHostClass = readClass(currentAttributeOffset, charBuffer); } else if (Constants.NEST_MEMBERS.equals(attributeName)) { nestMembersOffset = currentAttributeOffset; } else if (Constants.SIGNATURE.equals(attributeName)) { signature = readUTF8(currentAttributeOffset, charBuffer); } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { runtimeVisibleAnnotationsOffset = currentAttributeOffset;
int constantPoolOffset = classReader.getItem(1) - 1; int constantPoolLength = classReader.header - constantPoolOffset; constantPoolCount = classReader.getItemCount(); constantPool = new ByteVector(constantPoolLength); constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength); char[] charBuffer = new char[classReader.getMaxStringLength()]; boolean hasBootstrapMethods = false; int itemIndex = 1; while (itemIndex < constantPoolCount) { int itemOffset = classReader.getItem(itemIndex); int itemTag = inputBytes[itemOffset - 1]; int nameAndTypeItemOffset; case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: nameAndTypeItemOffset = classReader.getItem(classReader.readUnsignedShort(itemOffset + 2)); addConstantMemberReference( itemIndex, itemTag, classReader.readClass(itemOffset, charBuffer), classReader.readUTF8(nameAndTypeItemOffset, charBuffer), classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer)); break; case Symbol.CONSTANT_INTEGER_TAG: case Symbol.CONSTANT_FLOAT_TAG: addConstantIntegerOrFloat(itemIndex, itemTag, classReader.readInt(itemOffset)); break; case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
switch (b[cpInfoOffset - 1]) { case Symbol.CONSTANT_INTEGER_TAG: return readInt(cpInfoOffset); case Symbol.CONSTANT_FLOAT_TAG: return Float.intBitsToFloat(readInt(cpInfoOffset)); case Symbol.CONSTANT_LONG_TAG: return readLong(cpInfoOffset); case Symbol.CONSTANT_DOUBLE_TAG: return Double.longBitsToDouble(readLong(cpInfoOffset)); case Symbol.CONSTANT_CLASS_TAG: return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer)); case Symbol.CONSTANT_STRING_TAG: return readUTF8(cpInfoOffset, charBuffer); case Symbol.CONSTANT_METHOD_TYPE_TAG: return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer)); case Symbol.CONSTANT_METHOD_HANDLE_TAG: int referenceKind = readByte(cpInfoOffset); int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)]; int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)]; String owner = readClass(referenceCpInfoOffset, charBuffer); String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); boolean isInterface = b[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; return new Handle(referenceKind, owner, name, descriptor, isInterface); case Symbol.CONSTANT_DYNAMIC_TAG: return readConstantDynamic(constantPoolEntryIndex, charBuffer); default: throw new IllegalArgumentException();
case ClassWriter.METH: case ClassWriter.IMETH: nameType = items[readUnsignedShort(index + 2)]; item.set(tag, readClass(index, buf), readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); break; case ClassWriter.INT: item.set(readInt(index)); break; case ClassWriter.FLOAT: item.set(Float.intBitsToFloat(readInt(index))); break; case ClassWriter.NAME_TYPE: item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), null); break; case ClassWriter.LONG: item.set(readLong(index)); ++i; break; case ClassWriter.DOUBLE: item.set(Double.longBitsToDouble(readLong(index))); ++i; break; if (s == null) { index = items[i]; s = strings[i] = readUTF(index + 2, readUnsignedShort(index), buf);
return v + 5; case '@': // annotation_value return readAnnotationValues(v + 3, buf, true, null); case '[': // array_value return readAnnotationValues(v + 1, buf, false, null); default: return v + 3; case 'F': // pointer to CONSTANT_Float case 'D': // pointer to CONSTANT_Double av.visit(name, readConst(readUnsignedShort(v), buf)); v += 2; break; case 'B': // pointer to CONSTANT_Byte av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'Z': // pointer to CONSTANT_Boolean av.visit(name, readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE : Boolean.TRUE); v += 2; break; case 'S': // pointer to CONSTANT_Short av.visit(name, (short) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'C': // pointer to CONSTANT_Char av.visit(name, (char) readInt(items[readUnsignedShort(v)]));
int access = readUnsignedShort(u); String name = readUTF8(u + 2, c); String desc = readUTF8(u + 4, c); u += 6; for (int i = readUnsignedShort(u); i > 0; --i) { String attrName = readUTF8(u + 2, c); int item = readUnsignedShort(u + 8); value = item == 0 ? null : readConst(item, c); } else if ("Signature".equals(attrName)) { signature = readUTF8(u + 8, c); } else if ("Deprecated".equals(attrName)) { access |= Opcodes.ACC_DEPRECATED; itanns = u + 8; } else { Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); if (attr != null) { attr.next = attributes; u += 6 + readInt(u + 4); for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), true)); for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
int accessFlags = readUnsignedShort(currentOffset); String name = readUTF8(currentOffset + 2, charBuffer); String descriptor = readUTF8(currentOffset + 4, charBuffer); currentOffset += 6; int attributesCount = readUnsignedShort(currentOffset); currentOffset += 2; while (attributesCount-- > 0) { String attributeName = readUTF8(currentOffset, charBuffer); int attributeLength = readInt(currentOffset + 2); currentOffset += 6; int constantvalueIndex = readUnsignedShort(currentOffset); constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer); } else if (Constants.SIGNATURE.equals(attributeName)) { signature = readUTF8(currentOffset, charBuffer); } else if (Constants.DEPRECATED.equals(attributeName)) { accessFlags |= Opcodes.ACC_DEPRECATED; } else { Attribute attribute = readAttribute( context.attributePrototypes, attributeName, int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; while (numAnnotations-- > 0) {
case ClassWriter.METH: case ClassWriter.IMETH: nameType = items[readUnsignedShort(index + 2)]; item.set(tag, readClass(index, buf), readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); break; item.set(readInt(index)); break; item.set(Float.intBitsToFloat(readInt(index))); break; readUTF8(index, buf), readUTF8(index + 2, buf), null); break; item.set(readLong(index)); ++i; break; item.set(Double.longBitsToDouble(readLong(index))); ++i; break; if (s == null) {