Passing multiple values from WebAssembly to Javascript can be harder than it needs to be. Normally, I find that I have to:
- Setup memory shared between Javascript and WebAssembly.
- Do the WASM work to produce the values.
- Store the values somewhere in the shared memory.
- Output a memory pointer to Javascript.
- Have Javascript retrieve the values from shared memory.
Multi-value is a feature of WASM intended to make this easier, where multiple values can be passed directly from WASM to Javascript, eliminating the need to deal with pointers. The steps become:
- Do the WASM work to produce the values.
- Output the values to Javascript.
For example:
(module
(func $multResult (export "multResult")
(result f64 f64)
f64.const 1
f64.const 2
)
)
We directly output 1 and 2.
I can use Rick Battagline's helpful functions to compile WASM from WAT (with a slight fix to properly support the multi-value flag):
node ./bin/watwasm bugrepro.wat -o newoutput.wasm -O3 --multi-value
Turning the resulting WASM compilation back into WAT, we get:
(module
(type $none_=>_f64_f64 (func (result f64 f64)))
(export "multResult" (func $0))
(func $0 (result f64 f64)
(tuple.make
(f64.const 1)
(f64.const 2)
)
)
)
That tuple.make command is the secret sauce that makes the function consumable directly in Javascript. If I write this Javascript:
const fs = require('fs');
const wasmBytes = fs.readFileSync('./newoutput.wasm');
WebAssembly.instantiate(wasmBytes)
.then(obj => obj.instance.exports)
.then(exported => exported.multResult())
.then(res => console.log(res));
I can see that [1,2] is returned by the WASM function. Terrific.
I want to be able to do this with higher-level languages than WAT. Do any higher-level languages produce multi-value WASM?