[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

可以在here中找到一个测试.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程序。实现callend的最简单方法是使用JSRRET操作码,它们是用来实现子例程的。在JSR操作之后,堆栈将包含一个returnAddress引用,该引用应存储在变量中,以便以后在end中使用。

    但是,由于可以将markcall编码为jump,因此堆栈中可能包含也可能不包含returnAddress引用。我决定使用一个 boolean 变量(地址为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
    

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

    我已经使用ASM的分析器来监视堆栈以调试所有这些内容,但是刚刚断言了这种行为,并且找不到我做错了什么。我的一个怀疑是iincifeq还有比我徒劳的哲学想像的更多的东西。我承认我只阅读了该项目的instruction set pageASM's pertinent documentation,但是我希望有人可以从头开始提出解决方案。

    In this folder有相关文件,包括可执行文件类和原始空格,以及javap -c和ASM分析的输出。

    最佳答案

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

    就是说,示例代码未与-noverify标志一起运行,但是其他未通过验证的简单示例确实可以正确执行。

    10-06 13:13