lukewagner.github.io/wasm-talk-2017
Luke Wagner / @luke_wagner
Questions welcome!
This is pretty low-level stuff; if you have a question, chances are everyone else does too!
Mozilla Firefox/SpiderMonkey hacker for 8 years
![]() |
![]() |
![]() |
![]() |
![]() |
Member of WebAssembly W3C Community Group
An emerging standard which defines:
Multiple valid ways to look at WebAssembly:
Depends on where you are coming from
Not a programming language
Compile from programming languages
As close to real CPUs as safety/portability allow
WebAssembly doesn't change the security model of the Web
Pointers are checked indices, not raw addresses
Memory access is like JS array access: out-of-bounds throws
Changing browser/version/device shouldn't break things
Just like upgrading your x86 CPU shouldn't break things
So WebAssembly specifies everything*
| WebAssembly | x86/x64 | ARM/ARM64 | |
|---|---|---|---|
i32.add |
↦ | addl |
ADD |
call |
↦ | call |
BL |
i32.load |
↦ | check + mov |
check + LDR |
| infinite stack/locals | ↦ | 8/16 registers | 16/32 registers |
asm.js is an extraordinarily optimizable, low-level subset of JavaScript that can be compiled from languages like C/C++.
Because it's just JavaScript, runs well on all browsers today.
Special optimizations added to Firefox, Edge and Chrome.
Safari includes asm.js in their JetStream benchmark.
How do you get asm.js?
C/C++ ⇒ clang/LLVM ⇒ Emscripten ⇒ asm.js
| 2009 - 2012 |
Mozilla Research experiments: Emscripten: C/C++ to JS compiler/toolchain asm.js: optimize Emscripten-style output |
| 2013 - 2014 | Published asm.js subset, shipped optimizations in Firefox, demonstrated on large game engines |
| 2015 - 2016 |
Other browsers add optimizations Adobe, AutoDesk, Epic, Facebook, Mega, Unity, and more shipping with Emscripten/asm.js Cross-browser work begins on WebAssembly |
Why are developers using asm.js?
Why wasn't asm.js enough?
WebAssembly as binary encoding of asm.js (with tweaks)
| asm.js | WebAssembly | |
|---|---|---|
(x+y)|0 |
↦ | i32.add |
| ☹ | ↦ | i64.add |
f()|0 |
↦ | call |
HEAP32[i>>2]|0 |
↝ | i32.load |
raw: WebAssembly is ~42% smaller
gzipped: WebAssembly is ~23% smaller
Decoding WebAssembly ~10x faster than parsing JS
Ability to efficiently load large code +
predictable near-native performance =
Powerful JavaScript library-building tool
What sort of libraries? Today, using asm.js:
Tomorrow: Web Frameworks!
What?!! But it's all DOM and strings and stuff!
Not anymore: virtual DOM, reconciliation, bytecode VMs, ...
From Tom Dale's 2017 JSConf.eu talk
From Lin Clark's 2017 ReactEurope talk

WebAssembly is being specified and shipped iteratively
What's released today is the Minimum Viable Product (MVP)
There is a lot more to do: standard and toolchain
Speculative features are marked with ☃
Today, WebAssembly primarily compiled from C/C++:
C/C++ ⇒ clang/LLVM ⇒ Emscripten ⇒ WebAssembly
Ongoing work on:
Start with some C code:
// demo.c
MODULE_EXPORT
int add(int lhs, int rhs) {
return lhs + rhs;
}
then compile to wasm:
☃ clang-wasm demo.c -o demo.wasm
Render the binary as text:
$ wasm2wat demo.wasm | less
(module
(func (export "add") (param i32 i32) (result i32)
get_local 0
get_local 1
i32.add
)
)
Tour of opcodes out of scope, see draft spec
Compile the .wasm using JS WebAssembly API
fetch('demo.wasm').then(response =>
response.arrayBuffer()
).then(bytecode =>
WebAssembly.instantiate(bytecode)
).then(({instance}) =>
alert("1 + 2 = " + instance.exports.add(1, 2));
);
wasm:// URL appearStandardized and coming soon:
WebAssembly.instantiate(fetch('demo.wasm')).then(({instance}) =>
alert("1 + 2 = " + instance.exports.add(1, 2));
);
Allows browser to do streaming and caching
☃ ES Module integration:
WebPack integration starting
Lot more work to do here to integrate with modular workflow!
WebAssembly can call JavaScript too!
// main.c
// Think: import {printInt} from 'logger';
extern MODULE_IMPORT("logger") void printInt(int);
int main() {
printInt(42);
}
JS functions are imported (just as with an ES Module)
☃ With ES Module integration, we could write:
// logger.js
export var printInt = i => console.log(i);
Today, pass in JS function using the WebAssembly API:
function printInt(i) { console.log(i) }
WebAssembly.instantiate(fetch('main.wasm'), {logger:{printInt}});
What we really want to see is the source language
Source Maps actually map naturally onto WebAssembly
Still need to add mappings for variable names
More work to do here...
What APIs look like on a traditional VM:
The Web started out different:
But the Web has changed a lot since then
and is starting to resemble a traditional virtual platform
... with some special "Webby" properties like:
So where does WebAssembly fit in?
Today, WebAssembly only gets to Web APIs by "thunking" through JavaScript
Emscripten maps common C/C++ interfaces to Web APIs:
#include <SDL/SDL.h>
#include <stdio.h>
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Surface *s = SDL_SetVideoMode(200, 200, 32, SDL_HWSURFACE);
SDL_Rect rect = { 50, 50, 100, 100 };
SDL_FillRect(s, &rect, 0xffff0000);
printf("Done!\n");
return 0;
}
Compiled by Emscripten with:
emcc -O2 test.c -o test.html
Which produces a default HTML harness:
☃ In the future, import and call Web APIs directly from WebAssembly
Currently, WebAssembly only has linear memory
Great if your language has a low-level memory model (C++, Rust, FORTRAN)
But if your language has GC:
To provide first-class support for GC languages, WebAssembly needs direct GC access
☃ Goal: add low-level GC primitives to avoid baking in one language's class model
☃ Goal: share GC heap with JS, allow objects/strings/values to flow back and forth
Follow on GitHub GC proposal repo
☃☃ So what could you do with GC support? ☃☃
Need even more features in WebAssembly to run dynamic languages efficiently:
dynamic/any-typePrecedent with invokedynamic in the JVM
☃☃ But this is all rather far off ☃☃
No. Why?
In fact, WebAssembly may have quite the opposite effect:
If you're going to target WebAssembly and your app needs a scripting language, JS is a natural choice...
Sure, if you want to go slower
...theoretically you could get a startup win by shipping your own bytecode + JS interpreter...
Find out more at webassembly.org
Lin Clark has an awesome blog post and JSConf.eu talk introducing WebAssembly
Slides at lukewagner.github.io/wasm-talk-2017