WASM mdBook

The purpose of this blog is to study low level WASM concepts and features in an iterative and interactive literate programming workflow.

It uses mdBook as a static site generator and the source code is on GitHub.

JS

For JS, the browser itself is the runtime so we can do whatever we want with Web API.

Our approach would be use script tag to load JS file directly into the markdown page.

<pre id="browser_vendor"></pre>
<script src="introduction/js/browser_vendor.js"></script>

introduction/js/browser_vendor.js

document.getElementById('browser_vendor').innerHTML =
`Your browser is made by ${window.navigator.vendor}
`


WASM

Install the WABT: The WebAssembly Binary Toolkit from Homebrew

$ brew install wabt

introduction/wat/simple.wat

(module
  (func $answer (;0;) (export "answer") (result i32)
    (local $var0 i32)
    i32.const 42
    local.set $var0
    local.get $var0
    return
  )
)

introduction/Makefile

build:
	wat2wasm wat/simple.wat -o wasm/simple.wasm
	wat2wasm wat/memory.wat -o wasm/memory.wasm
$ make -C src/introduction
wat2wasm wat/simple.wat -o wasm/simple.wasm
wat2wasm wat/memory.wat -o wasm/memory.wasm
<pre id="wasm_answer"></pre>
<script async src="introduction/js/wasm.js"></script>

introduction/js/wasm.js

(async () => {
    var importObject = {};
    const response = await fetch('introduction/wasm/simple.wasm');
    const bytes = await response.arrayBuffer();
    const { instance } = await WebAssembly.instantiate(bytes, importObject);
    const { exports } = instance;
    console.log('WASM Answer', {response, bytes, instance, exports});
    document.getElementById('wasm_answer').innerHTML = `From WASM Answer
${instance.exports.answer()}
Also see console log.
    `
})();


WASM Memory

Based on

introduction/wat/memory.wat

(module
  (memory (import "js" "mem") 1)
  (func (export "accumulate") (param $ptr i32) (param $len i32) (result i32)
    (local $end i32)
    (local $sum i32)
    (local.set $end (i32.add (local.get $ptr) (i32.mul (local.get $len) (i32.const 4))))
    (block $break (loop $top
      (br_if $break (i32.eq (local.get $ptr) (local.get $end)))
      (local.set $sum (i32.add (local.get $sum)
                               (i32.load (local.get $ptr))))
        (local.set $ptr (i32.add (local.get $ptr) (i32.const 4)))
        (br $top)
    ))
    (local.get $sum)
  )
)
wat2wasm wat/memory.wat -o wasm/memory.wasm
<pre id="wasm_memory"></pre>
<script async src="introduction/js/memory.js"></script>

introduction/js/memory.js

(async () => {
    var mem = new WebAssembly.Memory({initial:10, maximum:100});

    var importObject = { js: { mem }};
    const response = await fetch('introduction/wasm/memory.wasm');
    const bytes = await response.arrayBuffer();
    const { instance } = await WebAssembly.instantiate(bytes, importObject);
    const { exports } = instance;
    const { accumulate } = exports;
    var i32 = new Uint32Array(mem.buffer);
      for (let i = 0; i < 100; i++) {
        i32[i] = i+1;
      }
    const sum = accumulate(0, 100); 
    console.log('WASM Memory', {response, bytes, instance, exports, sum});
    document.getElementById('wasm_memory').innerHTML = `From WASM Memory
sum = ${sum}
Also see console log.
`

})();