tree: f477b8412748d389b849a858da1ead6dd8de8a49 [path history] [tgz]
  1. function-tests/
  2. fuzz/
  3. js-api/
  4. self-test/
  5. spec-tests/
  6. assert.js
  7. Builder.js
  8. Builder_WebAssemblyBinary.js
  9. import-spec-tests.rb
  10. LowLevelBinary.js
  11. README.md
  12. test.sh
  13. utilities.js
  14. WASM.js
  15. wasm.json
JSTests/wasm/README.md

wasmjs: JavaScript tooling for WebAssembly

wasmjs is a self-contained collection of JavaScript tools which can create and manipulate WebAssembly representations and binaries. At its core is wasm.json, a JSON decription of the WebAssembly format and other interesting facts about WebAssembly as used by the Webkit project (such as the names of associated JavaScriptCore B3 opcodes).

wasmjs requires modern JavaScript features such as ES6 modules, which is acceptable because WebAssembly is itself contemporary to these other features.

Builder API

The current core API of wasmjs is the Builder API from Builder.js. It is used to build WebAssembly modules, and assemble them to valid .wasm binaries (held in an ArrayBuffer). The Builder is a small DSL which looks similar to the WebAssembly binary format. Each section is declared through a property on the Builder object, and each declaration returns a proxy object which has properties specific to that section. Proxies are “popped” back by invoking their .End() property.

The Code section has properties for each WebAssembly opcode. Opcode which create a scope can be nested using a lambda.

A simple example:

import Builder from 'Builder.js';

const builder = new Builder();

// Construct the equivalent of: (module (func "answer" (i32.const 42) (return)))
builder
    // Declare a Type section, which the builder will auto-fill as functions are defined.
    .Type().End()
    // Declare a Function section, which the builder will auto-fill as functions are defined.
    .Function().End()
    .Export()
        // Export the "answer" function (defined below) to JavaScript.
        .Function("answer")
    .End()
    .Code()
        // The "answer" function takes an i32 parameters, and returns an i32.
        .Function("answer", { params: ["i32"], ret: "i32" })
            // Create a block returning an i32, whose body is the enclosed lambda.
            .Block("i32", b => b
                .GetLocal(0) // Parameters are in the same index space as locals.
                .I32Const(0) // Generate an i32 constant.
                .I32Eq()     // A comparison, using the two values currently on the stack.
                .If("i32")   // Consume the comparison result, returning an i32.
                    .I32Const(42)
                .Else()
                    .I32Const(1)
                .End()
            )
            .Return() // Return the top of the stack: the value returned by the block.
        .End() // End the current function.
    .End(); // End the Code section.

// Create an ArrayBuffer which is a valid WebAssembly `.wasm` file.
const bin = builder.WebAssembly().get();

// Use the standard WebAssembly JavaScript API to compile the module, and instantiate it.
const module = new WebAssembly.Module(bin);
const instance = new WebAssembly.Instance(module);

// Invoke the compiled WebAssembly function.
const result0 = instance.exports.answer(0);
if (result0 !== 42)
    throw new Error(`Expected 42, got ${result0}.`);

const result1 = instance.exports.answer(1);
if (result1 !== 1)
    throw new Error(`Expected 1, got ${result1}.`);

Testing

  • self-test tests wasmjs itself.
  • js-api tests the WebAssembly JavaScript API.
  • function-tests tests the WebAssembly compiler's implementation.

All tests can be executed using:

JSSHELL=/path/to/my/js-shell test.sh

They can also be executed by using WebKit's run-javascriptcore-tests tool:

./Tools/Scripts/run-javascriptcore-tests --release --filter wasm -arch x86_64