WebAssembly入门笔记[3]:如何用Table传递引用实现引用传递?
摘要:在《WebAssembly入门笔记[2]》中,我们介绍了如何利用Memory在作为宿主的JavaScript应用和wasm模块之间传递数据,但是Memory面向单纯二进制字节的读写在使用起来还是不太方便,此时我们会更多地用到另一个重要的对象
在《WebAssembly入门笔记[2]》中,我们介绍了如何利用Memory在作为宿主的JavaScript应用和wasm模块之间传递数据,但是Memory面向单纯二进制字节的读写在使用起来还是不太方便,此时我们会更多地用到另一个重要的对象Table。Table利用用来存储一组指定类型的对象,说得准确一点是对象的引用,所以可以读取出来直接消费。
一、利用Table存储wasm函数引用
二、执行call_indirect执行函数
三、利用Table存储JavaScript函数引用
一、利用Table存储wasm函数引用就目前的版本来说,Table只支持funcref和externref两种引用类型,前者表示wasm原生函数,后者则用来存储宿主程序提供的任何JavaScript对象,所以如果存储JavaScript函数,Table元素的类型必需指定为externref。下面的实例演示了这样的场景:wasm模块将自身定义的函数存储在导出的Table中供宿主程序使用。
如下所示的采用WebAssembly Text(WAT)格式定义的app.wat文件的定义。我们定义了用来执行加、减、乘、除运算的四个函数,并将它们存储在导出的Table中。由于存储的是wasm函数,所以Table定义语句(table (export "table") funcref (elem $add $sub $mul $div))将元素类型设置为funcref。我们利用elem语句将四个函数的引用填充到Table中。(源代码)
(module
(func $add (param $op1 i32) (param $op2 i32) (result i32)
(local.get $op1)
(local.get $op2)
(i32.add)
)
(func $sub (param $op1 i32) (param $op2 i32) (result i32)
(local.get $op1)
(local.get $op2)
(i32.sub)
)
(func $mul (param $op1 i32) (param $op2 i32) (result i32)
(local.get $op1)
(local.get $op2)
(i32.mul)
)
(func $div (param $op1 i32) (param $op2 i32) (result i32)
(local.get $op1)
(local.get $op2)
(i32.div_u)
)
(table (export "table") funcref (elem $add $sub $mul $div))
)上面的定义主要是为了解释wasm基于“堆栈”的参数传递方式,代码相对繁琐。如果切换如下所示的“嵌套模式”,就会简洁很多。(源代码)
(module
(func $add (param $op1 i32) (param $op2 i32) (result i32)
(i32.add (local.get $op1) (local.get $op2))
)
(func $sub (param $op1 i32) (param $op2 i32) (result i32)
(i32.sub (local.get $op1) (local.get $op2))
)
(func $mul (param $op1 i32) (param $op2 i32) (result i32)
(i32.mul (local.get $op1) (local.get $op2))
)
(func $div (param $op1 i32) (param $op2 i32) (result i32)
(i32.div_u (local.get $op1) (local.get $op2))
)
(table (export "table") funcref (elem $add $sub $mul $div))
)在承载宿主应用的index.html中,在得到导出的Table对象之后,我们将存储(0-3)的位置作为参数调用其get方法得到对应的wasm函数。我们传入相同的参数(2,1)调用这四个函数。
