java - 获取方法中当前解释的字节码指令的索引

标签 java bytecode java-bytecode-asm

我想在访问某个字节码时获取该方法中该字节码的索引号。例如,给定下面的字节码序列,invokevirtual 的索引号为 7(使用 SKIP_DEBUG 访问方法体)。

public calculate(IILjava/lang/String;J)J
   L0
    LINENUMBER 17 L0
    ICONST_3  //0 
    ISTORE 6  //1
   L1
    LINENUMBER 18 L1
    LDC 10.0  //2
    DSTORE 7  //3
   L2
    LINENUMBER 19 L2
    ALOAD 0  //4
    GETFIELD code/sxu/asm/Callee._call2 : Lcode/sxu/asm/Callee2; //5
    LDC "xushijie"  //6
    INVOKEVIRTUAL code/sxu/asm/Callee2.sayHello (Ljava/lang/String;)I  //7
    ISTORE 9

}

我的代码是这样的:

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);

    cr.accept(new SomeMethodVisitor(api, owner, access, name,   desc, cw.visitMethod(access, name, desc, owner, null)), SKIP_DEBUG);

class SomeMethodVisitor extends MethodVisitor{
            @Override
            public void visitMethodInsn(final int opcode, final String owner,
                    final String name, final String desc, final boolean itf) {
                int index = ???  //Get the current  bytecode index number here.
                super.visitMethodInsn(opcode, owner, name, desc, itf);
            }
}

使用基于树的 ASM API 相对容易,我们可以使用:

 class MethodNode{
     public InsnList instructions;
}

但是我在基于事件的模式中没有好的解决方案。另外,重写 MethodVisitor 的所有 visitXXX 方法并计算所有已经过去的字节码也不是一个好的解决方案。

最佳答案

这实际上对于 ASM 来说非常棘手,以至于几乎值得使用 Javassist 来代替此功能。

MethodVisitor 有一个名为 CodeSizeEvaluator 的子类。如果您对其进行子类化,则可以获取字节码大小的运行总计(以及字节码的偏移量)。为什么是“有点”?

某些字节码操作的大小可能有所不同。例如,如果要将整数常量压入堆栈,可以使用一、二或三个字节的指令代码来完成此操作,具体取决于整数的大小。 ASM 拥有字节码的操作抽象。换句话说,对于该指令,它将维护一个节点,该节点表示“将一个整数压入值 X 的堆栈中”。 Classwriter 将决定如何在实际字节码中执行此操作。因此,CodeSizeEvaluator 并不真正知道该指令是 1、2 还是 3 个字节。这就是为什么它保持“最小值”或“最大值”。

您可以通过查看 X 的值并确定将使用哪个实际指令并选择“实际”大小来增强逻辑。有几种情况是很棘手的。这些是当你有表跳转(即 case 语句)时。这些被填充,以便它们与 4 字节边界对齐。了解对齐方式需要了解它们开始的字节码计数(您应该知道)。更难的是跳转和跳转。 Classwriter 通过插入带有长 goto 的代码来处理跳转偏移量超过 +/-32K 的情况。除非你正在做一些疯狂的事情,否则这种情况几乎永远不会发生。尽管如此,CodeSizeEvaluator 将允许分支最多使用 7 个字节。您可能必须假设一个典型情况并计算 3 个字节。

我希望这会有所帮助。

附注这是凭内存写的,所以我可能忘记了其他一些边缘情况。

关于java - 获取方法中当前解释的字节码指令的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31840994/

相关文章:

java - 如何调试内部错误?

java - 对象不是声明类的实例

java - 使用 JDB(或类似工具)调试 ASM 生成的字节码

java - Spring Boot fat jar 中出现 NoClassDefFoundError 但依赖项位于已编译的存档中,并且应用程序在 IDE 中运行良好

Java EE 的 CDI 没有按预期工作

java - 自动生成加特林场景

java - LocalVariableTable 中缺少什么?

java - ASM 4(Java 库)教程?

java - 如何在 JMenu 中激活 ActionEvent 以在框架上显示新面板?(基本)

java - 如何编译Java字节码字符串?