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

20210825_ossx

00580f6c11851d2fff0b3e2f7392226b?s=47 chikoski
September 16, 2021

 20210825_ossx

00580f6c11851d2fff0b3e2f7392226b?s=128

chikoski

September 16, 2021
Tweet

Transcript

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

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

  3. カテゴリー 利用例 説明 Web アプリ Acrobat PDF 編集ツール Autocad CAD

    Lightroom 画像編集 Squoosh 画像圧縮、変換ツール Zoom ビデオミーティング サーバーレス環境 Cloudflare Workers Compute@Edge Envoy Service Proxy Istio Service mesh。Envoy を利用 Krustlet Kubernetes 上で動く Wasm 実行環境
  4. エコシステム パフォーマンス

  5. • Shopify App • Microsoft Flight Simulator • Envoy /

    Proxy-Wasm • Vector by Datadog プラグイン としての Wasm
  6. Shopify “Shopify is a subscription-based software that allows anyone to

    set up an online store and sell their products”, What is Shopify
  7. None
  8. https://shopify.dev/apps/getting-started

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

  10. Performance × Flexibility × Security ・サーバー内での実行 ・ネイティブコードの事前生成 ・生成したコードのキャッシュ ・プログラムなのでユースケースを広くカバー ・いろんな言語で実装可能

    ・メモリ保護 ・安全な実行コードの生成 ・アイソレーション
  11. WebAssembly 101

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

  13. 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; }
  14. 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)))
  15. スタックベースの仮想マシン

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

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

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

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

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

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

    2 i32.const 3 i32.add i32.add 6
  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)
  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
  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
  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) 2 1
  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
  27. 関数定義と関数呼び出し (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
  28. 線形メモリー

  29. 線形メモリー • バイト単位でのアクセス • ページ単位でメモリを増やせる • 1ページ = 64KiB 単位

    • data section で初期状態を記述 64KiB 最大サイズは 実行時に指定可
  30. 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)
  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 メモリー スタック
  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 メモリー スタック 0
  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
  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 8
  35. (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
  36. • コンパイルによって作られる 関数定義のまとまり • 仮想マシン向けの命令セット • 線形メモリー Wasm ファイル https://rsms.me/wasm-intro

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

  38. const stream = await fetch('some.wasm'); const wasmFile = await stream.arrayBuffer();

    const instance = WebAssembly.instantiate(wasmFile); const value = instance.exports.add(1, 2);
  39. Ahead of time コンパイル x86 ARM インタープリター Just in time

    コンパイル x86 ARM
  40. 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);
  41. #[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)
  42. 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
  43. • インスタンス化が必要 • export ◦ ホスト側に参照できる値 ◦ メモリーも export できる

    • import ◦ ホスト側から与えられる値 ◦ メモリーも与えられる Wasm の実行 https://rsms.me/wasm-intro
  44. プラグインシステムの基盤としての Wasm

  45. • プラグインとは第三者のコード ◦ Security vs flexibility ◦ 信頼の実現は難しい • 安全にコードを実行するには

    ◦ サンドボックス内での実行 ◦ 安全なコードの生成 • 信頼できないコードの実行を 考慮して設計されている 1 0 0 0 10 0 0 0 2 0 0 0 2 3 0 0 0 8 第三者のコードの実行 x86 ARM
  46. https://rsms.me/wasm-intro API

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

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

  49. Microsoft Flight Simulator SDK Documentation

  50. WebAssembly in Envoy Proxy-Wasm vNEXT ABI specification

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

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

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

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

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

  56. • i32, i64, f32, f64 については規定がある • それ以外は規定がない ◦ 配列、リスト

    ◦ 文字、文字列 ◦ レコード(構造体、共用体) • 線形メモリ上に、なんとかして置いている → 置き方は処理系に任せられている。 データ表現に関する規定があまりない
  57. バージョン名を返す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)))
  58. 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)))
  59. 文字列の表現が異なる 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
  60. グルーコードが必要 H e l l o \0 8 5 H

    e l l o
  61. 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)
  62. #[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)
  63. データ表現の数だけ API が必要 • サポートする言語が (type $t1 (func (param i32)

    (result i32))) (type $t2 (func (param i32 i32 i32)))
  64. • 策定中の仕様で、次の 3 つが目的 ◦ Language neutral なインターフェイスの定義を可能にする ◦ Web

    API 呼び出しの最適化 ◦ Wasm モジュールの再利用性の向上 • 内容 ◦ Interface type の定義 ◦ Adapter ◦ Lifting and Lowering Instructions Interface Types
  65. 言語ごとにライブラリを提供することも必要 Microsoft Flight Simulator: Platform toolset WebAssembly for Proxies (ABI

    specification)
  66. まとめ

  67. • さまざまなユースケースに対応できる • サンドボックス化による安全性の確保できる • 手に馴染んだ言語が使え、開発者体験の向上が期待できる ◦ 勉強のコストを減らす可能性が高い ◦ 既存資産を、少ない手間で利用できる

    → エコシステムの面で有利になりうる プラグインシステムに Wasm を採用すると