Compiling Wat to WebAssembly


As said in Understanding WebAssembly text format, to enable WebAssembly to be read and edited by humans, there is a textual representation of the wasm binary format. You've seen how to compile C to WebAssembly and the corresponding text format in Compiling C to WebAssembly. In both the binary and textual formats, the fundamental unit of code in WebAssembly is a module. If you have experience with Lisp, you might feel familiar with the text format represented as one big S-expression.

WasmFiddle can compile C to WebAssembly but doesn't allow editing the text format. There's a online WasmExplorer which allows you to do that (but doesn't provide JavaScript editor).

Compiling Wat to WebAssembly

In the above figure, you can edit the WebAssembly text format in the “Wat”. (The file extension of the WebAssembly text format is “.wat”. That's why we often call it “Wat”.) After editing in “Wat”, click “ASSEMBLE” to compile to the wasm binary format.

Even though I haven’t started talking about Wat, you can still understand what the code does from keywords module, func, param, result and export. The code defines a module and exports an add function.

(module
  (func $add (param $lhs i32) (param $rhs i32) (result i32)
    get_local $lhs
    get_local $rhs
    i32.add)
  (export "add" (func $add))
)

The get_local command would push the value of the local it read onto the stack. We push two values onto the stack because i32.add pops two i32 values, computes their sum and pushes the resulting i32 value onto the stack.

After downloading “.wasm“, use the following JavaScript to invoke the exported add function.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <script>    
    WebAssembly.instantiateStreaming(fetch('program.wasm'))
               .then(prog => {
                   console.log(prog.instance.exports.add(1, 2)); 
               });
    </script>
  </body>
</html>

You can edit and compile Wat locally through WABT: The WebAssembly Binary Toolkit. The wat2wasm command translates from WebAssembly text format to the WebAssembly binary format. The wasm2wat command is the inverse of wat2wasm. It translates from the binary format back to the text format.

If you use Visual Studio Code, the extension WebAssembly Toolkit for VSCode by Dmitriy Tsvettsikh is helpful. It provides syntax highlight for WebAssembly textual representation and fast convertation between text and binary view.

Compiling Wat to WebAssembly

You can see that I use http-server of Node.js in the above figure.

Importing a JavaScript function can be done by import. For example, the following code imports and calls the JavaScript log function into WebAssembly.

(module
  (import "env" "log" (func $log (param i32)))
  (func $add (param $lhs i32) (param $rhs i32) (result i32)
    (local $result i32)
    get_local $lhs
    get_local $rhs
    i32.add
    tee_local $result
    call $log
    get_local $result)
  (export "add" (func $add))
)

The example includes more details about Wat. I'll explain them in later documents.

Node.js also supports WebAssembly now. For example, you can edit a .js file.

const fs = require('fs');
const buffer = fs.readFileSync(('program.wasm'));

WebAssembly.instantiate(buffer)
.then(prog => {
    console.log(prog.instance.exports.add(1, 2)); 
});

Use nodejs to run it. You would see the resulting 3 shown in the console.