001: package org.drools.util.asm;
002:
003: import java.util.List;
004:
005: import org.drools.asm.AnnotationVisitor;
006: import org.drools.asm.Attribute;
007: import org.drools.asm.ClassReader;
008: import org.drools.asm.ClassVisitor;
009: import org.drools.asm.FieldVisitor;
010: import org.drools.asm.MethodVisitor;
011: import org.drools.asm.util.TraceMethodVisitor;
012:
013: /**
014: * The purpose of this utility it to check if 2 method implementations are equivalent, by comparing the bytecode.
015: * This essentual for node sharing where java semantics are involved.
016: * @author Michael Neale
017: */
018: public class MethodComparator {
019:
020: /**
021: * This actually does the comparing.
022: * Class1 and Class2 are class reader instances to the respective classes. method1 and method2 are looked up on the
023: * respective classes and their contents compared.
024: *
025: * This is a convenience method.
026: */
027: public boolean equivalent(final String method1,
028: final ClassReader class1, final String method2,
029: final ClassReader class2) {
030:
031: final List list1 = getMethodBytecode(method1, class1);
032: final List list2 = getMethodBytecode(method2, class2);
033:
034: return compareBytecode(list1, list2);
035: }
036:
037: /**
038: * This will return a series of bytecode instructions which can be used to compare one method with another.
039: * debug info like local var declarations and line numbers are ignored, so the focus is on the content.
040: */
041: public List getMethodBytecode(final String methodName,
042: final ClassReader classReader) {
043: final Tracer visit = new Tracer(methodName);
044: classReader.accept(visit, true);
045: final TraceMethodVisitor trace = visit.getTrace();
046: return trace.getText();
047: }
048:
049: /**
050: * This will return a series of bytecode instructions which can be used to compare one method with another.
051: * debug info like local var declarations and line numbers are ignored, so the focus is on the content.
052: */
053: public static List getMethodBytecode(final String methodName,
054: final byte[] bytes) {
055: final Tracer visit = new Tracer(methodName);
056: final ClassReader classReader = new ClassReader(bytes);
057: classReader.accept(visit, true);
058: final TraceMethodVisitor trace = visit.getTrace();
059: return trace.getText();
060: }
061:
062: /**
063: * Compares 2 bytecode listings.
064: * Returns true if they are identical.
065: */
066: public static boolean compareBytecode(final List b1, final List b2) {
067: if (b1.size() != b2.size()) {
068: return false;
069: }
070:
071: for (int i = 0; i < b1.size(); i++) {
072: if (!(b1.get(i).equals(b2.get(i)))) {
073: return false;
074:
075: }
076: }
077: return true;
078: }
079:
080: public static class Tracer implements ClassVisitor {
081:
082: private TraceMethodVisitor trace;
083: private String methodName;
084:
085: public Tracer(final String methodName) {
086: this .methodName = methodName;
087: }
088:
089: public void visit(final int version, final int access,
090: final String name, final String signature,
091: final String super Name, final String[] interfaces) {
092: }
093:
094: public AnnotationVisitor visitAnnotation(final String desc,
095: final boolean visible) {
096: return new DummyAnnotationVisitor();
097: }
098:
099: public void visitAttribute(final Attribute attr) {
100: }
101:
102: public void visitEnd() {
103: }
104:
105: public FieldVisitor visitField(final int access,
106: final String name, final String desc,
107: final String signature, final Object value) {
108: return null;
109: }
110:
111: public void visitInnerClass(final String name,
112: final String outerName, final String innerName,
113: final int access) {
114: }
115:
116: public MethodVisitor visitMethod(final int access,
117: final String name, final String desc,
118: final String signature, final String[] exceptions) {
119:
120: if (this .methodName.equals(name)) {
121: this .trace = new TraceMethodVisitor();
122: return this .trace;
123: }
124: return null;
125: }
126:
127: public void visitOuterClass(final String owner,
128: final String name, final String desc) {
129: }
130:
131: public void visitSource(final String source, final String debug) {
132: }
133:
134: public TraceMethodVisitor getTrace() {
135: return this .trace;
136: }
137:
138: }
139:
140: static class DummyAnnotationVisitor implements AnnotationVisitor {
141:
142: public void visit(final String name, final Object value) {
143: }
144:
145: public AnnotationVisitor visitAnnotation(final String name,
146: final String desc) {
147: return new DummyAnnotationVisitor();
148: }
149:
150: public AnnotationVisitor visitArray(final String name) {
151: return new DummyAnnotationVisitor();
152: }
153:
154: public void visitEnd() {
155: }
156:
157: public void visitEnum(final String name, final String desc,
158: final String value) {
159: }
160:
161: }
162:
163: }
|