ASM:ClassReader 未调用 MethodVisitor 的方法

ASM: MethodVisitor's methods are not called by the ClassReader

我正在编写一个使用 ASM 5 执行字节码静态分析的小工具。我将我的输入 Java class 提供给触发自定义 ClassVisitor 事件的 ClassReader。如果满足某些条件,我的 ClassVisitor 将 visitMethod 覆盖为 return 我的自定义 MethodVisitor,如果不满足,则覆盖 null

问题是,ClassReader 从不调用 MethodVisitor 的方法;我用 NetBeans 调试了它,我看到访问者被正确地 returned(它不是 null)但是执行仍然没有进入 visitMethodInsn,即使有 are 我用于测试的 classes 中的方法说明。

以前用过ASM,但是第一次遇到这个问题

这是我的 MyClassVisitor.visitMethod 代码:

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    InvokeFinder visitor;
    if(condition.isMet()) {
        visitor = new InvokeFinder(api);
        visitor.doStuff();
    } else {
        visitor = null;
    }
    return visitor;
}

这里是InvokeFinder的代码,在执行过程中从不输入:

public class InvokeFinder extends MethodVisitor {

    public InvokeFinder(int api) {
        super(api);
    }

    void unrelatedMethod(String parameter) {
        doStuff(parameter);
    }

    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
        switch (opcode) {
            case Opcodes.INVOKEVIRTUAL:
            case Opcodes.INVOKESPECIAL:
            case Opcodes.INVOKEDYNAMIC:
                doSomething();
                break;
            case Opcodes.INVOKEINTERFACE:
                doSomethingElse();
                break;
            case Opcodes.INVOKESTATIC:
                doSomethingDifferentAgain();
                break;
            default: break;
        }
    }
}

最后这是我正在测试的class(这并不意味着永远执行,它的唯一目的是编译然后由我的工具分析):

public class MyTestClass{

  public MyTestClass(String s) {
    System.out.println( "Function Name" );
  }

  public static void main(String args[]) {
    CGraph g = new CGraph("entry");

    g.enterBF(new CGVisitor() {
        @Override
        public void nodeOperations(CGraph graph, CGraphNode currentNode) {
            System.out.println("20");
        }

        @Override
        public String getString() {
            throw new UnsupportedOperationException("No string can be returned from this anonymous implementation of CGVisitor.");
        }
    });

    a( 11 );
  }

  public static void a(int n) {
    b( n );
  }

  public static void b(int m) {
    int n;

    if (m >= 10)
      a( m-1 );
    else
      System.out.println(m);
  }
}

我仔细检查了上面的 visitMethod 方法总是被执行,return 是 InvokeFinder 的一个非空实例并且这个实例永远不会被执行;怎么可能在这些条件下 InvokeFinder.visitMethodInsn 永远不会被 ClassReader 调用,即使 MyTestClass 的某些方法中有调用指令(例如内部方法 a(int))?

编辑:进一步调试,我发现 ClassReader 调用默认 MethodVisitor.visitMethodInsn 而不是调用覆盖版本 InvokeFinder.visitMethodInsn。为什么会这样?

原来我更改了 ASM 的 API 版本并且 MethodVisitor.visitMethodInsn 的签名在版本 4 和 5 之间不同。动态绑定不再将其识别为覆盖方法。

我可以通过将缺少的参数添加到 InvokeFinder.visitMethodInsn 来解决这个问题,InvokeFinder.visitMethodInsn 现在的签名是

public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf)