WebAssembly有三種區塊指令:
block...end
loop...end
if...else...end
區塊有一個特色,就是裡面計算的值無法透過堆疊返回,另外,if需要從堆疊取一個參數做條件判斷,block及loop則不會帶入參數。所以像這樣的區塊就會有問題:
(func (export "test1") (result i32)
i32.const 3
block $blk
i32.const 55
i32.add
end
)
編譯時,會警告i32.add的參數不符合,他需要兩個參數,但是只給了一個。
所以,如果有值需要從區塊往外傳,可以把他寫入Memory,或是寫入到local變數。像這樣:
(func (export "test1") (param $n i32) (result i32)
(local $ret)
block
get_local $n
i32.const 1
i32.add
set_local $ret
end
get_local $ret
)
if區塊會需要一個參數來做條件判斷,可以使用不同型別的比較運算指令來產生這個參數。例如寫一個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
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
)
)
這個函數是從維基百科上費氏數列條目底下的Javascript範例改寫的,可以互相參照。
在html端呼叫一下:
<html>
<body>
<script src="../wasm_util.js"></script>
<script>
new Wasm('test009.wasm').getInstance()
.then(instance => {
console.log(instance.exports.fib(40));
});
</script>
</body>
</html>
跑出來的結果:
既然剛好也有結構差不多的Javascript Fibonacci函數,乾脆來比較一下速度。把Javascript版本的函數也放進html:
<html>
<body>
<script src="../wasm_util.js"></script>
<script>
new Wasm('test010.wasm').getInstance()
.then(instance => {
let start = new Date().getTime();
let result = 0;
for(let i=0; i<1000000; i++) {
result = instance.exports.fib(40);
}
let end = new Date().getTime();
console.log(end-start + 'ms\n' + result);
start = new Date().getTime();
for(let i=0; i<1000000; i++) {
result = fib(40);
}
end = new Date().getTime();
console.log(end-start + 'ms\n' + result);
});
function fib(n) {
var fib_n = function(curr, next, n) {
if (n == 0) {
return curr;
}
else {
return fib_n(next, curr+next, n-1);
}
}
return fib_n(0, 1, n);
}
</script>
</body>
</html>
各跑一百萬次fib(40),然後比較一下時間。可以看出WebAssembly的版本執行速度會快一點:
block跟loop區塊,在之前的文章有提到過。總之總結一下重點:
區塊 | 參數數目 | Label位置 |
---|---|---|
block | 0 | 結束 |
loop | 0 | 開始 |
if | 1 | 結束 |
嗯,分支相關的指令中,br
跟br_if
沒什麼問題,但是br_table怎麼寫...文件有點不太清楚,所以把他推遲到明天吧XD,先花一些時間寫寫看。明天也同時介紹一下其他控制指令。