Skip to content

Instantly share code, notes, and snippets.

@Sc4ramouche
Last active June 4, 2024 08:15
Show Gist options
  • Save Sc4ramouche/253a5c689e0a91fd5ac60937bb38fd17 to your computer and use it in GitHub Desktop.
Save Sc4ramouche/253a5c689e0a91fd5ac60937bb38fd17 to your computer and use it in GitHub Desktop.

Adjust Frontend Day 2024

Sisyphus.

Who knows what WebAssembly is?

It is an overloaded term. Compile target, also runtime. Low-level language?

It was created to complement JavaScript on the web. Performance and portability. And it was not necessarily created for UI engineers.

WASM runs on near native speed. It is executed in a sandboxed env.

So, WASM is now a full-fledged part of the web.

Binary Nature

WASM executes binary code. We compile Rust to binary. However WASM has another representation format — WAT. Best name ever for debugging file format. Quite unique situation two formats here.

Compiling Rust to WASM

It might be surprising, but that's all to get started with WASM.

We will compile Rust to WASM.

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"
  • src/lib.rs content:
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn add_one(x: i32) -> i32 {
    x + 1
}
  • wasm-pack build --target web
  • introduce the following index.html in the root:
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>hello-wasm example</title>
  </head>
  <body>
    <script type="module">
      // TODO
    </script>
  </body>
</html>
  • the JS we need:
WebAssembly.instantiateStreaming(fetch('./pkg/rust_wasm_bg.wasm')).then(({instance}) => {
    const res = instance.exports.add_one(41)
    document.write(res)
})
  • start up the server python -m http.server

Using wasm-pack glue code:

import init, {add_one} from './pkg/rust_to_wasm.js'
init().then(() => {
    document.write(add_one(30))
})

CMD+CTRL+C

So, let's recap what we have done here:

  • We have written a simple Rust function
  • Compiled it to WASM
  • We have fetched the binary WASM code and compiled it
  • We called the Rust function from our JavaScript world

Compiling WAT to WASM

There's one downside to the example I just showed as we are not able to look into WAT.

Screenshot of wasm-pack with feature request of compiling WAT too.

Now we will try to take a closer look at WAT.

(module
  (func $add_one (param $x i32) (result i32)
    get_local $x
    i32.const 1
    i32.add
  )
  (export "add_one" (func $add_one))
)

Wikipedia example of stack virtual machine.

This is kind of the lowest level you can get to write code. No if blocks, no loops, no variables we are used to.

Table of opcodes in WASM.

Different computer architectures are.

Compiling AssemblyScript to WASM

Now we got some ambition, I feel excited and I am ready to write some decent project in WASM. But I definitely don't want to write WAT by hand.

There's AssemblyScript — TypeScript to WASM compiler. With AssemblyScript we got all the luxury of high-level programming language.

  • npm i --save-dev assemblyscript
  • npx asinit .
  • npm run asbuild
  • node
  • const wasm = await import('./build/release.js')

Running from Node.js — check

Demonstrate the point of WAT being rediculous with fizzbuzz.

export function fizzbuzz(num: i32): string | null {
  if (num % 15 === 0) return "fizzbuzz";
  if (num % 3 === 0) return "fizz";
  if (num % 5 === 0) return "buzz";
  return null;
}

We have been exposing WASM code to JS.

Note on string conversion.

  • declare function log(n: i32): void
memory.grow(2); // 2 x 64KB
store<u8>(0, 21); // globally available functions 
store<u8>(1, 42);
store<u8>(2, 64);

export function readMemory(n: i32): i32 {
  return load<u8>(n);
}
const {memory, readMemory} = instance.exports;
const memoryArray = new Uint8Array(memory.buffer)
console.log(memoryArray[0], memoryArray[1], memoryArray[2], memoryArray[3])
memoryArray[2] = 100
console.log(memoryArray[2])
console.log(readMemory(2))

Conclusion

WASM VS Web Worker? WASM is cached You might be wondering, why do we care.

You came up with your own reasons. I first got to meet WASM during uni.

Exploring this technology was a window for me to explore stuff which was exciting and scary. Hexadecimal, binary string representation, how WASM is loaded, how little python server is being run.

But this WASM thing was a window for me to learn so much: operational codes, virtual stack machine, binary execution.

  • We have seen three different ways to do the same thing

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment