WebAssembly in javascript : load and run with ease

WebAssembly libraries looks like unicorns in the sky, but they need to be prepared to be used efficiently ;
most of the time, you start by naively pass values in functions before realizing that only pointers are read.

const webAssemblyModule = await WebAssembly.compile(wasmData);
const instance = await WebAssembly.instantiate(webAssemblyModule,
{env: {memory: newMemory}, exports: { memory: newMemory }});
instance.exports.foo("bar"); // but intriguingly, foo is called with a number ??

When you suddenly realize that you have to use a memory as a buffer between your application and the library,
you start doing silly things like :
const pointer = (instance.exports as any).__new(length * 2, 1);
const U16 = new Uint16Array((instance.exports.memory as WebAssembly.Memory).buffer);
const base = Math.floor(pointer / 2);

javascriptString.split('').forEach((_, index) => {U16[base + index] = javascriptString.charCodeAt(index);});

Then you invoke your so-called pure function with your pointer, cheating with the types by the way :
instance.exports.foo(pointer as string); // actually it is a number but typescript should not complain

And if your function happens to return a result, you have to look for the value using a reverse lookup function again …

const memory = instance.exports.memory as WebAssembly.Memory;
const memoryBuffer = memory.buffer as ArrayBuffer;
const U16 = new Uint16Array(memoryBuffer);
const beginIndex16 = Math.ceil(pointer / 2);
const lastIndex16 = U16.indexOf(0, beginIndex16);
const value16 = U16.slice(beginIndex16, lastIndex16);
return Buffer.from(value16).toString();

What if you could just call a wrapper that creates a javascript function that does the boilerplate for you ?
This is what I am doing with this : https://gist.github.com/libetl/b15798408d34ea48e4838936a083cd83

In this example, simply do const { foo } = await init(await fs.readFile(resolve(__dirname, './library.wasm')));
Then, you should be able to call it as a simple function :
expect(foo("bar")).toEqual("Hello foo 'bar'");

Simple enough, isn’t it ?

Leave a Reply

Your email address will not be published. Required fields are marked *


This site uses Akismet to reduce spam. Learn how your comment data is processed.