Open Voileexperiments opened 5 years ago
WebAssembly logo (it's CC0 aka effectively public domain).
@kazk I'm trying to set up the wasm docker but it seems that the docker image linked to in this repo (codewars/base-runner
) is completely outdated: it runs on trusty and Node 6 by default.
It's causing problems because trusty only has CMake 2.8 which causes error when building wabt because cmake_parse_arguments
is only a built-in in CMake 3.5. Also Node 6 has no wasm support.
I checked against the current runner and it runs on xenial (uname -v
gives #28~16.04.1-Ubuntu SMP Fri Jan 18 10:10:51 UTC 2019
); xenial's cmake
is 3.5.1 so it should be fine.
So how do I get access to the current base runner image and make wasm run off the xenial/Node 10 docker image?
? The new runner doesn't use any of those. The only code from this repository that's still used is the custom frameworks and some of the test output formatters.
So how do I get access to the current base runner image and make wasm run off the xenial/Node 10 docker image?
There's no common base image. If you're just trying to make a proof of concept, then just create anything that works. It doesn't even need to use Docker as long as it runs on Linux and shows how it can be used.
Okay then.
So as it turns out setting up WAT to JS toolchain is actually surprisingly simple:
curl https://deb.nodesource.com/gpgkey/nodesource.gpg.key | sudo apt-key add - \
&& apt-add-repository "deb https://deb.nodesource.com/node_11.x $(lsb_release -sc) main" \
&& apt-get update \
&& apt-get install -y nodejs
npm install -g binaryen wabt
export NODE_PATH=/usr/lib/node_modules:/runner/node_modules
// prepare WAT file
require('fs').writeFileSync('simple.wat', `(module
(func (export "addTwo") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add))
`);
// load WAT as module, validate then convert to binary var userCode = require('fs').readFileSync('simple.wat'); var wabt = require('wabt')(); var module = wabt.parseWat('simple.wat', userCode.toString()); try { module.validate(); } catch(e) { // validation failed throw e; } var wasm = module.toBinary({log: false});
// load the result binary like a normal wasm file var importObj = {}; WebAssembly.instantiate(wasm.buffer, importObj).then(res => { console.log(res.instance.exports.addTwo(1, 2)); // prints 3 });
(I added binaryen too in case someone wants to do other weird stuff with wasm.)
Things to investigate:
- `toBinary` also opens `canonicalize_lebs`, `relocatable` and `write_debug_names` flags from `wat2wasm`. Maybe open them to the test code?
- Needs more code snippets. I took the example from https://webassembly.github.io/wabt/demo/wat2wasm/, and there aren't lots of snippets around
- `wat2wasm` experimental features toggling is not documented but https://github.com/AssemblyScript/wabt.js/issues/2 shows a usage, I haven't put it in the above snippet
- I haven't tested error handling when parsing invalid wat files, it could be very shitty
Do we really need to generate binary format using JS API?
solution.wat
:
(module
(func $add (param i32 i32) (result i32)
(i32.add
(get_local 0)
(get_local 1)))
(export "add" (func $add)))
Generate binary format using wat2wasm
(should fail here on error):
wat2wasm solution.wat -o solution.wasm
Test:
const importWasm = require("./import-wasm"); // see below
const { assert } = require("chai");
// not ideal to import in a test case, but works
describe("add", () => {
it("adds two numbers", async () => {
const { add } = await importWasm("./solution.wasm");
assert.strictEqual(add(1, 1), 2);
});
});
Utility to import WebAssembly file.
// import-wasm.js
const readFile = require("util").promisify(require("fs").readFile);
module.exports = async function importWasm(file, env = defaultEnv()) {
const bytes = await readFile(file);
const module = await WebAssembly.compile(bytes);
return new WebAssembly.Instance(module, { env }).exports;
};
const defaultEnv = () => ({
memory: new WebAssembly.Memory({ initial: 256 }),
table: new WebAssembly.Table({
initial: 0,
element: "anyfunc",
}),
});
We can experiment more and decide.
Yes it can be done that way (it was my original approach), but wat2wasm
comes from wabt set and they only provide instructions to build the binaries with CMake, so package manager will not help here. Alternatively it can be grabbed from the release, but that's kinda janky (and I'm not sure if bugs won't be introduced this way).
npm install -g webassembly-binary-toolkit
after installing cmake
should build it. I haven't tried building image for this yet, but it's been working fine on my machine running Arch Linux.
Do you know the difference between wat2wasm
and wasm-as
?
wat2wasm: translate from WebAssembly text format to the WebAssembly binary format wabt
wasm-as: Assembles WebAssembly in text format (currently S-Expression format) into binary format (going through Binaryen IR). binaryen
So what does "going through Binaryen IR" do?
Binaryen IR is a compiler, so it doesn't just translate wat to wasm, it also does code analysis and wasm-specific optimization (one use case is wasm => Binaryen IR => wasm
). So it provides options akin to -O
in typical compilers.
Adding wasm language shouldn't be very hard since Node can call wasm binaries trivally, which means the majority of Node environment can be reused.
As far as coding goes wat (WebAssembly text format) is the standard so we can code in wat, and then let it be converted to wasm to be run by Node environment.
Steps:
solution.wat
towat2wasm
to get wasm fileAnd I think it's done?