WebAssembly:编译具有 return 值的循环未按预期运行

WebAssembly: compilation of loops with return values not behaving as expected

我正在编写一个 WebAssembly 字节码分析器,并遇到了一些关于各种 WebAssembly 编译器如何处理循环指令的行为,我发现这些行为很难与 WebAssembly 规范相协调。

以下代码片段(摘自 WebAssembly loop test cases)显示了一个嵌套循环,该循环预期 return 一个 i32 整数。

(module
  (type $t0 (func (result i32)))
  (func $cont-inner (export "cont-inner") (type $t0) (result i32)
    (local $l0 i32)
    i32.const 0
    local.set $l0
    local.get $l0
    loop $L0 (result i32)
      loop $L1 (result i32)
        br $L0
      end
    end
    i32.add
    local.set $l0

对上述内容的可视化分析表明,这种语法并不严格符合规范(据我所知),因为循环体没有任何 return.[=13 的堆栈值=]

当然上面的循环形成了一个死循环,所以在执行的时候程序实际上不会退出最外层的循环。

但是我试过的几个编译器编译这个没有任何问题,例如webassembly.studio。相反,如果无条件分支被条件分支替换,那么编译器实际上会按照我的预期运行并抱怨缺少 return 值。

我是否遗漏了有关循环如何运行的 WebAssembly 规范中的某些内容?还是编译器隐含地进行了一些可达性分析?

您正在观察的是无条件分支之后的 stack becoming polymorphic。这意味着堆栈的行为就像它具有验证所需的值一样。

在这种情况下,br $L0 指令使堆栈具有多态性。通常从末尾掉落 loop $L1 需要堆栈上的 i32,但由于堆栈是多态的,类型检查器的行为就好像这是真的。

您可能会找到 validation algorithm in the spec useful. I also wrote about WebAssembly type-checking a while back,这可能是对您有用的资源。