Running WebAssembly (wasm) from Node.js

Yesterday, I looked up whether node.js can run wasm files, and I found a Stack Overflow answer and post that showed how. I couldn’t get the C file to compile to wasm in a way that would run in node*, but compiling a WebAssembly Text file worked.

First, put this in a file called test.wat:

(module
  (func $addTwo (param i32 i32) (result i32)
        (i32.add
          (get_local 0)
          (get_local 1)))
  (export "addTwo" (func $addTwo)))

After you have the “wabbit” installed**, compile with:

$ wat2wasm test.wat -o test.wasm

Create an app.js file with the code below:

const fs = require('fs');
const util = require('util');
const source = fs.readFileSync('./test.wasm');
const typedArray = new Uint8Array(source);

const env = {
    memoryBase: 0,
    tableBase: 0,
    memory: new WebAssembly.Memory({
        initial: 256
    }),
    table: new WebAssembly.Table({
        initial: 0,
        element: 'anyfunc'
    })
};

WebAssembly.instantiate(typedArray, {
    env: env
}).then(result => {
    // console.log(util.inspect(result, true, 0));
    // console.log('result.instance', result.instance);

    // Run the WebAssembly function
    console.log(result.instance.exports.addTwo(127, 1));
}).catch(e => {
    console.log(e);
});

Then run it with:

$ node app

*I was getting errors like these when trying to run the C code, but I don’t know enough about how wasm works yet to debug it.

$ emcc test.c -Os -s WASM=1 -s SIDE_MODULE=1 -o test.wasm
$ node app
LinkError: WebAssembly Instantiation: Import #0 module="env" function="__memory_base" error: global import must be a number
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
    at Function.Module.runMain (module.js:678:11)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3

$ wasm2wat test.wasm
(module
  (type (;0;) (func))
  (import "env" "__memory_base" (global (;0;) i32))
  (func (;0;) (type 0)
    global.get 0
    global.set 1
    global.get 1
    i32.const 5242880
    i32.add
    global.set 2)
  (global (;1;) (mut i32) (i32.const 0))
  (global (;2;) (mut i32) (i32.const 0))
  (export "__post_instantiate" (func 0)))

**I installed wabt by cloning the repo, compiling it with the command below, and then putting the resulting executable files on my PATH.

$ make gcc-release