ifeq / ifne JVM操作码总是分支

Bru*_*Kim 5 java jvm java-bytecode-asm whitespace-language

[TL; DR:以下JVM字节码指令似乎不起作用:

iconst_0
istore 6
...sequential
iinc 6 1
jsr L42
...
; L42
iload 6
ifeq L53 ; Always branches!!!
astore 8
iinc 6 -1
; L53
LDC 100
ISUB     ; ERROR, returnAddress is at the top of the stack
Run Code Online (Sandbox Code Playgroud)

可以在此处找到测试.class (具有稍微复杂的逻辑)。如果您想进一步了解为什么我会看到这些说明,请继续阅读。]

我正在编写针对JVM字节码的Whitespace编译器。尽管是一种深奥的语言,但是Whitespace向堆栈计算机描述了一组有趣的汇编指令,该堆栈计算机很好地映射到了JVM。

空格具有标签,它们都是跳转(goto / jump-if-zero / jump-if-negative)和函数调用的目标。相关说明(由我给定的名称,在规范中以空格,制表符和换行符的组合形式给出)为:

  • mark <label>:为以下说明设置标签
  • jump[-if-neg|-if-zero] <label>:无条件或有条件地跳转到给定标签
  • call <label>:调用标签所指向的函数
  • end <label>:结束功能,返回到调用方。

我的编译器以类的main方法输出整个Whitespace程序。实现call和的最简单方法end是使用JSRRET操作码,用于实现子例程。JSR操作完成后,堆栈将包含一个returnAddress引用,该引用应存储在变量中,以供以后在中使用end

但是,mark可以call-ed或jump-ed入栈,堆栈可以包含也可以不包含returnAddress引用。我决定使用一个布尔变量(地址为6的调用位)来存储标记的到达方式,然后测试它是否应将堆栈的顶部存储到局部变量中(地址为8的返回地址)。每条指令的实现如下:

; ... initialization
iconst_0
istore 6 ; local variable #6 holds the call bit

# call
iinc 6 1 ; sets the call bit
jsr Lxxx ; jumps to the given label, pushing a returnAddress to the stack

# mark
; Lxxx
iload 6       ; loads the call bit
ifeq Lxxx-end ; SHOULD jump to mark's end if the call bit is not set
; call bit is set: mark was call-ed and returnAddress is in the stack
astore 8      ; stores returnAddress to local variable #8
iinc 6 -1     ; resets the call bit
; Lxxx-end

# end
ret 8 ; returns using the stored returnAddress
Run Code Online (Sandbox Code Playgroud)

问题:ifeq总是分支。我还尝试反转逻辑(调用位->跳转位,ifeq-> ifne),甚至简单地切换到ifne(这是错误的)...但是if总是分支到最后。调用后,将returnAddress保留在堆栈中,然后执行下一个操作。

我已经使用ASM的分析器监视堆栈来调试所有这些内容,但是只是断言了这种行为,无法发现我在做什么错。我的一个怀疑是,要实现的目标iinc或目标还ifeq远没有我虚妄的哲学所能想象的。我承认我只阅读了该项目的指令集页面ASM的相关文档,但是我希望有人能够从头开始提出解决方案。

在此文件夹中,有相关的文件,包括可执行文件类和原始的空白,以及javap -cASM分析的输出。

Bru*_*Kim 1

找到了可能的原因:问题不在执行过程中,而是在验证器上。当它看起来“总是分支”时,实际上是验证者测试了所有可能的结果if,因此可以确保堆栈看起来是一样的。我的代码依赖于堆栈上可能存在也可能不存在的引用(returnAddress),并且验证程序无法检查它。

也就是说,示例代码不使用该-noverify标志运行,但验证失败的其他更简单的示例确实执行正确。