WASM?

Le navigateur est une vraie VM

@m4d_z
alwaysdata
C'était déjà à Codeurs En Seine, il y a longtemps

JS et le Web en 6 dates
(et une bonus)

  • 2001: Prototype, Scriptaculo·us, Mootools
  • 2005: jQuery
  • 2010: SPA / Backbone
  • 2012: Angular
  • 2015: virtual-dom, React, Vue.js
  • 2018: PWA
  • 2020: Ça va vous, la RAM ? 🤮

On développe des
(Progressive Web) Apps!

What Do We Need?

La plateforme Web est déjà
une machine virtuelle

  • PWA
  • Electron / NodeGUI
  • NativeScript / ReactNative
  • Tessel

On veut :

  • Un environnement sécurisé
  • Une exécution rapide
  • Un code métier portable et partagé

WASM

  • Format compilé
  • LLVM → WASM
  • Chargé via JS (glue code)
  • Exécuté dans le navigateur
  • Multi-plateforme
    (serveur, IoT, etc)

Webassembly: Origins

JS est lent
(bah oui, quand même)

ASM.js : l’expérience

  • Sous-ensemble JavaScript
  • Très optimisé, mais très contraint
  • Très complexe à écrire manuellement
function increment(x) {
  x = x|0;
  return (x + 1)|0;
}

Il va falloir compiler !

Emscripten

  • Toolchain
  • Compile depuis C/C++
  • Utilise LLVM
$ emcc hello_world.c
$ tree
.
├── a.out.html
└── a.out.js
$ node a.out.js
Hello World!

Et si on pouvait compiler
toute notre codebase Web ?

WebAssembly is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.

WASM Binary Format

0061 736d
0100 0000
0100 01
6002
7f7f
017f 07
0300 01
0002
0700 0103
6164 64
0000 07
0a00 0100
00
2000 2001
6a0b 0709
0000 04
6e61 6d65

WASM Text Format

(module
  (func (export "add") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add))

Problème :
WASM est en MVP

🍀 static types

  • 2 Integers
  • 2 Floats

Rust Do it!

WASM Rust Hello World, Web version

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

Pourquoi Rust ?

  • C++, non merci, j’ai qu’un cerveau de dispo
  • Pas de data-race
  • Types statiques
  • Iterators
  • Gestion mémoire 👌
  • Communauté 😍
  • Toolchain (Rustup, Cargo, Rustc…)

Modules By Design

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

Compiler pour le Web

Modules WASM

  • Headers → Déclaratifs
  • Statique → Déterministes
  • Types forts → Runtime Error Proof

Le modèle de sécurité

  • Exécution en sandbox, par module
  • Exécution déterministe
  • Control-Flow Integrity
  • Controle des Type Signature sur les appels indirects
  • Memory Safety

Instanciation

const importObject = {
  imports: {
    alert: window.alert
  }
};

WebAssembly
  .instantiateStreaming(fetch('greeter.wasm'), importObject)
  .then(mod => mod.instance.exports.greet('Hello World'));

Souviens-toi l’été dernier,
WASM : que des nombres !

Strings ?
💩TF-8

Un nombre, ça peut être…
un pointeur mémoire !

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, … ]
Faut faire ça... à la main ?

wasm-pack

📦✨ your favorite rust -> wasm workflow tool!

Package

$ cd my-module
$ wasm-pack build --target web --release

Publication vers les registres (NPM…)

$ tree
├── bridge.js
├── Cargo.toml
├── pkg
│   ├── my-module_bg.d.ts
│   ├── my-module_bg.wasm
│   ├── my-module.d.ts
│   ├── my-module.js
│   ├── package.json
│   └── snippets
│       └── my-module-91b01578bc1ce6c0
│           └── bridge.js
└── src
    └── lib.rs

wasm-bindgen

Facilitating high-level interactions between wasm modules and JavaScript.

  • Librairie Haut-niveau
  • Expose
    • Web sys (DOM, window, document, fetch, canvas…)
    • JS sys (passing values, types, boxing…)
    • Promises
  • Génère les bindings TypeScript
use wasm_bindgen::prelude::*;

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

#[wasm_bindgen(module = "/bindings.js")]
extern "C" {
    fn updateState(state: &JsValue);
}

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

    let state = State { name }
    updateState(JsValue::from_serde(&state).unwrap());
}

Embind pour C/C++

Embind is used to bind C++ functions and classes to JavaScript, so that the compiled code can be used in a natural way by JavaScript.

Le Graal de la VM

Les promesses de WebAssembly

  1. Exécution rapide
  2. Environnement sécurisé
  3. Code portable

Rapidité :

Stack Based VM

Stack based vs. Register based

  • Register: proche du fonctionnement CPU,
    puissante mais complexe
  • Stack: flexible,
    légère

→ JVM, CLR &… JS JIT: Stack Based VM

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

Assembleur !

PUSH 1
PUSH 2
PUSH 3
MUL
ADD
PUSH 7
DIV

WASM utilise le même moteur JS

  • échanges ultra-rapides avec JS
  • unboxing
  • monomorphic calls
  • built-ins methods

Portabilité

WASM ce n'est pas que pour le navigateur

Wasmtime

  • Modules bas-niveau pour tous les interpréteurs
    (bye bye node-gyp)
  • Sandbox native pour tous les langages
  • write once, run everywhere

System Interface

  • Abstraction System Calls
  • Émulation du Runtime JS
    (glue code / navigateur)
  • Sécurité

La portabilité, c’est

  • Une seule cible de compilation
  • Distribution d’un fichier unique
  • Ensemble de Standard Interfaces modulaire

Sécurité :

La sandbox pour tous !

Glue : WASM Standard Interfaces

  • Utilisation de modules nativement
  • Sandbox basée sur le runtime
  • Base de code commune

Passage de types de WASM à JS :
simple mais fastidieux

Passage de types de WASM
vers tout le reste :
on ne va pas hardcoder tous les codex !

Interface Types

  • Représentations intermédiaires
  • WASM utilise ces IR pour échanger les données
  • Typage fort, statique, et exécution déterministe partout

WASM pour la production

Production-Proof

Tu ❤ JS? Essaie AssemblyScript !

AssemblyScript compiles a strict variant of TypeScript to WebAssembly using Binaryen.

export function fib(n: i32): i32 {
  var a = 0, b = 1
  if (n > 0) {
    while (--n) {
      let t = a + b
      a = b
      b = t
    }
    return b
  }
  return a
}

Tu fais du dev système ?
Check LLVM !

  • C / C++
  • Rust
  • C#
  • GO + TinyGO + syscall/js
  • Java

Tu fais du backend interprété ?
Interface Types ! (ou Wasmtime)

Coming Soon

  • Multi-threading
  • JS Modules exchange/Garbage Collector
  • IR/IoT
  • CPU SIMD
$ wasmer run cowsay.wasm Hello World!
 ________________
< Hello World! >
 ----------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
               ||----w |
                ||     ||

The Future of FaaS

$ curl --location --request POST 'https://[::]/api/executables' \
--header 'Content-Type: application/octet-stream' \
--header 'SSVM_Description: say hello' \
--data-binary 'pkg/hello_lib_bg.wasm'
$ curl --location --request POST 'https://[::]/api/run/123/say' \
--header 'Content-Type: text/plain' \
--data-raw 'World'

Hello World!

Open Standard
→ Construisons l’écosystème

Know The Web!

  • HTML/DOM → Interfaces
  • CSS → Layouts/Style
  • JS → UI Thread
  • WASM → Tâches de fond et code métier
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