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



我正在做一个个人项目,创建一个编译为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),但出现相同的错误。

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)

最新更新