iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 10
2
Modern Web

謙虛,踏實的Web Assembly練習系列 第 10

[練習 09] 流程控制指令

  • 分享至 

  • xImage
  •  

區塊

WebAssembly有三種區塊指令:

  1. block...end
  2. loop...end
  3. 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>

跑出來的結果:

Imgur

既然剛好也有結構差不多的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的版本執行速度會快一點:

Imgur

block跟loop區塊,在之前的文章有提到過。總之總結一下重點:

區塊 參數數目 Label位置
block 0 結束
loop 0 開始
if 1 結束

嗯,分支相關的指令中,brbr_if沒什麼問題,但是br_table怎麼寫...文件有點不太清楚,所以把他推遲到明天吧XD,先花一些時間寫寫看。明天也同時介紹一下其他控制指令。


上一篇
[練習 08] 使用Table來分享資源
下一篇
[練習 10] 對於區塊理解的錯誤以及br_table的寫法
系列文
謙虛,踏實的Web Assembly練習20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言