概要
- iOSではJITコンパイルが制限 されており、DolphinエミュレータはApp Storeで利用不可
- WebAssembly(Wasm)とJavaScriptCore のJIT例外を活用した新しいアプローチ
- RustによるWasmバイトコード生成・リンク手法 の実装解説
- WATaBoy(Game Boyエミュレータ)でのJIT-to-Wasmの実装事例
- JIT-to-Wasmとインタプリタのパフォーマンス比較 を目的としたプロジェクト
iOSでJITが許可されない理由とWebAssemblyの活用
- iOSではJITコンパイルが原則禁止 されているため、DolphinのようなCPU依存エミュレータはApp Storeでリリース不可
- AppleはWebブラウザ(JavaScriptCore, WebKit)にのみJIT例外 を設けている現状
- WebAssemblyやJavaScriptはJITで高速化 されるため、Wasmバイトコードを生成しブラウザ側でJITさせる手法を検討
- 既存の類似プロジェクト(The Jiterpreter, v86) は存在するが、ゲームコンソールエミュレータでの応用例やパフォーマンス比較は未開拓
- Game Boyエミュレータ(WATaBoy)を題材にJIT-to-Wasmを実装 し、インタプリタとの速度比較を最終目標に設定
Game BoyエミュレータでのJIT-to-Wasmの意義
- Game BoyレベルのエミュレータでJIT導入の恩恵は限定的 だが、実装が容易で卒業研究の範囲に収まる利点
- JIT導入時の課題 として、割り込み予測やMMIOアクセス時のインタプリタへのフォールバックが必要
- GameRoyのJIT実装を参考 に最適化技術を応用(x86向けだが手法はWasmにも有効)
RustによるWasmバイトコード生成・リンク手法
- 低レイヤWasm操作にはwasm-encoderクレートを使用
- wasm-bindgenやwasm-packは低レベル用途に不向き なため、C ABI経由でRustとJS間のデータ受け渡しを実施
- Nightly Rustの利用が必須 (inline Wasmのため)
- add関数のWasmバイトコード生成例
- wasm_encoderで型セクション・関数セクション・エクスポートセクション・コードセクションを順に構築
make_add_module関数でバイトコードを出力
Wasmバイトコードの実行方法
- WasmはHarvardアーキテクチャを採用 し、生成バイトコードを直接実行不可
- JavaScript側でWasmバイトコードをコンパイル・インスタンス化・リンク する必要
- linkNewModule関数をJavaScriptで実装 し、Rustから呼び出す
- Rust側でcall_indirect命令をinline Wasmで発行
- 関数テーブルの指定インデックスを間接呼び出しし、JIT生成関数を実行
LLDへのビルドフラグ指定
- --export-tableで関数テーブルをエクスポート
- --growable-tableで関数テーブルの動的拡張を許可
- build.rsでフラグを指定し、
cargo build --release --target wasm32-unknown-unknownでビルド
JavaScript側の実装例
- Wasmインスタンスの生成と関数テーブル操作
linkNewModuleで新規Wasmバイトコードをコンパイル→インスタンス化→関数テーブルに追加- 追加した関数のインデックスをRust側に返却
- make_and_execute_add関数を呼び出し、動的生成したadd関数を実行
- 実行結果として正しい加算結果(例:2+3=5)が得られる
WATaBoyでのJIT-to-Wasm応用
- Game Boy命令セットをWasmにJIT再コンパイル
- 分岐のない命令列(ベーシックブロック)ごとにWasmモジュールを生成・キャッシュ
- 関数シグネチャや命令列を動的に拡張可能
パフォーマンス比較と今後
- JIT-to-Wasm、Wasmインタプリタ、ネイティブインタプリタの速度比較が主目的
- WATaBoyのソースコードや詳細な命令再コンパイル例も公開
- 今後の応用範囲 として、より高性能なゲーム機エミュレータやiOS向けJIT活用の可能性
この内容は iOS/JIT制限の回避策 や Rust/Wasmの低レベル連携 の実装知見、 エミュレータ開発の新しい選択肢 として有用です。