Web assembly

16 януари 2020

Web assembly

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.

Източник: https://webassembly.org

Компилация на rust до wasm

Компилация на rust до wasm

Компилация на rust до wasm

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Компилация на rust до wasm

Крос компилация

Пример 1

Rust до Wasm

Cargo.toml

1 2
[lib]
crate-type = ["cdylib"]

Пример 1

Rust до Wasm

src/lib.rs

1 2 3 4
#[no_mangle]
pub fn add(a: u32, b: u32) -> u32 {
    a + b
}

Пример 1

Rust до Wasm

1
cargo build --release --target wasm32-unknown-unknown

Това ше генерира target/wasm32-unknown-unknown/release/example_01.wasm

Пример 1

Изпълняване в уеб браузър

Пример 1

Изпълняване в уеб браузър

Пример 1

Изпълняване в уеб браузър

Пример 1

Изпълняване в уеб браузър

Пример 1

Изпълняване в уеб браузър

Сървъра ще връща следните файлове:

1 2
cp target/wasm32-unknown-unknown/release/example_01.wasm \
    pkg/wasm_lib.wasm

Пример 1

Изпълняване в уеб браузър

index.html

1 2 3 4 5 6 7 8 9 10
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello wasm!</title>
  </head>
  <body>
    <script src="./index.js" type="module"></script>
  </body>
</html>

Пример 1

Изпълняване в уеб браузър

index.js

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
const response = fetch('./pkg/wasm_lib.wasm')

response
    .then(r => r.arrayBuffer())
    .then(bytes => WebAssembly.instantiate(bytes, {}))
    .then(({instance, module}) => {
        return instance.exports;
    })
    .then(wasm => {
        // През `wasm` можем да достъпваме функциите които
        // сме дефинирали в нашата библиотека.
        //
        // Но не знаем каква е "calling конвенцията" затова
        // не знаем как правилно да ги извикаме.
        //
        // Единствено функции които приемат и връшат само
        // числа ще работят *почти* както очакваме.
        console.log(wasm.add(1, 2))

        // Това няма да работи както очакваме - ще получим
        // `-3` вместо `-3 as u32`
        console.log(wasm.add(-1, -2))
    })

Wasm-bindgen

Wasm-bindgen

Wasm-bindgen

Wasm-bindgen

Пример 2

Wasm-bindgen

Cargo.toml

