昨天測試中,以為區塊是使用新的堆疊,所以無法返回值。不過後來發現不是這麼回事Orz
區塊跟函數一樣,都可以指定返回值,只是預設不返回,所以需要返回的時候,只要宣告就可以啦。
原本的Fibonacci函數長這樣:
(module
(func $fibn (param $cur i32) (param $nex i32) (param $n i32) (result i32)
(local $ret i32)
get_local $n
i32.const 0
i32.eq ;;param for if
if
get_local $cur
set_local $ret
else
get_local $nex ;;1st param for $fibn
get_local $cur
get_local $nex
i32.add ;;2nd param for $fibn
get_local $n
i32.const 1
i32.sub ;;3rd param for fibn
call $fibn
set_local $ret
end
get_local $ret
)
(func (export "fib") (param $n i32) (result i32)
i32.const 0
i32.const 1
get_local $n
call $fibn
)
)
set_local $ret
以及get_local $ret
這兩個動作看起來就很多餘。
只要正確的宣告if,其實不需要用到$ret區域變數:
(module
(func $fibn (param $cur i32) (param $nex i32) (param $n i32) (result i32)
get_local $n
i32.const 0
i32.eq ;;param for if
if (result i32)
get_local $cur
else
get_local $nex ;;1st param for $fibn
get_local $cur
get_local $nex
i32.add ;;2nd param for $fibn
get_local $n
i32.const 1
i32.sub ;;3rd param for fibn
call $fibn
end
)
(func (export "fib") (param $n i32) (result i32)
i32.const 0
i32.const 1
get_local $n
call $fibn
)
)
以上。
修正昨天的錯誤後,來看分支以及其他流程控制用的指令。
之前也講過br很簡單,就類似goto,只是他後面要跟一個label變數或索引值。不過在Web Assembly裡面,只有區塊可以加上label...所以會參考到label的程式碼,一定是位於區塊內。
br的寫法像這樣:
...
(block $label
...
br $label
)
其實跟br差不多,只是要先做一個比較運算,根據結果來決定要不要分支。寫起來就像這樣:
...
(block $label
...
get_local $n
i32.const 0
i32.eq
br_if $label
在比較複雜的區塊結構中,使用br_table可以用一個判斷來決定要分支到哪個列出的label。先來看一下範例:
(module
(func (export "test") (param $n i32) (result i32)
(block $a
(block $b
(block $c
(block $d
(block $e
(br_table $b $a $c $d $e (get_local $n))
(return (i32.const 99))
)
(return (i32.const 100))
)
(return (i32.const 101))
)
(return (i32.const 102))
)
(return (i32.const 103))
)
(i32.const 104)
)
)
這個test函數,有一個參數$n,可以用他來在br_table做判斷。在br_table中給定的label列表是:
不過在上面的程式中,刻意把列表中的$a跟$b互換,這樣$b就變成索引為0的label,而$a是索引為1的...
然後來測試一下:
<html>
<body>
<script src="../wasm_util.js"></script>
<script>
new Wasm('test012.wasm')
.getInstance()
.then(instance => {
console.log(instance.exports.test(0));
console.log(instance.exports.test(1));
console.log(instance.exports.test(2));
console.log(instance.exports.test(3));
console.log(instance.exports.test(4));
console.log(instance.exports.test(5));
})
</script>
</body>
</html>
分別傳給函數0~5,看看他返回哪些東西:
結果分別是:
分別對應到$b, $a, $c, $d, $e, $e,看起來只要運算式的結果不在索引範圍,就會使用列表中最後一個label。(其實我試過,傳-1,結果也是100)
還有幾個指令跟流程控制相關的:
沒了。其他幾個跟流程有相關的是call以及call_indirect,前者呼叫在程式中定義或是輸入的函數,後者用來呼叫透過Table定義的函數。
明天不知道練習什麼比較好XD,先來做一些應用看看好了