| 11 | } |
| 12 | |
| 13 | fn run_passed_funcref_example() -> Result<()> { |
| 14 | // Host receives funcref and calls it via an exported proxy. |
| 15 | const WASM: &str = r#" |
| 16 | (module |
| 17 | (import "host" "call_this" (func $host_callback_caller (param funcref))) |
| 18 | (import "host" "mul" (func $host_mul (param $x i32) (param $y i32) (result i32))) |
| 19 | |
| 20 | (func $tell_host_to_call (export "tell_host_to_call") |
| 21 | (call $host_callback_caller (ref.func $add)) |
| 22 | (call $host_callback_caller (ref.func $sub)) |
| 23 | (call $host_callback_caller (ref.func $host_mul)) |
| 24 | ) |
| 25 | |
| 26 | (type $binop (func (param i32 i32) (result i32))) |
| 27 | |
| 28 | (table 3 funcref) |
| 29 | (elem (i32.const 0) $add $sub $host_mul) |
| 30 | (func $add (param $x i32) (param $y i32) (result i32) |
| 31 | local.get $x |
| 32 | local.get $y |
| 33 | i32.add |
| 34 | ) |
| 35 | (func $sub (param $x i32) (param $y i32) (result i32) |
| 36 | local.get $x |
| 37 | local.get $y |
| 38 | i32.sub |
| 39 | ) |
| 40 | |
| 41 | (table $callback_register 1 funcref) |
| 42 | (func (export "call_binop_by_ref") (param funcref i32 i32) (result i32) |
| 43 | (table.set $callback_register (i32.const 0) (local.get 0)) |
| 44 | (call_indirect $callback_register (type $binop) (local.get 1)(local.get 2)(i32.const 0)) |
| 45 | ) |
| 46 | ) |
| 47 | "#; |
| 48 | |
| 49 | let wasm = wat::parse_str(WASM).expect("failed to parse wat"); |
| 50 | let module = tinywasm::parse_bytes(&wasm)?; |
| 51 | let mut store = Store::default(); |
| 52 | |
| 53 | let mul = HostFunction::from(&mut store, |_, (lhs, rhs): (i32, i32)| -> tinywasm::Result<i32> { Ok(lhs * rhs) }); |
| 54 | let call_this = |
| 55 | HostFunction::from(&mut store, |mut ctx: FuncContext<'_>, func_ref: FuncRef| -> tinywasm::Result<()> { |
| 56 | // Host cannot call a funcref directly, so it routes through Wasm. |
| 57 | let call_by_ref = ctx.module().func::<(FuncRef, i32, i32), i32>(ctx.store(), "call_binop_by_ref")?; |
| 58 | let _result = call_by_ref.call(ctx.store_mut(), (func_ref, LHS, RHS))?; |
| 59 | Ok(()) |
| 60 | }); |
| 61 | |
| 62 | let mut imports = Imports::new(); |
| 63 | imports.define("host", "call_this", call_this).define("host", "mul", mul); |
| 64 | |
| 65 | let instance = ModuleInstance::instantiate(&mut store, &module, Some(imports))?; |
| 66 | let caller = instance.func::<(), ()>(&store, "tell_host_to_call")?; |
| 67 | |
| 68 | caller.call(&mut store, ())?; |
| 69 | |
| 70 | Ok(()) |