使用ASM在字节码中实现比较运算符

问题描述 投票:0回答:1

我正在我的一个个人项目中,创建一种简单的语言,该语言被编译为Java字节码。我正在使用ASM库7.3.1版,但遇到了无法完全弄清楚的Frames问题。

这实际上是两个问题合而为一。我正在尝试实现简单的比较运算符,例如><>=等。这些运算符应该明显返回布尔结果。我看不到直接在字节码中实现此方法的方法,因此我正在使用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)

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

bytecode java-bytecode-asm jvm-bytecode
1个回答
1
投票

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

2)您收到验证错误,因为您忘记在if块的末尾添加跳转。如果仔细查看代码,您会发现当不执行跳转时,会执行both分支,并且堆栈中的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)
© www.soinside.com 2019 - 2024. All rights reserved.