Files
hakorune/docs/phases/phase-10/phase_10_cranelift_jit_backend.md

12 KiB
Raw Blame History

Phase 10: Cranelift JIT BackendMIR→VM→Cranelift

Status: Planned (Primary path for native speed) Last Updated: 2025-08-25

🎯 ゴール

  • 実行系の主経路を「MIR→VM」を維持しつつ、ホットパスをCraneliftでJIT化して高速化する。
  • LLVM AOTは後段Phase 11以降の研究対象へ繰り延べ。

🔗 位置づけ

  • これまでの案MIR→LLVM AOTを改め、現実的な開発速度と安定性を優先してCranelift JITを先行。
  • VMとのハイブリッド実行OSR/ホットカウントに基づくJITを採用。

📐 アーキテクチャ

AST → MIR → Optimizer → VM Dispatcher
                         └─(Hot)→ Cranelift JIT (fn単位)
  • VMが命令カウント・プロファイルを集計し、しきい値超過関数をJITコンパイル。
  • JIT済み関数は関数テーブルから直接呼び出し、VMはフォールバック先として維持。

📋 スコープ

  1. 基盤
  • JITマネージャ関数プロファイル・コンパイルキャッシュ
  • Craneliftコード生成MIR→CLIF Lower
  • 呼出しABINyash VMスタック/レジスタとのブリッジ)
  1. 命令カバレッジ(段階導入)
  • Phase A: Const/Copy/BinOp/Compare/Jump/Branch/Return純関数相当
  • Phase B: Call/BoxCall/ArrayGet/ArraySetホットパス対応
  • Phase C: TypeOp/Ref*/Weak*/Barrier必要最小
  1. ランタイム連携
  • Boxの所有・参照モデルを維持共有/クローンの意味論を破らない)
  • 例外・TypeErrorはVMの例外パスへエスケープ

受け入れ基準Milestone

  • M1: 算術/比較/分岐/returnの関数がJIT化され、VMより高速に実行
  • M2: Array/Mapの代表操作get/set/push/sizeがJITで安定動作
  • M3: BoxCallホットパス特にArray/Mapで有意な高速化2×目標
  • M4: 回帰防止のベンチと--vm-stats連携JITカウント/時間)

🪜 実装ステップ

  1. JITマネージャ/関数プロファイルの導入VM統計と統合
  2. MIR→CLIF Lower骨子基本型/算術/比較/制御)
  3. 呼出しABIブリッジ引数/戻り値/BoxRefの表現
  4. JIT関数テーブル + VMディスパッチ切替
  5. Array/Map/BoxCallのホットパス最適化
  6. TypeOp/Ref/Weak/Barrierの必要最小を実装
  7. ベンチ/スナップショット整備・回帰検出

⚠️ 依存・前提

  • MIR26整合TypeOp/WeakRef/Barrierの統合前提
  • P2PBox再設計Phase 9.xを先に安定化しておくVM/プラグインE2E維持

📚 参考

  • Cranelift: Peepmatic/CLIF、simple_jitの最小例
  • JIT/VMハイブリッド: LuaJIT/HotSpotのOSR設計

備考: LLVM AOTはPhase 11以降の研究路線に移行設計ドキュメントは維持

🔬 Sub-Phases (10_a .. 10_h)

各サブフェーズは「小さく立ち上げ→検証→次へ」。既存のVM/Thunk/PICを活用し、JITは同じ経路に自然合流させる。

10_a: JITブートストラップ基盤プロファイラ

  • 目的: Cranelift JITの骨組みとホット関数検出の導線を用意。
  • 具体:
    • JitManager(関数プロファイル、しきい値、キャッシュ)
    • CLIF環境初期化Module, Context, ISA
    • VM統合: 関数入口でホット度チェック→JITコンパイル/呼び出し
    • 診断: NYASH_JIT_STATS=1JIT件数/時間/キャッシュヒット)
  • 受入: ダミー関数をJIT登録してVMから呼出可能、ログが出る

10_b: Lower(Core-1) Const/Move/BinOp/Cmp/Branch/Ret

  • 目的: ループや条件分岐を含む純粋関数をJIT実行可能に。
  • 具体:
    • MIR値/型→CLIF型i64/f64/i1/void
    • Const/Copy/算術/比較/ジャンプ/分岐/return のLower
    • フレームレイアウトVMValue最小表現
  • 受入: 算術/比較/分岐のみの関数がJITでVMより速い小ベンチ

