What if I told you…
…you can run code in your browser at near-native speeds… (WITHOUT PLUGINS)
…and use the language of your choice? Zen Garden Demo: https://jlik.me/fzg
Bare metal webassembly🕸 Your Browser is the new OS All photographs in this deck © 2019 Jeremy Likness. All Rights Reserved. @JeremyLikness
Jeremy Likness https://blog.jeremylikness.com/ @JeremyLikness Cloud Advocate @ Microsoft Quarter Century Professional Developer 👟 Likes to “run” 🥑 99.9765% plant-based diet 🎱 Shoots pool whenever possible https://blog.jeremylikness.com/ @JeremyLikness Jeremy.Likness@microsoft.com
In the beginning … const computePrime = () => { var lastPrime = -1; for (let i = 2; i < 50000; i+=1) { let isPrime = true; for (let j = i-1; j >= 2; j-=1) { if (i % j == 0) { isPrime = false; break; } } if (isPrime) { lastPrime = i; } return lastPrime; }
Along came asm.js …
Along came asm.js … C/C++
C/C++ Clang Along came asm.js …
C/C++ Clang LLVM Along came asm.js …
C/C++ Clang LLVM Emscripten Along came asm.js …
C/C++ Clang LLVM Emscripten Asm.js Along came asm.js …
primes.c int computePrimesAsm() { int lastPrime; int i; int j; int isPrime; for (i = 2; i < 50000; i = i+1) { isPrime = 1; for (j = i-1; j >= 2; j--) { if (i % j == 0) { isPrime = -1; break; } if (isPrime == 1) { lastPrime = i; return lastPrime;
Demo https://github.com/JeremyLikness/blazor-wasm/tree/master/primes Build ASM.js Demo https://github.com/JeremyLikness/blazor-wasm/tree/master/primes
primes.js function _computePrimesAsm() { var $0 = 0, $1 = 0, $10 = 0, $11 = 0, $12 = 0, $13 = 0, $14 = 0, $15 = 0, $16 = 0, $17 = 0, $18 = 0, $19 = 0, $2 = 0, $20 = 0, $21 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0; var $8 = 0, $9 = 0, label = 0, sp = 0; sp = STACKTOP; STACKTOP = STACKTOP + 16|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abortStackOverflow(16|0); $1 = 2; while(1) { $4 = $1; $5 = ($4|0)<(50000); if (!($5)) { break; } $3 = 1; $6 = $1; $7 = (($6) - 1)|0; $2 = $7; $8 = $2; $9 = ($8|0)>=(2); if (!($9)) { $10 = $1; $11 = $2; $12 = (($10|0) % ($11|0))&-1; $13 = ($12|0)==(0); if ($13) { label = 6; break; } $14 = $2; $15 = (($14) + -1)|0; $2 = $15; if ((label|0) == 6) { label = 0; $3 = -1; $16 = $3; $17 = ($16|0)==(1); if ($17) { $18 = $1; $0 = $18; $19 = $1; $20 = (($19) + 1)|0; $1 = $20; $21 = $0; STACKTOP = sp;return ($21|0); primes.js
JavaScript vs. asm.js in Chrome
Then, in 2017 …
A Quick Look Back… Binary 1010 1101 0010 0000 1101 0000
1010 1101 0010 0000 1101 0000 $AD $20 $D0 Binary Hexadecimal A Quick Look Back… Binary 1010 1101 0010 0000 1101 0000 Hexadecimal $AD $20 $D0
1010 1101 0010 0000 1101 0000 $AD $20 $D0 LDA $D020 A Quick Look Back… Binary 1010 1101 0010 0000 1101 0000 Hexadecimal $AD $20 $D0 Assembly LDA $D020 A Quick Look Back…
A Quick Look Back…
A Quick Look Back…
primes.wasm.c int computePrimesWasm() { int lastPrime; int i; int j; int isPrime; for (i = 2; i < 50000; i = i+1) { isPrime = 1; for (j = i-1; j >= 2; j--) { if (i % j == 0) { isPrime = -1; break; } if (isPrime == 1) { lastPrime = i; return lastPrime;
Wasm is Binary, this is a textual visualization (module (type $t0 (func)) (type $t1 (func (result i32))) (func $__wasm_call_ctors (type $t0)) (func $computePrimesWasm (export "computePrimesWasm") (type $t1) (result i32) (local $l0 i32) (local $l1 i32) (local $l2 i32) (local $l3 i32) (local $l4 i32) i32.const 1 set_local $l0 i32.const 2 set_local $l1 loop $L0 get_local $l0 set_local $l2 block $B1 block $B2 loop $L3 get_local $l2 i32.lt_s br_if $B2 get_local $l1 i32.rem_s set_local $l3 i32.const -1 i32.add get_local $l3 br_if $L3 end i32.const 1 i32.add set_local $l0 get_local $l1 tee_local $l1 i32.const 50000 i32.ne br_if $L0 br $B1 end set_local $l4 get_local $l0 get_local $l4) (table $T0 1 1 anyfunc) (memory $memory (export "memory") 2) (global $g0 (mut i32) (i32.const 66560)) (global $__heap_base (export "__heap_base") i32 (i32.const 66560)) (global $__data_end (export "__data_end") i32 (i32.const 1024)))
A Quick Look at the basics Introducing WebAssembly Studio: https://webassembly.studio/
Stack-Based Programming
Stack-Based Programming get_local $lhs 2
Stack-Based Programming get_local $rhs 4 2
Stack-Based Programming i32.add 4 6 2
Wasm vs. asm.js Byte code (no pre-compilation/script parsing) Compact delivery (smaller file size) Wasm-specific instruction set (not constrained by JavaScript)
Demo https://github.com/JeremyLikness/b lazor-wasm/tree/master/primes Wasm and performance Demo https://github.com/JeremyLikness/b lazor-wasm/tree/master/primes
Wasm exposes memory via heaps Byte: 1 2 3 4 5 6 7 Value HEAP8 -1 HEAP16 -256 HEAP32 -32769 HEAPU8 128 HEAPU16 32768 HEAPU32 65537 HEAPF32 -3.1415 HEAPF64 4.669
JavaScript provides typed arrays JavaScript Array BYTES_PER_ELEMENT HEAP8 Int8Array 1 HEAP16 Int16Array 2 HEAP32 Int32Array 4 HEAPU8 Uint8Array HEAPU16 Uint16Array HEAPU32 Uint32Array HEAPF32 Float32Array HEAPF64 Float64Array 8
Two ways to allocate memory in Wasm unsigned char x[2] = 2 bytes allocated, access via HEAPU8 int x[2] = 8 bytes allocated, access via HEAP32 long x[2] = 8 bytes allocated, access via HEAP32 Wait, wuuuuut? Support for 64-bit, like winter, is coming WebAssembly application: Module.malloc(x) = x bytes allocated Module.malloc(4 * Float32Array.BYTES_PER_ELEMENT) = 32 bytes allocated as 4 floating-point numbers on HEAPF32 JavaScript:
The Chaos Game Demo https://github.com/JeremyLikness/wasm-trees
Automated Builds https://github.com/JeremyLikness/wasm-trees/blob/master/azure-pipelines.yml
Go from 2007 Statically typed and compiled language Memory safety Garbage collection Structural typing Concurrency Runtime built-in
Gophers went Wasm in 2018 “Operating System” = JavaScript “Architecture” = Wasm import “syscall/js” js.Func type Js.FuncOf for conversion js.Global() Get, Set, and Call
Demo https://github.com/Jere myLikness/plasmawasm go Plasma in go Demo https://github.com/Jere myLikness/plasmawasm go
Automated Builds https://github.com/JeremyLikness/PlasmaWasmGo/blob/master/azure-pipelines.yml
Run a 1980s vm implemented in go on wasm “Open the mailbox.” https://github.com/JeremyLikness/zmachine
A little Rust-y in 2010 C++ syntax Memory safety Most ❤ in StackOverflow for past four years (yes, there are problems with the survey) No null pointers Reference counting for memory management Explicit mutability Type ownership
Rust 🦀 ➕ WebAssembly 🕸 No runtime so smaller Wasm sizes wasm-pack for building Wasm from Rust wasm-bindgen for automated interop (both ways!) Rust 🦀 ➕ WebAssembly 🕸
Demo https://github.com/Jere myLikness/PlasmaWasm Rust Plasma in Rust Demo https://github.com/Jere myLikness/PlasmaWasm Rust
The Rust Payload https://github.com/JeremyLikness/PlasmaWasmRust/blob/master/azure-pipelines.yml
.NET …then in 2017
Wait. Why use .NET for browser apps? Modern languages (C#, F#) .NET ecosystem Performance Full-stack Tools Stable & mature
“Blazor” preview project Full-stack web development with .NET via WebAssembly No plugin or code transpilation Works in all modern browsers including mobile browsers Browser + Razor = Blazor!
@JeremyLikness
@JeremyLikness
@JeremyLikness
@JeremyLikness
@JeremyLikness
Blazor DEPENDENCY INJECTION SERVER-SIDE RENDERING COMPONENT MODEL FORMS & VALIDATION DEBUGGING PUBLISHING Blazor ROUTING LAYOUTS UNIT TESTING AUTO REBUILD ASSEMBLY TRIMMING JAVASCRIPT INTEROP INTELLISENSE & TOOLING COMPONENT PACKAGES
Demo: Blazor in action .NET on Wasm with JavaScript interactions https://github.com/JeremyLikness/blazor-wasm
Why WebAssembly? Speed Reach Accessibility Diversity
https://github.com/JeremyLikness/blazor-wasm 9/18/2019 12:01 PM https://blog.jeremylikness.com/ @JeremyLikness Jeremy.Likness@microsoft.com “No GitHub repositories were harmed in the making of this presentation.” https://github.com/JeremyLikness/blazor-wasm https://github.com/JeremyLikness/wasm-trees https://github.com/JeremyLikness/PlasmaWasmGo https://github.com/JeremyLikness/PlasmaWasmRust https://github.com/JeremyLikness/zmachine © Microsoft Corporation. All rights reserved. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.