1 2 3 4 5
[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "*"

Пример 2

Wasm-bindgen

src/lib.rs

1 2 3 4 5 6 7 8
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn add(a: u32, b: u32) -> u32 {
    a + b
}

// повече примери на демото

Пример 2

Wasm-bindgen

1 2 3 4 5
cargo build --release --target wasm32-unknown-unknown

wasm-bindgen target/wasm32-unknown-unknown/release/wasm_lib.wasm \
    --out-dir pkg \
    --target web

Пример 2

Wasm-bindgen

index.js

1 2 3 4 5 6 7
import init from './pkg/wasm_lib.js'
import { add } from './pkg/wasm_lib.js'

init('pkg/wasm_lib_bg.wasm')
    .then(wasm => {
        console.log(add(1, 2));
    })

Пример 2

Примери от демото

src/lib.rs

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
use serde_derive::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;

/// Връща поздрав.
///
/// Този коментар се вижда в генерирания js wrapper.
#[wasm_bindgen]
pub fn greet() -> String {
    "hello wasm".to_string()
}

#[wasm_bindgen]
pub fn add(a: u32, b: u32) -> u32 {
    a + b
}

#[wasm_bindgen]
pub fn sub(a: i32, b: i32) -> i32 {
    a - b
}

#[wasm_bindgen]
pub fn len_64(s: String) -> u64 {
    s.len() as u64
}

// `wasm_bindgen` атрибута позволява да подаваме структурата
// на JS код като opaque тип, т.е. указател
//
// `Serialize, Deserialize` идват от библиотеката `serde`
#[wasm_bindgen]
#[derive(Debug, Serialize, Deserialize)]
pub struct User {
    name: String,
    age: u32,
}

// В този случай `User` е opaque type
#[wasm_bindgen]
pub fn user_info(user: User) -> String {
    format!("{:?}", user)
}

// В този случай `User` е opaque type
#[wasm_bindgen]
pub fn gosho() -> User {
    User {
        name: "Гошо".to_string(),
        age: 11,
    }
}

// в този случай се използва `#[derive(Deserialize)]`
#[wasm_bindgen]
pub fn js_user_info(user: JsValue) -> String {
    // Извиква `JSON.stringify` върху `user` и след това
    // го десериализира до структура
    user_info(user.into_serde().unwrap())
}

// в този случай се използва `#[derive(Serialize)]`
#[wasm_bindgen]
pub fn js_gosho() -> JsValue
{
    // Сериализира структурата до JSON и я подава на JS,
    // където ще се десериализира до JS обект
    JsValue::from_serde(&gosho()).unwrap()
}

Пример 2

Примери от демото

index.js

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
import init from './pkg/wasm_lib.js'
import { add, greet, len_64, user_info, gosho, js_user_info, js_gosho, User } from './pkg/wasm_lib.js'

function try_catch(id, fn) {
    try {
        fn()
    } catch (e) {
        console.log(id, e);
    }
}

init('pkg/wasm_lib_bg.wasm')
    .then(_ => {
        console.log("greet", greet());

        // 4294967293
        console.log("add0", add(-1, -2));
        // 12
        console.log("add1", add(12));
        // 0
        console.log("add2", add("still", "php?"));

        // 3n
        console.log("len_64", len_64("asd"));

        // { ptr: 1114136 }
        console.log("gosho0", gosho());
        // "User { name: \"Гошо\", age: 11 }"
        console.log("gosho1", user_info(gosho()));
        // Error: "expected instance of User"
        try_catch("gosho2", () => user_info({ name: "Гошо", age: "11" }))
        // Error: "expected instance of User"
        try_catch("gosho3", () => user_info({ ptr: 123456 }))
        // User { name: "", age: 0 }    // Undefined behaviour i guess
        console.log("gosho4", user_info(User.__wrap(123456)))

        // "User { name: \"Гошо\", age: 11 }"
        console.log("js_gosho0", js_user_info({ name: "Гошо", age: 11 }));
        // "User { name: \"Гошо\", age: 11 }"  // the power of serde
        console.log("js_gosho1", js_user_info(["Гошо", 11]));
        // RuntimeError: "unreachable executed"
        try_catch("js_gosho2", () => js_user_info({ name: "Гошо", age: "11" }))
        // RuntimeError: "unreachable executed"
        try_catch("js_gosho3", () => js_user_info('{name: "Гошо", age: "11"}'))
        // { name: "Гошо", age: 11 }
        console.log("js_gosho4", js_gosho());
    });

Wasm pack

Wasm pack

Wasm pack

Wasm pack

Wasm pack

Оптимизиране за малък размер

Web assembly извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб намира и други приложения.

Web assembly извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб намира и други приложения.
Web assembly като формат притежава някои много удобни свойства:

Web assembly извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб намира и други приложения.
Web assembly като формат притежава някои много удобни свойства:

Web assembly извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб намира и други приложения.
Web assembly като формат притежава някои много удобни свойства:

Web assembly извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб намира и други приложения.
Web assembly като формат притежава някои много удобни свойства:

Web assembly извън браузъра

Въпреки, че wasm е създаден с идеята да се използва за уеб намира и други приложения.
Web assembly като формат притежава някои много удобни свойства:

Web assembly извън браузъра

С две думи е подходящ ако имаме някаква система върху която искаме да позволим на потребители да изпълняват произволен код.

If WASM+WASI existed in 2008…

Web assembly извън браузъра

Няколко презентации

Rust, WebAssembly, and the future of Serverless by Steve Klabnik
https://www.youtube.com/watch?v=CMB6AlE1QuI

Bringing WebAssembly outside the web with WASI by Lin Clark
https://www.youtube.com/watch?v=fh9WXPu0hw8

Watt

Watt

Watt

WAT

Въпроси