10_c: ABI/呼出し 関数呼び出しとフォールバック

  • 目的: JIT化関数から他関数を呼ぶ/VMへ戻る道を用意。
  • 具体:
    • 同一モジュール関数呼び出しJIT→JITJIT→VM
    • 引数/戻り値の受け渡し(整数/浮動/void
    • 例外/TypeErrorはVMへバイアウトtrap→VM
  • 受入: 再帰/多段呼び出しが安定動作

10_d: コレクション基礎 Array/Map ホット操作(外部呼び出し)

  • 目的: 実用的ホットパスlength/get/set/push/popをJIT側から呼べるように。
  • 具体:
    • ホスト関数テーブル外部シンボルで既存Rust実装を呼ぶ
    • 境界チェック/エラーはRust側に委譲、JITは薄い橋渡し
  • 受入: Array操作がVM経由より高速目安1.52.0×

Status2025-08-27

  • Param経路でのE2Eを実装NYASH_JIT_HOSTCALL=1ゲート)
  • 実装済みシンボルPoC, C-ABI in Rust:
    • nyash.array.{len,push,get,set} / nyash.map.size
  • 使い方(例):
cargo build --features cranelift-jit --release
NYASH_JIT_THRESHOLD=1 NYASH_JIT_HOSTCALL=1 NYASH_JIT_EXEC=1 \
  ./target/release/nyash --backend vm examples/jit_array_param_call.nyash
NYASH_JIT_THRESHOLD=1 NYASH_JIT_HOSTCALL=1 NYASH_JIT_EXEC=1 \
  ./target/release/nyash --backend vm examples/jit_map_param_call.nyash

Notes

  • 関数パラメータに渡した配列/MapのみHostCall経由でアクセスthread-local引数参照
  • ローカルnew値は10_eへ移管ハンドル表PoC: u64→Arc

10_e: BoxCall高速化 Thunk/PICの直結

  • 目的: Phase 9.79bの TypeMeta{slot->thunk} と Poly-PIC をJITにインライン。
  • 具体:
    • slot -> thunk -> target 解決をJITで再現ユニバーサル0..3含む)
    • (type_id, version) チェックPoly-PIC 24件→ヒット直呼び、ミスVM
    • バージョンミスマッチで安全にフォールバック
  • 受入: BoxCallホットサイトで2×以上の高速化正しい無効化挙動

10_f: TypeOp/Ref/Weak/Barrier最小

  • 目的: 実アプリで必要な最小限のタイプ/参照操作を埋める。
  • 具体:
    • as_bool() 等の基本型変換
    • 参照/弱参照/バリアの最小パス重い経路はVMへ
  • 受入: 代表的コードパスでJIT有効のままE2E成功

10_g: 診断/ベンチ/回帰

  • 目的: 可視化と安定化。
  • 具体:
    • --vm-stats にJIT統計統合compile/ms, sites, cache率
    • ベンチ更新JIT有/無比較)とスナップショット
  • 受入: CIで回帰検知可能ドキュメント更新

10_h: 硬化・パフォーマンス調整

  • 目的: ホットスポットの最適化とノイズ除去。
  • 具体:
    • ガード配置最適化(分岐予測/ICヒット優先
    • 不要コピー削減、ホスト呼出回数の削減
  • 受入: 代表ベンチで安定して目標達成2×以上

📦 成果物(各サブフェーズ)

  • 10_a: jit/manager.rs スケルトン、VM連携、統計ログ
  • 10_b: jit/lower/core.rsConst/BinOp/Cmp/Branch/Ret単体テスト
  • 10_c: jit/abi.rscall/ret/fallback再帰テスト
  • 10_d: jit/extern/collections.rsArray/Mapブリッジマイクロベンチ
  • 10_e: jit/inline_cache.rsPIC/VT連携無効化テスト
  • 10_f: jit/lower/typeop_ref.rs(最小)
  • 10_g: ベンチ/統計/README更新
  • 10_h: 最適化コミットと測定レポート

🧩 既存資産との連携(重要)

  • Thunk: Phase 9.79b.3の TypeMeta{thunks} をJIT直呼びターゲットとして使用
  • Poly-PIC: VMの構造をJITに投影同じキー (label, version) を使用)
  • Versioning: cache_versions のイベントに同期してIC無効化

