【问题标题】:Implementing comparison operators in Bytecode using ASM使用 ASM 在字节码中实现比较运算符
【发布时间】:2020-02-09 14:38:37
【问题描述】:

我正在从事我的个人项目,创建一种编译为 Java 字节码的简单语言。我使用的是 ASM 库版本 7.3.1,但我遇到了一个我无法弄清楚的框架问题。

这实际上是两个问题合二为一。我正在尝试实现简单的比较运算符,例如><>= 等这些运算符显然应该返回一个布尔结果。我看不到直接在字节码中实现这一点的方法,所以我使用FCMPG 比较已经在堆栈上的两个浮点数,然后使用IFxx10 推送到堆栈取决于我为哪个运算符生成代码。

例如,这是我的> 代码:

val label = new Label()
mv.visitInsn(FCMPG)           // mv is my MethodVisitor, there are 2 Floats on the stack
mv.visitJumpInsn(IFGT, label)
mv.visitInsn(ICONST_1)
mv.visitLabel(label)
mv.visitInsn(ICONST_0)

问题 1:这是实现比较运算符的正确方法还是我缺少更简单的方法?

问题 2:运行此代码会产生此错误:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
    at org.objectweb.asm.Frame.merge(Frame.java:1268)
    at org.objectweb.asm.Frame.merge(Frame.java:1244)
    at org.objectweb.asm.MethodWriter.computeAllFrames(MethodWriter.java:1610)
    at org.objectweb.asm.MethodWriter.visitMaxs(MethodWriter.java:1546)
    at compiler.codegen.default$$anon$1.generateConstructor(default.scala:138)
    at compiler.codegen.default$$anon$1.generateCode(default.scala:157)
    at compiler.codegen.default$$anon$1.generateCode(default.scala:21)
    at compiler.codegen.package$.generateCode(package.scala:21)
    at compiler.codegen.package$CodeGeneratorOp.generateCode(package.scala:17)
    at Main$.main(main.scala:27)
    at Main.main(main.scala)

我知道这与框架有关,但我对框架的了解还不足以知道我做错了什么。我试过在visitLabel 之后添加mv.visitFrame(F_SAME, 0, null, 0, null),但我得到了同样的错误。

【问题讨论】:

    标签: bytecode java-bytecode-asm jvm-bytecode


    【解决方案1】:

    1) 是的,这是正确的方法。我相信实际的 Java 编译器会做一些非常相似的事情。

    2) 您收到验证错误,因为您忘记在 if 块的末尾添加跳转。如果您仔细查看您的代码,您会发现当没有执行跳转时,两个 分支都被执行,最终堆栈中同时出现了 0 和 1,这会导致验证错误.您需要进行第二次跳转,以便在这种情况下只有您希望的常量被推送到堆栈中。应该是这样的:

    val then_label = new Label()
    val end_label = new Label()
    mv.visitInsn(FCMPG)           // mv is my MethodVisitor, there are 2 Floats on the stack
    mv.visitJumpInsn(IFGT, then_label)
    mv.visitInsn(ICONST_1)
    mv.visitGoto(end_label)
    mv.visitLabel(then_label)
    mv.visitInsn(ICONST_0)
    mv.visitLabel(end_label)
    

    【讨论】:

    • 就是这样!谢谢@Antimoney
    猜你喜欢
    • 1970-01-01
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 2017-10-06
    • 2018-05-27
    • 2012-10-05
    相关资源
    最近更新 更多