Upgrade to Pro — share decks privately, control downloads, hide ads and more …

20210825_ossx

chikoski
September 16, 2021

 20210825_ossx

chikoski

September 16, 2021
Tweet

More Decks by chikoski

Other Decks in Technology

Transcript

  1. プラグインとしての WebAssembly
    chikoski@

    View full-size slide

  2. WebAssembly (Wasm)の概観
    プラグインシステムの基礎技術としての Wasm
    Outline

    View full-size slide

  3. カテゴリー 利用例 説明
    Web アプリ Acrobat PDF 編集ツール
    Autocad CAD
    Lightroom 画像編集
    Squoosh 画像圧縮、変換ツール
    Zoom ビデオミーティング
    サーバーレス環境 Cloudflare Workers
    Compute@Edge
    Envoy Service Proxy
    Istio Service mesh。Envoy を利用
    Krustlet Kubernetes 上で動く Wasm 実行環境

    View full-size slide

  4. エコシステム パフォーマンス

    View full-size slide

  5. ● Shopify App
    ● Microsoft Flight Simulator
    ● Envoy / Proxy-Wasm
    ● Vector by Datadog
    プラグイン としての Wasm

    View full-size slide

  6. Shopify
    “Shopify is a subscription-based
    software that allows anyone to set
    up an online store and sell their
    products”, What is Shopify

    View full-size slide

  7. https://shopify.dev/apps/getting-started

    View full-size slide

  8. https://shopify.engineering/shopify-webassembly

    View full-size slide

  9. Performance × Flexibility × Security
    ・サーバー内での実行
    ・ネイティブコードの事前生成
    ・生成したコードのキャッシュ
    ・プログラムなのでユースケースを広くカバー
    ・いろんな言語で実装可能
    ・メモリ保護
    ・安全な実行コードの生成
    ・アイソレーション

    View full-size slide

  10. WebAssembly 101

    View full-size slide

  11. コンパイラターゲット

    View full-size slide

  12. 0061736D01000000010A026000006002
    7F7F017F030302000104050170010101
    05030100020615037F01418088040B7F
    00418088040B7F004180080B072B0406
    6D656D6F727902000B5F5F686561705F
    6261736503010A5F5F646174615F656E
    6403020361646400010A0C0202000B07
    00200120006A0B0020046E616D650119
    0200115F5F7761736D5F63616C6C5F63
    746F72730103616464
    #define WASM_EXPORT
    __attribute__((visibility("default")))
    WASM_EXPORT
    int add(int a, int b) { return a + b; }
    #[no_mangle]
    pub extern
    fn add(x: i32, y: i32) -> i32 { x + y }
    export function add(x: i32, y: i32): i32 {
    return x + y;
    }

    View full-size slide

  13. 0061736D01000000010A026000006002
    7F7F017F030302000104050170010101
    05030100020615037F01418088040B7F
    00418088040B7F004180080B072B0406
    6D656D6F727902000B5F5F686561705F
    6261736503010A5F5F646174615F656E
    6403020361646400010A0C0202000B07
    00200120006A0B0020046E616D650119
    0200115F5F7761736D5F63616C6C5F63
    746F72730103616464
    (module
    (type $t0 (func))
    (type $t1 (func (param i32 i32) (result i32)))
    (func $__wasm_call_ctors (type $t0))
    (func $add (export "add") (type $t1)
    (param $p0 i32) (param $p1 i32) (result i32)
    get_local $p1
    get_local $p0
    i32.add)
    (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)))

    View full-size slide

  14. スタックベースの仮想マシン

    View full-size slide

  15. 1 + 2 + 3 = ? i32.const 1
    i32.const 2
    i32.const 3
    i32.add
    i32.add

    View full-size slide

  16. 1 + 2 + 3 = ? i32.const 1
    i32.const 2
    i32.const 3
    i32.add
    i32.add
    1

    View full-size slide

  17. 1 + 2 + 3 = ? i32.const 1
    i32.const 2
    i32.const 3
    i32.add
    i32.add
    1
    2

    View full-size slide

  18. 1 + 2 + 3 = ? i32.const 1
    i32.const 2
    i32.const 3
    i32.add
    i32.add
    1
    2
    3

    View full-size slide

  19. 1 + 2 + 3 = ? i32.const 1
    i32.const 2
    i32.const 3
    i32.add
    i32.add
    1
    5

    View full-size slide

  20. 1 + 2 + 3 = ? i32.const 1
    i32.const 2
    i32.const 3
    i32.add
    i32.add
    6

    View full-size slide

  21. 関数定義と関数呼び出し (i32.const 2)
    (i32.const 1)
    (call $add)
    (func $add
    (param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p0
    local.get $p1
    i32.add)

    View full-size slide

  22. 関数定義と関数呼び出し (i32.const 2)
    (i32.const 1)
    (call $add)
    (func $add
    (param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p0
    local.get $p1
    i32.add)
    2

    View full-size slide

  23. 関数定義と関数呼び出し (i32.const 2)
    (i32.const 1)
    (call $add)
    (func $add
    (param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p0
    local.get $p1
    i32.add)
    2
    1

    View full-size slide

  24. 関数定義と関数呼び出し (i32.const 2)
    (i32.const 1)
    (call $add)
    (func $add
    (param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p0
    local.get $p1
    i32.add)
    2
    1

    View full-size slide

  25. 関数定義と関数呼び出し (i32.const 2)
    (i32.const 1)
    (call $add)
    (func $add
    (param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p0
    local.get $p1
    i32.add)
    3

    View full-size slide

  26. 関数定義と関数呼び出し (i32.const 2)
    (i32.const 1)
    (call $add)
    (func $add
    (param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p0
    local.get $p1
    i32.add)
    3

    View full-size slide

  27. 線形メモリー

    View full-size slide

  28. 線形メモリー
    ● バイト単位でのアクセス
    ● ページ単位でメモリを増やせる
    ● 1ページ = 64KiB 単位
    ● data section で初期状態を記述
    64KiB
    最大サイズは
    実行時に指定可

    View full-size slide

  29. pub struct Item{
    pub id: u32,
    pub price: i32,
    }
    #[no_mangle]
    pub extern
    fn add(item_a: &Item,
    item_b: &Item) -> i32 {
    item_a.price + item_b.price
    }
    (func $add
    ($param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p1
    i32.load offset=4
    local.get $p0
    i32.load offset=4
    i32.add)

    View full-size slide

  30. (func $add
    ($param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p1
    i32.load offset=4
    local.get $p0
    i32.load offset=4
    i32.add)
    1 0 0 0 10 0 0 0
    2 0 0 0 2 3 0 0
    0
    8
    メモリー
    スタック

    View full-size slide

  31. (func $add
    ($param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p1
    i32.load offset=4
    local.get $p0
    i32.load offset=4
    i32.add)
    1 0 0 0 10 0 0 0
    2 0 0 0 2 3 0 0
    0
    8
    メモリー
    スタック
    0

    View full-size slide

  32. (func $add
    ($param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p1
    i32.load offset=4
    local.get $p0
    i32.load offset=4
    i32.add)
    1 0 0 0 10 0 0 0
    2 0 0 0 2 3 0 0
    0
    8
    メモリー
    スタック
    10

    View full-size slide

  33. (func $add
    ($param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p1
    i32.load offset=4
    local.get $p0
    i32.load offset=4
    i32.add)
    1 0 0 0 10 0 0 0
    2 0 0 0 2 3 0 0
    0
    8
    メモリー
    スタック
    10
    8

    View full-size slide

  34. (func $add
    ($param $p0 i32)
    (param $p1 i32)
    (result i32)
    local.get $p1
    i32.load offset=4
    local.get $p0
    i32.load offset=4
    i32.add)
    1 0 0 0 10 0 0 0
    2 0 0 0 2 3 0 0
    0
    8
    メモリー
    スタック
    10
    770

    View full-size slide

  35. ● コンパイルによって作られる
    関数定義のまとまり
    ● 仮想マシン向けの命令セット
    ● 線形メモリー
    Wasm ファイル
    https://rsms.me/wasm-intro

    View full-size slide

  36. Wasm ファイルを実行するには

    View full-size slide

  37. const stream = await fetch('some.wasm');
    const wasmFile = await stream.arrayBuffer();
    const instance = WebAssembly.instantiate(wasmFile);
    const value = instance.exports.add(1, 2);

    View full-size slide

  38. Ahead of time コンパイル
    x86
    ARM
    インタープリター
    Just in time コンパイル
    x86
    ARM

    View full-size slide

  39. const wasm = WebAssembly.instantiate(wasmFile);
    const memory =
    new Uint32Array(wasm.exports.memory.buffer);
    memory[0] = 0; // id for the first item
    memory[1] = 10; // price of the first item
    memory[8] = 2; // id for the first item
    memory[9] = 770; // the second item’s price
    wasm.exports.add(0, 8);

    View full-size slide

  40. #[wasm_import_module = "mod"]
    extern{
    fn discount() -> u32;
    }
    #[no_mangle]
    pub extern
    fn price(item: &Item) -> u32{
    unsafe{
    item.price - discount()
    }
    }
    (import "mod" "discount"
    (func $discount (type $t2)))
    (func $price (export "price")
    (type $t0)
    (param $p0 i32)
    (result i32)
    local.get $p0
    i32.load offset=4
    call $discount
    i32.sub)

    View full-size slide

  41. const imports = {
    mod: {discount: () => 50}
    };
    const wasm = WebAssembly.instantiate(wasmFile, imports);
    const memory =
    new Uint32Array(wasm.exports.memory.buffer);
    memory[8] = 2; // id for the first item
    memory[9] = 770; // the second item’s price
    wasm.exports.price(8); // returns 720

    View full-size slide

  42. ● インスタンス化が必要
    ● export
    ○ ホスト側に参照できる値
    ○ メモリーも export できる
    ● import
    ○ ホスト側から与えられる値
    ○ メモリーも与えられる
    Wasm の実行
    https://rsms.me/wasm-intro

    View full-size slide

  43. プラグインシステムの基盤としての Wasm

    View full-size slide

  44. ● プラグインとは第三者のコード
    ○ Security vs flexibility
    ○ 信頼の実現は難しい
    ● 安全にコードを実行するには
    ○ サンドボックス内での実行
    ○ 安全なコードの生成
    ● 信頼できないコードの実行を
    考慮して設計されている
    1 0 0 0 10 0 0 0
    2 0 0 0 2 3 0 0
    0
    8
    第三者のコードの実行
    x86
    ARM

    View full-size slide

  45. https://rsms.me/wasm-intro
    API

    View full-size slide

  46. https://rsms.me/wasm-intro
    Hook / callback

    View full-size slide

  47. API とコールバックの意味を定めることで、
    拡張機能を Wasm で実装できるようになる

    View full-size slide

  48. Microsoft Flight Simulator SDK Documentation

    View full-size slide

  49. WebAssembly in Envoy Proxy-Wasm vNEXT ABI specification

    View full-size slide

  50. API の設計以外に気をつけることは?

    View full-size slide

  51. 1. バージョン
    2. データ表現

    View full-size slide

  52. Wasm には追加の仕様があります
    https://webassembly.org/roadmap/ https://github.com/WebAssembly/proposals

    View full-size slide

  53. https://rsms.me/wasm-intro
    1で固定

    View full-size slide

  54. 対応する仕様の明示
    ● 策定中の仕様が多く存在
    ● Wasm にはバージョンがない
    ● 対応する仕様を明示することで、動
    作確認の手間を減らせる
    https://webassembly.org/roadmap/

    View full-size slide

  55. ● i32, i64, f32, f64 については規定がある
    ● それ以外は規定がない
    ○ 配列、リスト
    ○ 文字、文字列
    ○ レコード(構造体、共用体)
    ● 線形メモリ上に、なんとかして置いている
    → 置き方は処理系に任せられている。
    データ表現に関する規定があまりない

    View full-size slide

  56. バージョン名を返すAPIを例に考えると
    extern char* get_version_code();
    void do_something(){
    char *code = get_version_code();
    if (strncmp("pre", code, 3)){
    work_with_prelease();
    }else{
    work();
    }
    }
    (type $t0 (func (result i32)))
    (import "env" "get_version_code"
    (func $get_version_code (type $t0)))

    View full-size slide

  57. extern {
    fn get_version_code() -> String;
    }
    fn do_something(){
    unsafe{
    if get_version_code() == "pre"{
    work_with_prerelease();
    }else{ work(); }
    }
    }
    バージョン名を返すAPIを例に考えると
    (type $t3 (func (param i32)))
    (import "env" "get_version_code"
    (func $get_version_code (type $t3)))

    View full-size slide

  58. 文字列の表現が異なる
    H e l l o , w o r l d ! \0
    H e l l o , w o r l d !
    0
    0
    表現A:(0)
    表現B:(0, 12)
    0 12

    View full-size slide

  59. グルーコードが必要
    H e l l o \0
    8 5
    H e l l o

    View full-size slide

  60. char* id(char* value) {
    return value;
    }
    (type $t1
    (func (param i32) (result i32)))
    (func $id (export "id")
    (type $t)
    (param $p0 i32) (result i32)
    local.get $p0)

    View full-size slide

  61. #[no_mangle]
    pub extern
    fn id(value: &str) -> &str{
    value
    }
    (type $t2
    (func (param i32 i32 i32)))
    (func $id (export "id") (type $t2)
    (param $p0 i32) (param $p1 i32)
    (param $p2 i32)
    local.get $p0
    local.get $p2
    i32.store offset=4
    local.get $p0
    local.get $p1
    i32.store)

    View full-size slide

  62. データ表現の数だけ
    API が必要
    ● サポートする言語が
    (type $t1
    (func (param i32) (result i32)))
    (type $t2
    (func (param i32 i32 i32)))

    View full-size slide

  63. ● 策定中の仕様で、次の 3 つが目的
    ○ Language neutral なインターフェイスの定義を可能にする
    ○ Web API 呼び出しの最適化
    ○ Wasm モジュールの再利用性の向上
    ● 内容
    ○ Interface type の定義
    ○ Adapter
    ○ Lifting and Lowering Instructions
    Interface Types

    View full-size slide

  64. 言語ごとにライブラリを提供することも必要
    Microsoft Flight Simulator: Platform toolset WebAssembly for Proxies (ABI specification)

    View full-size slide

  65. ● さまざまなユースケースに対応できる
    ● サンドボックス化による安全性の確保できる
    ● 手に馴染んだ言語が使え、開発者体験の向上が期待できる
    ○ 勉強のコストを減らす可能性が高い
    ○ 既存資産を、少ない手間で利用できる
    → エコシステムの面で有利になりうる
    プラグインシステムに Wasm を採用すると

    View full-size slide