🎯 マイルストーン再定義

  • M1: 10_a + 10_b 合格Core関数のJIT実行
  • M2: 10_c + 10_d 合格(関数呼出/Arrayホット操作
  • M3: 10_e 合格BoxCallホットパス2×
  • M4: 10_g + 10_h 合格(ベンチ/統計/硬化)

⚠️ リスクと緩和

  • ABI複雑化: まず整数/浮動/voidに限定し、BoxRefはホスト関数へブリッジ
  • 最適化過剰: 常にVMフォールバックを保持、ガード失敗で安全に戻す
  • デバッグ困難: CLIFダンプ/CFG表示/NYASH_JIT_STATSで観測

🐛 発見した問題点2025-08-27 ベンチマーク実行時)

1. インタープリター性能問題

  • 問題: 10万回のループで2分以上かかりタイムアウト
  • 原因: unwrap_instanceのデバッグログが大量出力毎回の演算でInstanceBoxチェック
  • 目標: 10万回ループを数秒で完了
  • 対策:
    • デバッグログの条件付き出力化
    • 基本演算の高速化IntegerBoxの直接操作最適化

2. VMの変数管理エラー

  • 問題: Invalid value: Value %47 not set - simple_add_loop内の変数zが正しく管理されていない
  • 原因: MIR生成時の変数スコープ管理の不具合
  • 対策: MirBuilderの変数トラッキング改善

3. Box APIの成熟度

  • 問題: TimeBoxにelapsed()/reset()メソッドがインタープリターから呼べない
  • 原因: Boxメソッドの登録システム未完成
  • 対策:
    • Boxメソッドの統一的登録システム実装
    • インタープリターとVMのメソッド解決統一

4. ベンチマーク基盤

  • 問題: Nyashスクリプトでの正確な時間計測が困難
  • 根本原因: TimeBoxのelapsed()/reset()メソッドがインタープリターから呼べないBox API問題と同じ
  • 対策: Box APIの成熟度問題問題3が解決すれば自動的に解決

改善優先度

  1. : インタープリター性能問題(基本機能の使い物にならない)
  2. : VM変数管理JIT最適化の前提
  3. : Box APIの成熟度ベンチマーク基盤も同時解決

🚀 Phase 10.9: Cranelift AOT Backend追加計画

Status: Future (JIT実装の上乗せで実現可能)

概要

JIT実装10_a10_hで構築したMIR→CLIF変換基盤をそのまま活用し、事前コンパイルAOTによるスタンドアロン実行ファイル生成を実現する。

利点

  • コード再利用: JITと同じLowerCore実装を使用追加実装最小
  • 非同期完全サポート: WASMの制限なし、ネイティブ非同期可能
  • 最高性能: ネイティブコード直接実行(起動時コンパイル不要)
  • デバッグ容易: gdb/lldb等のネイティブデバッガ使用可能

実装ステップ案

10.9a: ObjectModule統合
├── cranelift-objectモジュール導入
├── CLIF→オブジェクトファイル生成
└── 既存のLowerCore再利用

10.9b: ランタイムライブラリ
├── Nyash標準Box群の静的リンク版作成
├── プラグインの静的埋め込み対応
└── 最小ランタイムGC hooks等分離

10.9c: リンカー統合
├── cc/ldによる実行ファイル生成
├── プラットフォーム別設定
└── デバッグシンボル生成

10.9d: クロスコンパイル
├── 複数ターゲットx86_64/aarch64/wasm32
├── ターゲット別最適化
└── CI/CDでのマルチプラットフォームビルド

使用イメージ

# ネイティブ実行ファイル生成
./target/release/nyash --compile-native program.nyash -o program
./program  # スタンドアロン実行!

# クロスコンパイル
./target/release/nyash --compile-native --target x86_64-pc-windows-msvc program.nyash -o program.exe
./target/release/nyash --compile-native --target aarch64-apple-darwin program.nyash -o program.mac

技術的詳細

  • 共通基盤: LowerCoreのemit処理はJIT/AOT両対応
  • 差分実装: JITはJITModule、AOTはObjectModuleを使用
  • リンク方式: 静的リンク優先(配布容易性重視)
  • サイズ最適化: LTO/strip対応で実行ファイルサイズ削減

WASM AOTとの比較

特性 Cranelift AOT WASM AOT
非同期 完全対応 制限あり
実行速度 最速 速い
ファイルサイズ MB級 KB級
ポータビリティ プラットフォーム別 高い
デバッグ ネイティブツール 限定的

想定スケジュール

  • Phase 10JIT安定化後に着手
  • 実装期間: 2-3週間JIT基盤の再利用により短期実現可能
  • 初期ターゲット: Linux x86_64、その後Windows/macOS対応