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,这可能是对您有用的资源。
我正在编写一个 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,这可能是对您有用的资源。