WebAssemblyインタプリタを書く ~Component Modelを添えて~
by
ruccho
×
Copy
Open
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
WebAssemblyインタプリタを書く ~Component Modelを添えて~ るっちょ @ruccho_vector
Slide 2
Slide 2 text
作ったもの ● Unity (.NET) 上で動く、C#製WebAssembly?インタプリタ ● Component Model?に対応 ● ゲームにおける会話イベントやカットシーンなどをWasmで動かす
Slide 3
Slide 3 text
ゲーム開発における「スクリプト」 ● ゲーム開発はエンジンの上に軽量なスクリプト環境を作りがち ● アプリケーション寄りのロジックを書く ● 動的なロードや実行、ホットリロードなどをサポート ● 非エンジニアが書けるようにする目的も エンジン (C++) スクリプト (C#, Lua, …)
Slide 4
Slide 4 text
Unityの場合 ● エンジンはC++、ユーザーコードとしてC#がサポートされている ● しかし、C#はスクリプトとして難点あり ○ 一部プラットフォームではAOT制約がある (JITができない) ○ ホットリロード機能はあるが、 よく壊れるので実質機能していない ○ コンパイル時間が長い ● 新たなスクリプトレイヤーが欲しい! C++ C# スクリプト (WebAssembly)
Slide 5
Slide 5 text
WebAssembly (Wasm) ● 特定のOSやCPUに依存しない仮想の命令セットとバイナリ形式 ● Rust, C/C++, Java, Go, C#など様々な言語をWasmにコンパイルできる 👉言語非依存なスクリプト環境をUnity上に作れるのではないか
Slide 6
Slide 6 text
余談:ほかの選択肢 ● Lua ○ 組み込みが容易で、昔からゲーム向けスクリプト環境として人気 ○ 動的型付け、エディタ補完の弱さから敬遠 ● ビジュアルスクリプティング ○ これを作る前に3回ビジュアルスクリプティング環境を自作した 結論、なんだかんだでテキストは強い
Slide 7
Slide 7 text
WebAssemblyインタプリタを書く
Slide 8
Slide 8 text
① モジュールのデコード ● ヘッダ+セクションのシンプルな構成 ● LEB128 (整数の可変長バイナリ表現) が多用される ● 仕様見ながら地道に書く ヘッダ Type Section Import Section Function Section Table Section Memory Section Global Section Export Section Start Section Code Section Data Section
Slide 9
Slide 9 text
② 命令のデコード・挙動の実装 ● 数が多いのでデコーダは自動生成で実装 ● とりあえずWasm 1.0まで実装 ○ 2.0にはSIMDなど含まれる https://pengowray.github.io/wasm-ops/
Slide 10
Slide 10 text
③ VM ● ハーバードアーキテクチャ ○ 関数にはインデックスベースで飛ぶ ● スタックマシン ● ブロック単位の遷移 ● 型はi32, i64, f32, f64の4種類 ○ ※Wasm 1.0の場合 ● 独自機能としてプリエンプティブなグリーンスレッドをサポート ○ C#側の非同期関数をWasmから同期的に呼べる ○ 会話イベントなど作るうえで便利
Slide 11
Slide 11 text
④テスト ● 公式テストスイートがある
Slide 12
Slide 12 text
動いた!しかし…… ● 素のWebAssemblyはFFIがたいへんやりにくい! ● FFIでの引数・戻り値の型はi32, i64, f32, f64の4種類のみ ○ それ以外のデータは線形メモリを介して渡す必要がある ● 線形メモリを介した任意長データの渡し方が十分に定義されていない ○ 線形メモリ上のデータレイアウト、確保・解放の方法やタイミングなど ○ つまり標準的なABIがない ● 実用的には、FFI用のグルーコード生成が必要になる
Slide 13
Slide 13 text
その悩み、 WebAssembly Component Modelが 解決します
Slide 14
Slide 14 text
WebAssembly Component Model ● Wasmのハイレベルなinteroperabilityを実現するための仕様 ● 文字列、配列、構造体など複雑な値を扱うためのCanonical ABIがある ○ 引数や戻り値はCanonical ABIに従ってやりとりされる ● WASI preview 2以降はComponent Modelに則って定義される ● 将来的にはWasmコンポーネントをレジストリに公開して依存解決する、 みたいなのも目指している ○ wa.devというパッケージレジストリが既にあったりする
Slide 15
Slide 15 text
利用者から見たComponent Model ● WITという専用のDSLを使う ○ Wasmコンポーネントが公開する関数のシグネチャや、そこで使われる データ型を定義するもの
Slide 16
Slide 16 text
利用者から見たComponent Model ● WITから各言語向けのバインディングを自動生成する ● コンパイルしたWasmモジュールにメタデータを付与してコンポーネントに 変換する WIT ゲストソース (Rust, Go, …) バインディング 素のWasm Wasm Component
Slide 17
Slide 17 text
ランタイムから見たComponent Model ● Wasmコンポーネントは独自のバイナリ仕様を定義している ○ 素のWasmバイナリに様々なメタデータを付与する ○ つまり、新たにデコーダが必要 ● FFIでCanonical ABIを実装する必要がある ○ 配列や構造体、複雑な値をWasmの線形メモリにシリアライズしたり、 逆にデシリアライズしたり
Slide 18
Slide 18 text
Component Modelに対応できた! ● 文字列とかカジュアルに渡せるようになった ○ ゲームの会話イベントで必須なメッセージ本文の受け渡しなど活用範囲は広い ● Component Model 対応の詳しい話は記事に書いています ○ Component Model な Wasm ランタイムを作った https://zenn.dev/ruccho/articles/7aad0b660377ae
Slide 19
Slide 19 text
👈 Unity (C++) の上で動く C# の上で 動く Rust (Wasm)
Slide 20
Slide 20 text
Component Modelの普及状況 ● ゲスト言語向けのツーリングは充実しつつある ○ Rust, Go, C/C++, C#あたりは動く ○ moonbit (Wasmをメインターゲットとした新興言語) も注目 ● 実行環境のサポートはまだまだ ○ wasmtime ○ ブラウザはまだ非対応
Slide 21
Slide 21 text
WebAssemblyインタプリタを書く ~Component Modelを添えて~ るっちょ @ruccho_vector