A Taste Of WASM

The Browser as a Virtual Machine

@m4d_z
alwaysdata logo
Because it's sooooo cool!

Remember

  • 2001: Prototype, Scriptaculo·us, Mootools
  • 2005: jQuery
  • 2010: SPA / Backbone
  • 2012: Angular
  • 2015: virtual-dom, React, Vue.js
  • 2018: PWA
  • 2019: How is your RAM today? Good?

WASM, What’s that?

Emscripten

Performances on Emscripten, a metaphor

asm.js
(optimized JS sub-part)

JS: event-driven

Single-threaded

  • Frozen UI
  • Memory Leaks
  • nextTick : setTimeout({...}, 0)

Concurrency:
WebWorker, ServiceWorkers

We want more perfs!

WebAssembly, is a new language, close to a machine codes instructions (an Assembly language) which allow pretty good, close to native performances, in the Web Browser.

0200 20 00
0202 42 00
0204 51
0205 04 7e
0207 42 01
020A 05
020B 20 00
020D 20 00
0210 42 01
0211 7d
0212 10 00
0214 7e
0217 0b

This is not a language!

get_local 0
i64.const 0
i64.eq
if i64
    i64.const 1
else
    get_local 0
    get_local 0
    i64.const 1
    i64.sub
    call 0
    i64.mul
end

Compile for the Web Architecture

LLVM (die, GCC)
the best compiling toolchain

Why?
Because We CAN!

JS can’t address all use-cases.
We sometimes need to share a codebase between projects.

The Browser is a Virtual Machine

  • PWA
  • Electron
  • Cordova
  • etc.

WASM

  • Any language that compile
  • Compiled through LLVM to WASM
  • Loaded using JS
  • Executed in the Browser

Back to Basics: It’s not that easy

Stack Based VM

Stack based vs. Register based

  • Register: close to the CPU, powerful
  • Stack: flexible, lightweight
  • JVM, CLR &… JS JIT: Stack Based VM

Stack Based VM

Magic!

The Stack is the main point

Operation: (1 + 2 * 3) / 7
Instructions: 1.2.3.MUL.ADD.7.DIV

ASM!

PUSH 1
PUSH 2
PUSH 3
MUL
ADD
PUSH 7
DIV

Logic JS Engine

  • SpiderMonkey
  • V8
  • Chakra
  • JavaScriptCore (JSC)

At start:

  • JS VM Engine
  • Interpreter
  • Compiler JIT

JIT Compiler produces
machine code instructions
fastly, but is limited

WASM uses the same Engine

  • quick exchanges with JS
  • unboxing
  • monomorphic calls
  • built-ins methods

Execution Engine able to
run all logic languages
directly on the Web!

Rust

Why Rust? :

  • C++, thanks, but I only have one brain
  • No data-race, by design
  • Static types
  • Iterators
  • Excellent Memory Management
  • Community
  • Toolchain (Rustup, Cargo, Rustc…)

Hello World

fn main() {
    // Print text to the console
    println!("Hello World!");
}

Modules By Design

mod sound {
    pub mod instrument {
        pub fn pouet() {
            // ...
        }
    }
}
fn main() {
    crate::sound::instrument::pouet();
}

Static Types & Iterators

mod squares {
    pub fn sum_from_zero( n: i32) -> i32 {
        (0 ..= n).fold(0, |a, b| a + b)
    }
}

Cargo

$ cargo build
   Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)
