bytecode - 使用 ASM 在字节码中实现比较运算符
问题描述
我正在开发我的个人项目,创建一种编译为 Java 字节码的简单语言。我正在使用 ASM 库版本 7.3.1,但我遇到了一个我无法弄清楚的框架问题。
这实际上是两个问题合而为一。我正在尝试实现简单的比较运算符,例如,>
等。这些运算符显然应该返回一个布尔结果。我看不到直接在字节码中实现这一点的方法,所以我使用 using来比较已经在堆栈上的两个浮点数,然后根据我生成代码的运算符来将 a或压入堆栈.<
>=
FCMPG
IFxx
1
0
例如,这是我的代码>
:
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)
我知道这与框架有关,但我对框架的了解还不足以知道我做错了什么。我试过添加mv.visitFrame(F_SAME, 0, null, 0, null)
之后,visitLabel
但我得到了同样的错误。
解决方案
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)
推荐阅读
- r - 如何使用杂乱的数据列自动整理excel数据并导入R?
- react-native - 反应模块'YogaKit'的本机run-ios重新定义
- sql - 如果 column_date 未通过,如何在 postgres 中插入?
- c - 在扫描复数计算器的数字之前扫描运算符会出错,但在数字后扫描运算符时不会出错
- ruby-on-rails - 如果 Rails Runner 消失,为什么它不会重新连接到数据库?
- java - 如何使用 MVC 结构暂停
- microsoft-graph-api - 无法使用 Graph API 在 Microsoft Teams 中回复第三方导入的消息
- python - 限制 Wagtail Steamfield 中特定 DocumentChooserBlock() 块的文件类型
- c++ - SSH 会话不会通过 cpp reboot 命令终止,而是通过 CLI 命令重新启动
- deep-learning - COCO 上的 Darknet 预训练权重如何适应不同的输出大小(不同的类数)?