Реализация операторов сравнения в байт-коде с использованием ASM - PullRequest
0 голосов
/ 09 февраля 2020

Я работаю над моим личным проектом, создающим простой язык, который компилируется в Java Байт-код. Я использую библиотеку ASM версии 7.3.1, но столкнулся с проблемой с фреймами, которую не могу понять.

На самом деле это два вопроса в одном. Я пытаюсь реализовать простые операторы сравнения, например >, <, >= et c. Эти операторы должны явно возвращать логический результат. Я не вижу способа реализовать это непосредственно в байт-коде, поэтому я использую FCMPG, чтобы сравнить два числа с плавающей точкой, которые уже находятся в стеке, а затем использую IFxx для pu sh либо 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 Ответ

1 голос
/ 09 февраля 2020

1) Да, это правильный способ сделать это. Я полагаю, что настоящий компилятор Java делает нечто очень похожее.

2) Вы получаете ошибку проверки, потому что забыли добавить переход в конец блока if. Если вы внимательно посмотрите на свой код, вы увидите, что когда переход не выполняется , выполняются обе ветви , и в результате вы получаете 0 и 1 в стеке, что приводит к ошибке проверки. Вам нужно добавить второй прыжок, чтобы в этом случае в стек помещалась только постоянная, которую вы sh. Это должно быть примерно так:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...