Skip to content

Instantly share code, notes, and snippets.

@abd1rahmane
Forked from kanaka/addTwo.wast
Created June 17, 2021 21:39
Show Gist options
  • Save abd1rahmane/388481bd9a904e419e5b38a37e36c082 to your computer and use it in GitHub Desktop.
Save abd1rahmane/388481bd9a904e419e5b38a37e36c082 to your computer and use it in GitHub Desktop.
Run wast (WebAssembly) in node

Run wast (WebAssembly) in node

This is a simple example of compiling and running the WebAssembly textual format (wast) in Node.js on Linux. This does not cover compiling from a higher level language to WebAssembly (for that you probably want Emscripten). But if all you want to do is play around directly with the wast textual format, this should get you going quickly.

Links

Prerequisites

  • Install node 8

  • You need a wast to wasm compiler. The are several options. This example uses wabt (wabbit). You will need a standard gcc toolchain to build wabt. Build wabt and add it to your path:

git clone --recursive https://github.com/WebAssembly/wabt/
cd wabt
make gcc-release
export PATH=`pwd`/out/gcc/Release

Compile and Run Wast Code

Compile a wast to wasm (binary module):

wast2wasm addTwo.wast -o addTwo.wasm

Run an exported function in the wasm binary module using the runwasm.js script (this should print 5 to the console):

node ./runwasm.js addTwo.wasm addTwo 2 3

The runwasm.js script is also written to be used as a node module:

node
> w = require('./runwasm.js')
> w.loadWebAssembly('addTwo.wasm').then(i => console.log(i.exports.addTwo(7,8)))
15

You are free to use runwasm.js code under an MIT license.

You can also run wasm modules using wac (WebAssembly in C). wac is a WebAssembly interpreter in which the code runs in a native x86 host context rather than in a JavaScript/Web host context.

wac addTwo.wasm addTwo 2 3
0x5:i32
(module
(func $addTwo (param i32 i32) (result i32)
(i32.add
(get_local 0)
(get_local 1)))
(export "addTwo" (func $addTwo)))
#!/usr/bin/env node
// Copyright Joel Martin
// License MIT
const fs = require('fs'),
assert = require('assert')
assert('WebAssembly' in global,
'WebAssembly global object not detected')
// Convert node Buffer to Uint8Array
function toUint8Array(buf) {
var u = new Uint8Array(buf.length)
for (var i = 0; i < buf.length; ++i) {
u[i] = buf[i]
}
return u
}
// Based on:
// https://gist.github.com/kripken/59c67556dc03bb6d57052fedef1e61ab
// and
// http://thecodebarbarian.com/getting-started-with-webassembly-in-node.js.html
// Loads a WebAssembly dynamic library, returns a promise.
// imports is an optional imports object
function loadWebAssembly(filename, imports) {
// Fetch the file and compile it
const buffer = toUint8Array(fs.readFileSync(filename))
return WebAssembly.compile(buffer)
.then(module => {
// Create the imports for the module, including the
// standard dynamic library imports
imports = imports || {}
imports.env = imports.env || {}
imports.env.memoryBase = imports.env.memoryBase || 0
imports.env.tableBase = imports.env.tableBase || 0
if (!imports.env.memory) {
imports.env.memory = new WebAssembly.Memory({ initial: 256 })
}
if (!imports.env.table) {
imports.env.table = new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
}
// Create the instance.
return new WebAssembly.Instance(module, imports)
})
}
if (module.parent) {
module.exports.loadWebAssembly = loadWebAssembly
} else {
assert(process.argv.length >= 4,
'Usage: ./runwasm.js prog.wasm func INT_ARG...')
const wasm = process.argv[2],
func = process.argv[3],
// Convert args to either floats or ints
args = process.argv.slice(4).map(
x => x.match(/[.]/) ? parseFloat(x) : parseInt(x))
loadWebAssembly(wasm)
.then(instance => {
var exports = instance.exports
assert(exports, 'no exports found')
assert(func in exports, func + ' not found in wasm module exports')
//console.log('calling exports.'+func+'('+args+')')
console.log(exports[func](...args))
})
.catch(res => {
console.log(res)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment