A Taste Of WASM

The Browser as a Virtual Machine

@m4d_z
alwaysdata

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?

Three main reasons:

  • It’s Fast
  • It’s Secured
  • It’s a "Write Once, Run Everywhere"™ promise

WASM, What’s that?

Emscripten

Performances on Emscripten, a metaphor

asm.js
(optimized JS sub-part)

JS:
async && 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

Wait, this is not a language!

Myself, some time back in the days

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)
modular compiler and toolchain technologies

Why?
Because We CAN 😎 !

JS can’t address all use-cases.
We sometimes need to share a codebase between projects, a faster execution, or a more secured environment

The Browser is a Virtual Machine

  • PWA
  • Electron
  • Cordova

WASM

  • Compiled language
  • LLVM → WASM
  • Loaded using JS
  • Executed in the Browser
  • Available on the Server

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));
}

xx

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 => {
  module.instance.exports.greet('Folks')
})

4 static types

  • 2 Integers
  • 2 Floats

Problem:
I need more than numbers!

I need Strings
💩

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, … ]

Tooling!

WASM-bindgen

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

use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}
#[wasm_bindgen(module = "/bindings.js")]
extern "C" {
    fn updateState(state: JsValue);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hey! {}!", name));
}
import init from "./js_hello_world"
const module = await init("./js_hello_world_bg.wasm")
module.greet("Hello World")

Get access to:

  • Export JS fn to Rust
  • JS Types
  • Web-sys
  • JS-sys
  • Promises / Futures

WASM-pack

Compile by hand!

$ 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 Node {
  id: Sha256,
  parent: Sha256,
  nonce: number,
  records: Array<Record>
}

let blockchain: Array<Nodes>
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 {
    if node.mine(&limit, &prefix) {
        break
    }
}

pub struct Node {
    ...
}
impl Node {
    fn mine(&mut self, limit: &usize, prefix: &str) -> bool {
        let mut rng = thread_rng();
        self.records.shuffle(&mut rng);
        self.generate_nonce();
        self.generate_id();
        self.id[..*limit].eq(prefix)
    }
}

Let’s Try It!

Under the Hood

Status

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

Server Side

  • WASI
  • Interface Types
  • Binding Modules for any languages

What about the Security?

  • Sandboxed
  • Deterministic Execution w/ Limited Exceptions
  • Control-flow Integrity
  • Protected Call-stack in Linear Memory
  • Embedding Security Policies

Comming Soon

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

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?

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