$ cargo run
     Fresh hello_world v0.1.0 (file:///path/to/package/hello_world)
   Running `target/hello_world`
Hello, world!

Production‽

Fantastic Four!

Open Standard

WASM Rust Hello World on the Web

pub fn greet(name: &str) {
    alert(&format!("Hey! {}!", name));
}

Execution timeline

  1. Fetch
  2. Load / Compile (2×)
  3. Instantiate
  4. Access fn

Fetch !

fetch('my-module.wasm')
  .then(res => res.arrayBuffer())
  .then(instance => WebAssembly.instantiate(instance))
  .then(module => {
    // module.instance.exports[...]
  })

Transfert Data to WASM

...
.then(module => {
  const sum = module.instance.exports.add(7, 4)
  console.log(sum)
})

4 static types

  • 2 Integers
  • 2 Floats

Problem:
I need more than numbers!

A number could be…
a memory pointer!

Linear Memory

const pointer = 0

const LM = new WebAssembly.Memory({ initial: 1 })
const sharedMem = new Uint8Array(LM.buffer)

const str = "Hello World"

[].forEach.call(
  btoa(str),
  (char, idx) => sharedMem[pointer + idx] = char.charCodeAt(0)
)
// Uint8Array(65536) [ 83, 71, 86, 115, 98, 71, 56, 103, 86, 50, … ]

wasm-bindgen!

wasm-bindgen facilitates high-level interactions between wasm modules and JavaScript.

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hey! {}!", name));
}
const wasm = import("./js_hello_world")
wasm.then(wasm => wasm.greet("Hello World"))
  • Export JS fn to Rust
  • JS
    • JS-types
    • Boxes
    • Catch
    • Getter / Setter
    • Namespaces
  • Web-sys
    • DOM
    • Fetch
    • Canvas / requestAnimationFrame
    • WebAudio / WebGL

Compiling? wasm-pack!

$ curl https://sh.rustup.rs -sSf | sh
$ rustup install nightly
$ rustup target add wasm32-unknown-unknown --toolchain nightly
$ wasm-pack build hello_world --target web --out-dir ./pkg

📦✨ your favorite rust → wasm workflow tool!

A State of WASM

interface Record {
  id: Sha256,
  payload: object
}

interface Block {
  id: Sha256,
  parent: Sha256,
  nonce: number,
  records: Array<Record>
}

let blockchain: Array<Block>
while (true) {
  node.nonce = nonce()
  node.id = await crypto.subtle.digest('SHA-256', encoder.encode(`
    ${node.parent};${node.nonce};
    ${node.records.map(record => Object.values(record).join(';')).join(';')}
  `))
  .then(value => tohex(value))

  if (node.id.substr(0, limit) == prefix) {
    break
  } else {
    node.records = shuffle(node.records)
  }
}
loop {
    let mut rng = thread_rng();
    _nonce = (0..32)
        .map(|_| rng.gen_range(0, 9).to_string())
        .collect();
    &mut node.records.shuffle(&mut rng);
    let _values: String = node.records.iter_mut().map(|r| r.join()).collect();

    let sha = Sha256::new()
        .chain(&_parent)
        .chain(&_nonce)
        .chain(&_values)
        .result();

    _id = format!("{:x}", sha);
    if _id[.._limit] == _prefix {
        break;
    }
}

Let’s Try It!

Status

  • Compile
  • Fast
  • Lightweight
  • Linear Memory w/ TypedArray

Comming Soon

  • Multi-threading
  • Streaming compilation/Tiered Compiler
  • JS Modules exchange/Garbage Collector
  • Portability/Runtime/IoT
  • WASI

Know The Web!

  • HTML/DOM → Interfaces
  • CSS → Layouts/Style
  • JS → UI Thread
  • WASM → Background Processes
m4dz's avatar
m4dz

Paranoïd Web Dino · Tech Evangelist

alwaysdata logo
https://www.alwaysdata.com

Questions?

Thank You!


Available under licence CC BY-SA 4.0

Illustrations

m4dz, CC BY-SA 4.0

Interleaf images

Courtesy of Unsplash and Pexels contributors

Icons

  • Layout icons are from Entypo+
  • Content icons are from FontAwesome

Fonts

  • Cover Title: Sinzano
  • Titles: Argentoratum
  • Body: Mohave
  • Code: Fira Code

Tools

Powered by Reveal.js

Source code available at
https://git.madslab.net/talks