A Taste Of WASM
The Browser as a Virtual Machine
@m4d_zhttps://talks.m4dz.net/a-taste-of-wasm/en/Remember
Three main reasons:
Emscripten
asm.js
(optimized JS sub-part)
JS:
async && event-driven
Single-threaded
setTimeout({...}, 0)
Concurrency:
WebWorker, ServiceWorkers
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
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
WASM
Stack based vs. Register based
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
At start:
JIT Compiler produces
machine code instructions
fastly, but is limited
WASM uses the same Engine
Execution Engine able to
run all logic languages
directly on the Web!
Why Rust? :
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!
Fantastic Four!
Open Standard
WASM Rust Hello World on the Web
pub fn greet(name: &str) {
alert(&format!("Hey! {}!", name));
}
xx
Execution timeline
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
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, … ]
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:
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!
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!
Status
TypedArray
Server Side
What about the Security?
Comming Soon
Paranoïd Web Dino · Tech Evangelist
https://talks.m4dz.net/a-taste-of-wasm/en/ Available under licence CC BY-SA 4.0
m4dz, CC BY-SA 4.0
Courtesy of Unsplash and Pexels contributors
Powered by Reveal.js
Source code available at
https://git.madslab.net/talks