# CURRENT TASK (Phase 11.7 kick-off: JIT Complete / Semantics Layer)

- Phase 12 準備（下準備・計画確定）
- 目的: ユーザー箱/プラグイン箱/内蔵箱の境界撤廃（TypeBox+Instance統一）＋ Nyash ABI(vtable)導入の段階計画を確定。最終ゴールは「Nyashコード（言語）→ VM → JIT の同一実行（意味・結果・副作用が一致）」。
- 参照: docs/development/roadmap/phases/phase-12/PLAN.md
- 参考: docs/reference/abi/NYASH_ABI_MIN_CORE.md（最小ABIと進化戦略）
- TODO（Tier‑0）
  - [ ] type_box_abi雛形（`src/runtime/type_box_abi.rs`）の設計固め（NyrtValue/TypeBox/関数ポインタ）
  - [ ] type_registry雛形（`src/runtime/type_registry.rs`）の役割定義（TypeId→TypeBox）
  - [ ] VM `execute_boxcall` に vtable優先stubを入れる設計（`NYASH_ABI_VTABLE=1`で有効）
  - [ ] 管理棟: `NYASH_ABI_VTABLE`/`NYASH_ABI_STRICT` トグルの仕様確定（実装は次フェーズ）

Docs（Phase 12 直近）
- [x] Minimal Core ABI方針の文書化（NYASH_ABI_MIN_CORE.md）
- [ ] TECHNICAL_DECISIONSの最小ABI/API交渉・互換・安全の章を精緻化（進行中）
- [ ] PLAN/READMEへのリンク整備と“同一実行テスト”の詳細化

Phase 12 ゴール（検証観点）
- Cross-backend 同値性: 同一プログラム（Nyashコード）が VM と JIT で同一の最終結果・ログ・副作用（Box状態）を生む。
- ゴールデン/スモーク: 共通テストハーネスで VM/JIT を同条件で走らせ比較（差分があれば落とす）。


> Quick Resume (Phase 12 bridge)

- Where to look next:
  - Phase 12 overview: docs/development/roadmap/phases/phase-12/README.md
  - Task board: docs/development/roadmap/phases/phase-12/TASKS.md
  - ABI digest: docs/development/roadmap/phases/phase-12/NYASH-ABI-DESIGN.md
  - Refactoring plan: docs/development/roadmap/phases/phase-12/REFACTORING_PLAN.md
- Build/run (VM/JIT):
  - VM: `cargo build --release --features cranelift-jit && ./target/release/nyash --backend vm apps/tests/ny-echo-lite/main.nyash`
  - JIT: `./target/release/nyash --backend jit apps/tests/ny-echo-lite/main.nyash`
- MapBox extensions (VM/JIT): remove/clear/getOr/keys/values/JSON are available; keys/values currently return newline-joined String (shim).
- First refactor candidate: split `src/runner.rs` into `runner/mod.rs` + `runner/modes/*` (see REFACTORING_PLAN.md).


Phase 11.7 へ仕切り直し（会議合意）

- 単一意味論層: MIR→Semantics→{VM/Cranelift/LLVM/WASM} の設計に切替。VMは参照実装、実行/生成はCodegen側で一本化。
- フォールバック廃止: VM→JITの実行時フォールバックは行わない。JITは“コンパイル専用/AOT補助”に限定。
- 共通ABI: handle/i64/ptr 変換、to_bool/compare、タグ分類、invoke（固定/可変）、NyRTシム呼び出しを共通化。
- Cranelift: 軽量JIT/AOTパスを追加し、最小実装からMIR-15を段階的に緑化。LLVM AOT は併存。

Docs: docs/development/roadmap/phases/phase-11.7_jit_complete/{README.md, PLAN.md, CURRENT_TASK.md, MEETING_NOTES.md}

以降は下記の旧計画（LLVM準備）をアーカイブ参照。スモークやツールは必要箇所を段階で引継ぎ。

開発哲学（Box-First）
- 「箱を作って下に積む」原則で進める。境界を先に置き、no-op足場→小さく通す→観測→厳密化の順で段階導入。
- 詳細: docs/development/philosophy/box-first-manifesto.md

次の候補（再開時）
- spawn を本当の非同期化（TLV化＋Scheduler投入）
- JIT/EXE用 nyash.future.spawn_method_h C-ABI 追加

Async Task System (Structured Concurrency)
- Spec/Plan: docs/development/roadmap/phases/phase-11.7_jit_complete/async_task_system/{SPEC.md, PLAN.md}
- 目的: Nyash→MIR→VM→JIT/EXE まで一貫した構造化並行を実現（TaskGroup/Future を Box化）
- 進捗（P1）: FutureBox を Mutex+Condvar 化、await は safepoint+timeout（NYASH_AWAIT_MAX_MS）で無限待ち防止済み。

Update (2025-09-01 late / Async P2 skeleton + P3 await.Result unify)
- P2（雛形）
  - CancellationToken 型（cancel/is_cancelled）を追加: src/runtime/scheduler.rs
  - Scheduler::spawn_with_token / global_hooks::spawn_task_with_token（現状はspawnへ委譲）
  - TaskGroupBox 雛形: src/boxes/task_group_box.rs（API: new/cancel_all/is_cancelled）
- P3（awaitのResult化・第一弾）
  - VM Await: Futureの値を NyashResultBox::Ok で返す（src/backend/vm_instructions.rs）
  - env.future.await（VM/Unified）: Ok(value)／Err("Timeout") を返す（timeoutは NYASH_AWAIT_MAX_MS 既定5秒）
  - JIT Await: await_h は常にハンドル返却→ nyash.result.ok_h で Ok(handle) にラップ
    - 追加: src/jit/extern/result.rs（SYM_RESULT_OK_H）／lowerで await 後に ok_h を差し込み
- Smokes/安全ガード
  - tools/smoke_async_spawn.sh（timeout 10s + NYASH_AWAIT_MAX_MS=5000）。apps/tests/async-spawn-instance は nowait/awaitの安全版
  - ハングした場合もOS timeoutで残存プロセスを避ける

次の実装順（合意があれば即着手）
1) Phase 2: VM 経路への最小配線（暗黙 TaskGroup）
   - nowait の着地点を TaskGroup.current().spawn(...) に切替（内部は現行 spawn_instance を踏む）
   - scope 終了時の cancelAll→joinAll（LIFO）は雛形から段階導入（まずは no-op フック）
2) Phase 3: JIT 側の Err 統一
   - nyash.result.err_h(handle_or_msg) をNyRT/JITに追加し、timeout/キャンセル時に Err 化（await ラッパで分岐）
   - 0/None フォールバックを撤去（VM/Externは実装済み／JITを揃える）
3) Verifier: await 前後の checkpoint 検証
   - Lowerer/パスで ExternCall(env.runtime.checkpoint) の前後挿入・検証ルールを追加
4) CI/Smokes 最終化
   - async-await-min, async-spawn-instance（VM/JIT）、timeout系（await_timeout）の3本を最小温存
   - {vm,jit} × {default,strict} で timeout(10s) ガード

Update (2025-09-01 PM / Semantics unify + Async Phase-2 prep)

- Semantics layer in place and adopted by Interpreter/VM/JIT
  - New: `src/runtime/semantics.rs` with `coerce_to_string` / `coerce_to_i64` and unified `+` ordering
  - Interpreter/VM now delegate to semantics (string concat matches VM path; plugin String toUtf8→toString→fallback)
  - JIT: added hostcall `nyash.semantics.add_hh` (handle,handle) for dynamic add; wired in builder/core
- Cross-backend smokes (Script/VM/JIT via VM+jit-exec)
  - `apps/tests/mir-branch-ret` → 1 (all three)
  - `apps/tests/semantics-unified` → 0 (concat/numeric semantics aligned across backends)
  - Tool: `tools/apps_tri_backend_smoke.sh` (summarizes Result lines for 3 modes)
- Async Phase‑2 (front): minimal spawn API and await path
  - Exposed `env.future.spawn_instance(recv, method_name, args...) -> FutureBox`
    - For now resolves synchronously (safe baseline). Hooked to `PluginHost::invoke_instance_method`
  - `env.runtime.checkpoint` now calls `global_hooks::safepoint_and_poll()` for future scheduler integration
  - `env.future.await(value)` pass‑through unless value is FutureBox (then wait_and_get)
  - `apps/tests/async-await-min`: uses `nowait fut = 42; await fut;` → VM/JIT return 42; Interpreter runs (CLI does not print standardized Result line)

Delta to code
- Added: `src/runtime/semantics.rs`
- Updated: `src/interpreter/expressions/operators.rs`, `src/backend/vm_values.rs` → use semantics layer
- JIT: `src/jit/lower/{builder.rs, core_ops.rs, extern_thunks.rs}`, `src/jit/extern/collections.rs`
- NyRT C‑ABI: `crates/nyrt/src/lib.rs` exported `nyash.semantics.add_hh`
- Runtime externs: `src/runtime/plugin_loader_v2.rs` added `env.future.spawn_instance`, improved `env.runtime.checkpoint`
- Hooks/Scheduler: `src/runtime/global_hooks.rs` (safepoint+poll, spawn_task stub), `src/runtime/scheduler.rs` (single‑thread scheduler API scaffold present)
- Smokes/tools: `apps/tests/semantics-unified`, `apps/tests/gc-sync-stress`, `tools/apps_tri_backend_smoke.sh`

Open items / Next steps (proposed)
1) True async spawn (Phase‑2 complete)
   - Change `spawn_instance` to queue a task (Scheduler) instead of inline: capture `recv(type_id/instance_id)`, `method_name`, and TLV‑encoded args
   - On run: decode TLV and `invoke_instance_method`, set Future result; ensure safepoint via `checkpoint`
   - Add NyRT C‑ABI `nyash.future.spawn_method_h` for JIT/EXE and wire lowering
2) Interpreter CLI result normalization (optional)
   - Align “Result:” line for static box Main return to make Script mode consistent with VM/JIT in smokes
3) Keep smokes minimal (avoid bloat); current trio is sufficient for gating

—
Update (2025-09-01 AM / JIT handoff follow-up)

- Cranelift 最小JITの下地は進捗良好（LowerCore→CraneliftBuilder 経路）
  - Compare/Branch/Jump、最小Phi（block params）、StackSlotベースの Load/Store は実装済み（builder.rs/core.rs）。
  - ExternCall(env.console.log/println) の最小橋渡し（ConsoleBox.birth_h→by-id invoke）を追加済み。
- 追加スモーク（jit-direct 用／I/Oなし）
  - apps/tests/mir-store-load: x=1; y=2; x=x+y; return x → 3
  - apps/tests/mir-phi-min: if(1<2){x=10}else{x=20}; return x → 10
  - apps/tests/mir-branch-multi: 入れ子条件分岐 → 1
  - 実行例: `NYASH_JIT_THRESHOLD=1 ./target/release/nyash --jit-direct apps/tests/mir-store-load/main.nyash`
  - jit-direct 分岐/PHI 根治: 単一出口＋BlockParam 合流で安定（fast-path は常時有効）。

変更点（犯人切り分けと根治のための構造改革＋ログ）
- CraneliftBuilder（jit-direct 経路）
  - 単一出口＋明示合流（SSA）へ切替（途中段階→完了段階へ移行中）
    - ret 合流ブロックを導入し、BlockParam(i64) で戻り値を受け渡し。
    - すべての `emit_return` を「i64 正規化 → `jump(ret, [val])`」に統一（return 命令は合流側だけ）。
    - end_function 側で ret 合流ブロックに切替し、BlockParam を f64 変換（必要時）のうえ return。
  - Compare/Branch/Select まわり
    - Compare 結果をローカルスロットへ保存→Branch/Select 時に確実にロード（スタック取りこぼし排除）。
    - `br_if` 直前に cond を b1 正規化（i64→b1）。
  - デバッグ用 extern を登録（必要時のみ）
    - `nyash.jit.dbg_i64(tag: i64, val: i64) -> i64`（値観測用）
    - `nyash.jit.block_enter(idx: i64) -> void`（ブロック入場ログ）
- LowerCore（return 値の堅牢化）
  - Return 値が known/param/slot 経路に乗らない場合、同一ブロックの Const 定義をスキャンして materialize。
  - Fast-path（読みやすさ＆単純化）: then/else が定数 return の場合、`select(cond, K_then, K_else)`→`emit_return` に縮約（常時有効）。

診断ログ（必要時のみ ON）
- `NYASH_JIT_TRACE_BLOCKS=1` … ブロック入場ログ（`[JIT-BLOCK] enter=<idx>`）
- `NYASH_JIT_TRACE_BR=1` …… br_if の cond 有無（`[JIT-CLIF] br_if cond_present=...`）
- `NYASH_JIT_TRACE_SEL=1` … select の cond/then/else 値（tag=100/101/102）
- `NYASH_JIT_TRACE_RET=1` … return の値: emit_return 直前（tag=201）、ret 合流（tag=200）

再現・実行コマンド（jit-direct）
- 分岐の最小: `apps/tests/mir-branch-ret/main.nyash`
  - `NYASH_JIT_THRESHOLD=1 NYASH_JIT_DUMP=1 ./target/release/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
  - 診断ON: `NYASH_JIT_THRESHOLD=1 NYASH_JIT_DUMP=1 NYASH_JIT_TRACE_RET=1 NYASH_JIT_TRACE_BLOCKS=1 ./target/release/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
- PHI最小: `apps/tests/mir-phi-min/main.nyash`
- 複合分岐: `apps/tests/mir-branch-multi/main.nyash`

期待と現状（2025-09-01 PM 時点）
- 統合JIT（`--backend cranelift`）: OK（`mir-branch-ret`→1）。
- jit-direct: 単一出口＋BlockParam 合流の配線で安定化を確認（cond/then/else も正常）。tag=201/200 は一致。

検証結果（jit-direct / 2025-09-01 実行）
- `apps/tests/mir-branch-ret`: Result=1, [JIT-DBG] 201=1 / 200=1
- `apps/tests/mir-phi-min`: Result=10, [JIT-DBG] 201=10 / 200=10
- `apps/tests/mir-branch-multi`: Result=1, [JIT-DBG] 201=1 / 200=1
- `apps/tests/mir-nested-branch`: Result=1, [JIT-DBG] 201=1 / 200=1
- `apps/tests/mir-phi-two`: Result=50

次のタスク（仕上げ）
1) LowerCore fast‑path/select のガード整理（`NYASH_JIT_FASTPATH_SELECT` の簡素化）。
2) b1 返り値 ABI を有効化する場合の経路確認（feature `jit-b1-abi`）。
3) ドキュメント整備（CraneliftBuilder 単一出口方針と TRACE 変数の最終化）。

Update (2025-09-02 / JIT seal・PHI安定化 + builder分割 進捗)

- 完了（JIT / jit-direct 最小3本グリーン）
  - seal 管理の一本化（途中seal撤廃、end_functionで最終seal）。
  - PHI(min) 合流: 事前スキャン→ensure_block_params、br/jump時のargs/append秩序確立。
  - Return の安定化（known/param/slot優先、フォールバック const materialize）。
  - 診断ログ整備（NYASH_JIT_DUMP/TRACE_*）。
- スモーク（debug/release）: mir-branch-ret=1, mir-phi-min=10, mir-branch-multi=1。

- 追加（2025-09-02 PM / fast-path 簡素化）
  - Branch fast-path を常時有効化（両後続が i64 定数 return の場合に限り `select+return` で縮約）。
  - 環境変数 `NYASH_JIT_FASTPATH_SELECT` は不要になりました（存在しても無視）。
  - jit-direct の3本スモーク（debug/release）で回帰なしを確認。

- リファクタリング（builder 1,000行目安に向けて段階実施）
  - 分離済み:
    - `src/jit/lower/builder/noop.rs`（NoopBuilder）
    - `src/jit/lower/builder/object.rs`（AOT .o 用 ObjectBuilder、finish対応）
    - `src/jit/lower/builder/rt_shims.rs`（nyash_jit_dbg_i64 等の小シム群）
    - `src/jit/lower/builder/tls.rs`（clif_tls と TLS 呼び出しヘルパ）
  - 動作維持: pub use で既存パス互換。jit-direct スモーク通過。

  - 追加（2025-09-02 PM / MIR builder 分割の第一段）
    - Calls 抽出: `src/mir/builder/builder_calls.rs` 新設。
      - 移動: `build_function_call` / `build_method_call` / `build_from_expression` / `lower_method_as_function` / `lower_static_method_as_function` + 補助 `parse_type_name_to_mir` / `extract_string_literal`。
      - 依存を明示（`use crate::mir::{TypeOpKind, slot_registry};`）。
    - Stmts ラッパ導入: `src/mir/builder/stmts.rs` 新設。
      - 現状は `build_*` 系をラッパで委譲（`*_legacy`）し、動作回帰チェックを優先。
    - ビルド/スモーク: release + jit-direct 3本（branch-ret/phi-min/branch-multi）緑維持。

  - 次のステップ（builder 分割 続き）
    - [x] 1) Stmts 本体移設: `builder/stmts.rs` に移動し、`builder.rs` から削除。
    - [x] 2) Ops 抽出: `builder/ops.rs` に移動。
    - [x] 3) Utils 抽出: `builder/utils.rs` に移動。
    - [x] 4) 残存 `*_legacy` の削除と最終ビルド＋jit-direct 3本スモークで回帰確認。
    - [x] 5) 目標: `src/mir/builder.rs` を < 1,000 行に縮小（現状: 967 行）。
    - Docs: 新モジュール構成のメモを `docs/development/mir/MIR_BUILDER_MODULES.md` に追加（参照）。

- 残タスク（次手）
  - [ ] CraneliftBuilder 本体を `builder/cranelift.rs` に分離（大枠）。
  - [ ] `builder.rs` を薄い “ハブ” 化（trait/enum/API公開 + pub use）。
  - [ ] 分離ごとに jit-direct 3本（debug/release）スモーク再確認。
  - [ ] LowerCore の段階分割（`analysis.rs` / `cfg.rs` / `ops.rs`）検討（別PRでも可）。

- 実行メモ（JIT）
  - Build: `cargo build --release --features cranelift-jit`
  - jit-direct: `NYASH_JIT_THRESHOLD=1 ./target/release/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
  - 診断: `NYASH_JIT_DUMP=1 NYASH_JIT_TRACE_BLOCKS=1 NYASH_JIT_TRACE_RET=1` 併用可。
  - 単一出口方針: jit-direct は関数終端で単一の ret ブロックに合流し、PHI(min) は BlockParam で表現。
  - TRACE 変数一覧（JIT）: `NYASH_JIT_DUMP`, `NYASH_JIT_TRACE_BLOCKS`, `NYASH_JIT_TRACE_BR`, `NYASH_JIT_TRACE_SEL`, `NYASH_JIT_TRACE_RET`

Update (2025-09-01 PM2 / Interpreter parity blockers)

- 目的: Semantics 層での VM/JIT/Interpreter パリティ検証に向け、Interpreter 側の既知不具合を記録・引き継ぎ。

- 再現ファイル（ユーザー提供）
  - examples/semantics_test_branch.nyash
    - 期待: 100
    - 実際(Interpreter): IntegerBox(4)（変数IDが返る挙動）
    - 実際(VM): 100
  - examples/simple_test.nyash
    - 事象: PluginBoxV2 同士の加算でエラー（IntegerBoxダウンキャストのみを試行して失敗）
  - /tmp/test_string_concat.nyash
    - 事象: 文字列連結でエラー（PluginBox と String の連結が不可）

- 現状の暫定対応（実装済み）
  - Await(JIT): I::Await を nyash.future.await_h に降下（同期get）
  - Safepoint(JIT): I::Safepoint を nyash.rt.checkpoint に降下（global_hooks 経由で GC/scheduler 連携）
  - Barrier(JIT): Array.set/Map.set で nyash.gc.barrier_write emit
  - Interpreter: FutureBox を登録（new FutureBox(42) 可）
  - Interpreter: 加算まわりのフォールバック強化
    - 文字列likeの優先連結（toUtf8/Result.Ok含む）
    - 数値文字列→整数にパースできる場合は加算

- 未解決（最優先）
  1) 返り値が変数IDになる（examples/semantics_test_branch.nyash）
     - 現状: 再現せず（CLI実行で Result: 100 を確認）。
     - 対応: Return 直前と関数エピローグに限定トレース追加（`NYASH_INT_RET_TRACE=1`）。再発時に型/値を即観測可。
  2) PluginBox 同士の演算の包括対応
     - 暫定は toString→数値/文字列へ正規化で回避。恒久対応は Semantics/VM と同じ規約（handle-first + 文字列like/数値like）に寄せる。
  3) 文字列連結の広範囲対応
     - toString()/toUtf8/Result.Ok の内包を最優先で文字列正規化（現状の強化で多くは通る。追加ケースが出れば順次取り込み）。

- 次アクション（Interpreter fix plan）
  - [ ] semantics_test_branch 再現→Return 値の実体化ルート修正
  - [ ] simple_test の演算パスを toString 正規化で網羅（必要なら算術 toNumber も）
  - [ ] test_string_concat の失敗パターン収集→ try_box_to_string の対象拡張
  - [ ] SemanticsVM/ClifAdapter パリティ小スモーク追加（分岐/配列/extern/await）


Update (2025-09-02 late / jit-direct TLS単一FBリファクタ step-2 部分反映)

- Runner 小リファクタ（計画どおりの分割）
  - `src/runner.rs` → `src/runner/mod.rs` に移動。
  - `NyashRunner::run()` の `run_task` 重複分岐を削除（無害な重複除去）。

- jit-direct（CraneliftBuilder）: 単一FunctionBuilder（TLS）化の前進
  - ローカル（store/load）をTLS単一FB経由に統一。
  - `switch_to_block`: 未終端のまま別ブロックへ切替時に `jump` 注入→`cur_needs_term=false` に更新。
  - `br_if_with_args`: TLS単一FBで発行し、分岐を明示的に終端扱い（`cur_needs_term=false`）。
  - エントリを `seal_block(entry)` 済みに変更（入口でのPHI完了を前提）。
  - ブロックパラメータ（PHI）: その場のappendはやめて「必要数を記録」→`switch_to_block` 前に不足分をappendする方式に変更（命令追加後のparam禁止アサート回避）。
  - `end_function`: 未sealedブロックを最終sealするフェーズを追加（内部追跡セットで二重seal回避）。

- 現状の挙動
  - `cargo build --features cranelift-jit` は通過（警告あり）。
  - `NYASH_JIT_THRESHOLD=1 ./target/debug/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
    - 以前の「未終端での切替」アサートは抑止済み。
    - なお finalize 時に「未sealed blockN」が残るケースを観測（例: block4）。seal の最終整合に取りこぼしがある。

- 追加で必要な作業（次の小ステップ）
  1) LowerCore 側の `seal_block` 呼び出し順序の確認・補強（分岐/合流直後に seal されるよう統一）。
  2) 生成ブロックが `self.blocks` に全て含まれることの確認（ret_block を含む）。不足時は `begin_function` で `pending_blocks` を尊重して作成。
  3) 最小スモークの緑化: `mir-branch-ret` → 1, 続いて `mir-phi-min` → 10, `mir-branch-multi` → 1。
  4) 上記が通ったら、終端注入・最終sealの実装を整理（不要な箇所の削減、ログスイッチ固定）。

- 実行/検証メモ（再掲）
  - ビルド: `cargo build --features cranelift-jit`
  - 実行: `NYASH_JIT_THRESHOLD=1 ./target/debug/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
  - 追跡: `NYASH_JIT_TRACE_BLOCKS=1`（ブロック切替）/`NYASH_JIT_TRACE_RET=1`（返り値）


開発メモ / 注意点
- 分岐の取り違えは「ブロックまたぎの共有スタック」が原因になりがち。根治策として BlockParam 経由の合流・単一出口 return を徹底。
- デバッグログは “必要時のみ ON” の方針で仕込む。収束後に不要箇所は落とす（本番は静かに）。

チェックリスト（収束条件）
- [ ] jit-direct: `mir-branch-ret` → 1（tag=201/200 とも 1）
- [ ] jit-direct: `mir-phi-min` → 10（合流経路で BlockParam 値が正しい）
- [ ] jit-direct: `mir-branch-multi` → 1（ネスト分岐でも合流が正しい）
- [ ] 統合JIT（--backend cranelift）と一致
- [ ] ログ・一時コードの整理（必要なものだけ残す）
- 既知の注意（jit-direct 経路のみ）
  - 条件分岐系（Branch/Jump）で戻り値が 0 になる事象を確認。`--backend cranelift`（統合経路）では期待値どおり（例: mir-branch-ret → 1）。
  - 影響範囲: jit-direct 実験フラグのみ。LowerCore/CraneliftBuilder の IR 自体は生成されており、統合経路では正しく実行される。

---

最終確認（apps フォルダ tri‑backend 実行計画 / 実行ログ用）

対象: C:\git\nyash-project\nyash\apps 下の各アプリ（インタープリター／VM／JIT(exe)）

前提
- ビルド: `cargo build --release --features cranelift-jit`
- 実行パス（Linux/Mac）: `./target/release/nyash`
- 実行パス（Windows PowerShell）: `target\release\nyash.exe`
- 3モードの呼び分け:
  - Script(インタープリター): `nyash apps/APP/main.nyash`
  - VM: `nyash --backend vm apps/APP/main.nyash`
  - JIT(exe): `nyash --backend vm --jit-exec --jit-hostcall apps/APP/main.nyash`

補足/既知
- 一部アプリは CLI 入力/標準入力/環境定数に依存（例: ny-echo の標準入力、NYASH_VERSION の参照）。必要に応じて簡易入力をパイプで与えるか、定数をスクリプト先頭に仮定義して実行確認する。
- PluginOnly 強制は apps では無効化する（toString 経路が PluginInvoke 固定になると出力整形に影響）。

進め方（手順テンプレート）
1) 共通ビルド
   - [ ] `cargo build --release --features cranelift-jit`
2) アプリごとに 3 モード実行（下記テンプレートをコピーして使用）

テンプレート（各アプリ用）
- アプリ名: <app-name>
  - Script: `nyash apps/<app-name>/main.nyash`
    - [ ] 実行OK / 出力: <貼付>
  - VM: `nyash --backend vm apps/<app-name>/main.nyash`
    - [ ] 実行OK / 出力: <貼付>
  - JIT(exe): `nyash --backend vm --jit-exec --jit-hostcall apps/<app-name>/main.nyash`
    - [ ] 実行OK / 出力: <貼付>
  - 備考: 例）標準入力が必要 → `echo "Hello" | ...`、定数 `NYASH_VERSION` を仮定義 等

対象アプリ（初期リスト）
- ny-echo
  - 入力例（Script）: `echo "Hello" | nyash apps/ny-echo/main.nyash`
  - 入力例（VM）:     `echo "Hello" | nyash --backend vm apps/ny-echo/main.nyash`
  - 入力例（JIT）:    `echo "Hello" | nyash --backend vm --jit-exec --jit-hostcall apps/ny-echo/main.nyash`
  - 既知: `NYASH_VERSION` を参照するため、未定義時はエラー。必要ならスクリプト先頭で仮定義（例: `version = "dev"`）して確認。

- ny-array-bench
  - Script/VM/JIT で 3 モード実行し、処理完了を確認（所要時間・出力サマリを記録）。

- ny-mem-bench
  - Script/VM/JIT で 3 モード実行し、処理完了を確認（所要時間・出力サマリを記録）。

クロスチェック（簡易スクリプト）
- 補助: `tools/apps_tri_backend_smoke.sh apps/ny-echo/main.nyash apps/ny-array-bench/main.nyash apps/ny-mem-bench/main.nyash`
  - 3 モードの Result ライン要約を出力（インタラクティブ入出力が必要なものは手動実行を推奨）。

ゴール/合格基準
- 各アプリで Script/VM/JIT(exe) の 3 モードがクラッシュ無しで完走し、期待する出力/挙動が観測できること。
- 不一致/未定義エラーが出た場合は「備考」に記録し、必要に応じて最小限の仮定義（標準入力や定数）での再実行結果も併記する。
  - 次回対応: brif 直後のブロック制御/シール順の見直し（entry/sealing）、条件値スタック消費タイミングの再点検。


Update (2025-09-01 night / JIT-direct branch/PHI fix)

- Summary
  - Fixed jit-direct returning 0 for branches by unifying returns to a single-exit ret block and improving MIR return type inference (including PHI-based inference).
  - Stabilized PHI joins by materializing PHI results into locals and preferring local loads for Return.
  - Corrected stack order for `br_if_with_args` (pop else args → then args → cond), matching LowerCore push order; added minimal fallback when predecessor mapping is unavailable.
  - Added debug symbols and logs (gated by env) for ret path and CFG wiring.

- Code touched
  - MIR: `src/mir/builder.rs` (return type inference incl. PHI inputs)
  - Lowering core: `src/jit/lower/core.rs` (PHI materialize to local; arg wiring fallback; small traces)
  - Builder (Cranelift): `src/jit/lower/builder.rs` (single-exit return; br_if/jump args order; debug symbol registrations)

- New smokes
  - `apps/tests/mir-phi-two` … merge two locals (x,y) then add
  - `apps/tests/mir-nested-branch` … nested branches returning constants

- Status (jit-direct)
  - mir-branch-ret → 1
  - mir-phi-min → 10
  - mir-phi-two → OK（合流＋加算）
  - mir-nested-branch → 1
  - LLVM AOT snips (prebuilt binaries) still OK for VInvoke samples.

- How to run
  - `NYASH_JIT_THRESHOLD=1 ./target/release/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
  - `NYASH_JIT_THRESHOLD=1 ./target/release/nyash --jit-direct apps/tests/mir-phi-min/main.nyash`
  - `NYASH_JIT_THRESHOLD=1 ./target/release/nyash --jit-direct apps/tests/mir-phi-two/main.nyash`
  - `NYASH_JIT_THRESHOLD=1 ./target/release/nyash --jit-direct apps/tests/mir-nested-branch/main.nyash`
  - Optional logs: `NYASH_JIT_DUMP=1` and/or `NYASH_JIT_TRACE_RET=1`

- Next (small boxes; avoid saturation)
  1) Fast-path(select) 1-hop extension only:
     - If then/else each jump to a block that immediately returns a Const Integer, lower to `select(cond, K_then, K_else) → return`.
     - Keep scope narrow to avoid regressions.
  2) Multi-PHI (limited):
     - Add one smoke with two PHI slots; confirm arg counts/ordering under `phi_min`.
  3) Logging remains env-gated; no default noise. No broad refactors until the above are green.


Update (2025-09-02 / jit-direct FB lifecycle refactor)

いま動くもの
- Interpreter/VM/MIR の基本スモーク: OK
- await の Result.Ok/Err 統一: Interpreter/VM/JIT で整合
- Cranelift 実行（`--backend cranelift`）: OK（例: `mir-branch-ret` → 1）

いま詰まっている点（要修正）

Update (2025-09-03 / Phase 11.8 MIR cleanup 準備・判断固め)

- 方針（箱言語原則 × 軽快最適化）
  - ArrayGet/Set と RefGet/Set を BoxCall に集約（Core‑13 化）。
  - 算術/比較（BinOp/Compare）は現状維持（MIR に残す）。定数畳み込みや分岐簡約の主戦場として維持し、型不明ケースは Lower/セマンティクス側でBoxCall/Hostcallにフォールバック。
  - EffectMask 正確化（READ/WRITE/MAY_GC/IO）と WriteBarrier の確実化。
  - 最適化は VM の execute_boxcall / JIT の lower_boxcall に集約（脱仮想化・境界消去・Barrier）。

- 準備タスク（Phase 11.8 Kickoff）
  1) Docs: 仕様と着手順を `docs/development/roadmap/phases/phase-11.8_mir_cleanup/PLAN.md` に確定（このコミットで追加）。
  2) Env 設計: 段階導入トグルを定義（NYASH_MIR_ARRAY_BOXCALL / NYASH_MIR_REF_BOXCALL / NYASH_MIR_CORE13 など）。管理棟（config::env）での一括適用方針。
  3) Optimizer: Array/Field→BoxCall 変換パスのスケルトン追加（デフォルトOFF）。
  4) VM: execute_boxcall に予約IDの fast‑path フック（Array get/set・Field get/set）雛形。
  5) JIT: lower_boxcall の fast‑path 雛形（Bounds/Barrier含む、失敗時 plugin_invoke）。
  6) Smokes/Bench: array/field/arithmetic_loop の最小3種を用意・回帰基準±5%/±10%を導入。
  7) Cleanup sweep: 残存のレガシー/未使用コード・コメントの一括整理（claude code指摘の残骸候補を含む）。

- 参照: docs/development/roadmap/phases/phase-11.8_mir_cleanup/TECHNICAL_SPEC.md / PLAN.md
- jit-direct で Cranelift FunctionBuilder が「block0 not sealed」でパニック
  - begin/end のたびに短命の FunctionBuilder を作って finalize している設計が、最新の Cranelift の前提（全ブロック seal 済みで finalize）と合っていない
  - 単一出口（ret_block）方針は Cranelift 側に途中まで入っているが、ObjectBuilder と二重実装があり、Cranelift 側の finalize 前にブロックを seal しきれていない箇所が残っている

直近の変更（対策の第一歩）
- CraneliftBuilder
  - return は ret_block へ jump（エピローグで最終 return）に変更（単一出口に合わせて安全化）
  - entry block の seal を begin_function で実施
  - end_function 最後に blocks/entry/ret の seal を実施
- ObjectBuilder
  - emit_return は従来通りダイレクト return（ret_block を持たないため）

現状の評価
- 上記を入れても FunctionBuilder finalize のアサーションは残存。
- jit-direct の builder ライフサイクル（複数回 finalize する設計）そのものを見直す必要あり。

次の実装（推奨順）
1) CraneliftBuilder のビルドモデルを単一 FunctionBuilder 方式へ
   - 関数スコープで1つの FunctionBuilder を保持し、lower 中は finalize しない
   - switch/jump/phi/hostcall も同一 FB で emit（現状の都度 new/finalize を撤廃）
   - seal は then/else/target を LowerCore 側からタイミング良く呼ぶ＋end_function で最終チェック
2) jit-direct での AOT emit パス（ObjectBuilder）は現状通りだが、strict 判定を整理
   - `mir-branch-ret` のような最小ケースは unsupported=0 を確実に維持
   - まずはこの1本で .o 生成→リンク→EXE 実行を通す
3) ツールチェイン側（`tools/build_aot.sh`）の strict モードヒントを活かしつつ、上記の最小成功ケースを CI スモークに追加

全側で続けてこのリファクタに着手。まずは FunctionBuilder のライフサイクル一本化から進め、`mir-branch-ret` の AOT（EXE）生成・実行まで通し切る。


# （以下、旧タスク: Phase 10.8 記録）

Contributor note: 開発手順・レイアウト・PR要件はリポジトリルートの `AGENTS.md`（Repository Guidelines）参照。ビルド/テストやCIスモークの環境変数も簡潔にまとまっています。

## Handoff (Phase 11 next): 実行確認プラン（tests/ は対象外）

目的: apps 配下の「簡単なアプリ」から順に、VM → AOT(LLVM) の順で確実に動作させる。tests/ フォルダは除外。

前提/共通
- LLVM: `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix)` を付与してビルド
- AOTリンク: `tools/build_llvm.sh <app.nyash> -o app` を使用（`target/aot_objects/*.o` 固定）
- Verbose: トラブル時は `NYASH_CLI_VERBOSE=1`
- プラグインテスター: `tools/plugin-tester` を利用可（`cargo run --release -- check --config ../../nyash.toml --library <lib>`）

推奨テスト順（簡単→段階的）
1) apps/ny-array-llvm-ret/main.nyash（Array push/get 戻り値）
   - 期待: `Result: 3`
   - VM: `./target/release/nyash --backend vm apps/ny-array-llvm-ret/main.nyash`
   - AOT: `tools/build_llvm.sh apps/ny-array-llvm-ret/main.nyash -o app && ./app`

2) apps/ny-vinvoke-llvm-ret-size/main.nyash（by-id size）
   - 期待: `Result: 1`
   - VM/AOT 同上

3) apps/ny-vinvoke-llvm-ret/main.nyash（by-id get 可変長経路）
   - 期待: `Result: 42`
   - VM/AOT 同上

4) apps/ny-echo-lite/main.nyash（readLine → print 最小エコー）
   - 期待: 出力に `Result:` 行が含まれる（llvm_smoke の基準）
   - 実行例: `echo hello | ./target/release/nyash --backend vm apps/ny-echo-lite/main.nyash`
   - AOT: `tools/build_llvm.sh apps/ny-echo-lite/main.nyash -o app_echo && echo hello | ./app_echo`

5) apps/ny-llvm-smoke/main.nyash（Array get/set/print）
   - 期待: `Result: 3`
   - 備考: 文字列連結は NyRT concat シムへフォールバック済み。emit 検知が不安定な場合は再試行。問題が残る場合はこの項を後回し可。

6) apps/ny-echo/main.nyash（オプション付きエコー）
   - 期待: VM/JIT/AOT の出力一致（upper/lower/そのまま）

7) apps/ny-map-llvm-smoke/main.nyash（Map by-id 経路）
   - 期待: 行に `Map: v=42` と `size=1`
   - 備考: 連結シム適用済み。必要なら `NYASH_LLVM_ALLOW_BY_NAME=1` で一時回避。

トラブルシュート要点
- AOT emit: `NYASH_LLVM_OBJ_OUT=$PWD/target/aot_objects/<name>.o ./target/release/nyash --backend llvm ...`
- リンク: `NYASH_LLVM_SKIP_EMIT=1 NYASH_LLVM_OBJ_OUT=... tools/build_llvm.sh ...`
- プラグイン: `nyash.toml` のパス解決（拡張子はOSで異なる）。tester は拡張子補完に対応。

Update (2025-08-31 AM / Phase 11.1 quick pass)

Update (2025-08-31 PM / Phase 11.2 partial)

- 方式A（LLVM専用 NyRT 静的ライブラリ）で前進。by-id を本線、by-name はデバッグ用ラッパ方針。
- Lowering 更新
  - NewBox（引数あり 1～2個）→ `nyash.box.birth_i64(type_id, argc, a1, a2)`（int/handle ptr の最小対応）。0引数は `birth_h`
  - BoxCall（by-id, method_idあり）→ `nyash_plugin_invoke3_i64(type_id, method_id, argc, a0, a1, a2)` 接続（a0=receiver handle）
    - 戻り: dstが整数/真偽ならi64のまま、Box/String/Array等は i64(handle)→i8*(ptr)
    - ArrayBox.get/set は既存の `nyash_array_get_h/set_h` 安全パスを存続
  - 生成関数名: `ny_main` に変更（NyRTの起動ルーチンから呼び出し）
- NyRT(libnyrt.a) 追加シンボル
  - `nyash_string_new(i8*, i32)->i8*`（Const String用）
  - `nyash_array_get_h(i64,i64)->i64`, `nyash_array_set_h(i64,i64,i64)->i64`
  - 既存の `nyash.box.birth_h/i64`, `nyash.rt.checkpoint`, `nyash.gc.barrier_write` などは維持
- ツール
  - `tools/build_llvm.sh` 追加（.o → libnyrt.a リンク → EXE）
  - `tools/llvm_smoke.sh`（.o生成のスモーク）
- スモーク
  - `examples/llvm11_core_smoke.nyash` で EXE 実行し `Result: 3` を確認

Update (2025-08-31 PM2 / Phase 11.2 lightweight LLVM)

- 方針（拡張性優先 / コア最小化: Tier‑0）
  - ExternCall: 環境/I/Oのみ（env.console/debug/runtime など）。print は ExternCall(env.console.log) 本線。
  - BoxCall: データ構造/Box 操作（Array/Map/String/Instance 等）。AOT/LLVM は最小の安全シムのみ直結。
  - コアに残す安全シム（NyRT）: Array(get/set/push/length), Instance(getField/setField)。Map はコアに足さない（後述）。
  - Map/JSON/Math 等は当面コア外（必要時はプラグイン by‑id + 汎用シムでAOTを通す）。

- 実装・反映
  - MIR パス: `passes/method_id_inject` 追加（NewBox/Copy 由来の型から BoxCall に method_id 注入。PluginInvoke は可能なら BoxCall(by‑id)へ書換）。
  - LLVM Lowering:
    - ExternCall: `env.console.log` → `nyash.console.log`（NyRT）, `env.debug.trace` → `nyash.debug.trace`。
    - ExternCall: `env.console.readLine` 追加 → `nyash.console.readline`（stdin 1行, CR/LF 除去, C文字列返却）。
    - ArrayBox: `get/set/push/length` を NyRT 安全シム（`nyash_array_get_h/set_h/push_h/length_h`）に直結。
    - Instance: `getField/setField` を NyRT 安全シム（`nyash.instance.get_field_h/set_field_h`）に直結（既存）。
    - プラグイン by‑id: f64 戻りの選択（`nyash_plugin_invoke3_f64`）/ i64 戻り（`..._i64`）。先頭2引数はタグ付け（int/float/handle）対応（`..._tagged_i64`）。
    - by‑name 薄フォールバック（デバッグ用）: `NYASH_LLVM_ALLOW_BY_NAME=1` 下で `nyash.plugin.invoke_by_name_i64` を使用。
  - NyRT(libnyrt.a): 上記 API を追加（console.log/debug.trace/readline, array push/length, instance get/set_field, by‑name, tagged_i64）。
  - オブジェクト出力: `NYASH_LLVM_OBJ_OUT=<path>` で .o を明示出力（`runner/modes/llvm.rs` 経由）。
  - ツール更新: `tools/build_llvm.sh` / `tools/llvm_smoke.sh` が `NYASH_LLVM_OBJ_OUT` を使用して .o を取得後、NyRT とリンク。
  - サンプル: `apps/ny-llvm-smoke/main.nyash`（Array get/set/print）、`apps/ny-echo-lite/main.nyash`（readLine→print）。

- しないこと / 後回し
  - Map のコア安全シム追加（`nyash_map_*_h`）は見送り。必要ならプラグイン by‑id + 汎用シムでAOT実行。
  - ConsoleBox の高度機能は ExternCall 側で段階導入（出力は既存 log、入力は readline のみ）。
  - 汎用可変長引数（>2）は後段（タグ付けの拡張で対応予定）。

- 次にやること（短期）
  - ny-echo を縮小AOT対応（console.readLine + print のみで OK 版）。
  - Map（プラグイン最小版）で string-key の get/set/size を by‑id 汎用シム経由でAOT実行（コアは増やさない）。
  - CI/スモーク: `.o→EXE→実行` を `apps/ny-llvm-smoke` / `apps/ny-echo-lite` で追加。
  - ガードレール: コア安全シムを Tier‑0 以外に増やさない簡易チェック（grep ベース）導入検討。

- How to Build / Run（AOT/LLVM）
  - ビルド: `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm`
  - .o→EXE: `tools/build_llvm.sh <file.nyash> -o app_llvm` → `./app_llvm`
  - .o のみ: `NYASH_LLVM_OBJ_OUT=$PWD/nyash_llvm_temp.o ./target/release/nyash --backend llvm <file.nyash>`
  - 推奨 @env（main.nyash 冒頭コメント）:
    - `// @env NYASH_CLI_VERBOSE=1`（詳細ログ）
    - デバッグ時のみ `// @env NYASH_LLVM_ALLOW_BY_NAME=1`

Update (2025-08-31 PM3 / LLVM VInvoke triage)

- 直近のテスト結果（要約）
  - VM backend（正常）
    - MapBox.size(): Result: 1 ✅
    - MapBox.get(1): Result: 42 ✅
    - 可変長（VInvoke: get(1,9,8,7,6)）: 期待どおりにTLV I64(tag=3)でエンコードされ、出力確認済 ✅
  - LLVM backend（要修正）
    - MapBox birth は成功（instance_id=1）
    - set()/get() 呼び出し経路で戻り値が Result: 0（期待は 42）❌
    - LLVM 実行時に VM 相当の PluginLoaderV2 Invoke 詳細ログが出ず、by-id/可変長の値流しに不整合がある可能性

- 実装・修正状況
  - ランタイム（NyRT）
    - by-id 固定長/可変長の argc を「レシーバ除外の実引数個数」に統一済み
    - invoke 時の type_id を「レシーバ実体（PluginBoxV2）から取得した実 type_id」に変更（呼び出し先揺れを排除）
  - LLVM Lowering
    - <=4 引数: nyash_plugin_invoke3_tagged_i64（f64→i64ビット化＋タグ付与）
    - >=5 引数: nyash.plugin.invoke_tagged_v_i64（vals/tags の vector 経路）
  - スモーク
    - apps/ny-vinvoke-llvm-ret: 戻り値で 42 を検証する LLVM 用スモークを追加（print/concatに依存しない）
    - tools/llvm_smoke.sh に VInvoke（戻り値）スモークをオプション追加（NYASH_LLVM_VINVOKE_RET_SMOKE=1）

- いま見えている課題（LLVM）
  - by-id vector 経路（vals/tags/argc）のどこかで齟齬 → get が 0 を返す（キーが TLV 化されていない／タグずれなど）
  - 固定長（<=4）経路は未切り分け → まず size()/get(1) を LLVM 戻り値で確定（size→1, get(1)→42）
  - .o 出力の一部環境不安定は Runner/Lowering にフォールバックを追加済（write_to_memory_buffer）

- 次アクション
  1) LLVM 戻り値テストを段階確認
     - MapBox.size() → Result: 1
     - MapBox.get(1) → Result: 42
     - これで固定長 by-id の健全性を確定後、可変長（>=5）vector 経路へ絞り込み
  2) NyRT デバッグ（NYASH_CLI_VERBOSE=1 時のみ）を最小追加
     - nyash.plugin.invoke_tagged_v_i64: argc/method_id、vals[0..2], tags[0..2] を stderr に出力
     - 実際のTLV化の前に観測し、ズレ箇所を確定
  3) LLVM Lowering（vector 経路）の配列構築を点検
     - alloca([N x i64]) → inbounds GEP → store → i64* へ pointer_cast → 呼び出し
     - GEP index（[0,i]）/型一致/メモリ幅を再確認
  4) 必要なら一時的に「<=4 でも vector 経路を選択」する実験分岐を作り、経路差異を切り分け
  5) tools/llvm_smoke.sh: target/aot_objects 固定・事前 emit → link のフローをデフォルト強化（CI安定化）

- ゴール（本フェーズ収束条件）
  - LLVM backend で MapBox: size()/get(1)/get(1,9,8,7,6) が戻り値ベースで一致
  - VInvoke（可変長）経路が by-id で安定
  - print/concat のLoweringは後続（必要最小）に回す

- タスク実行（MVP）
  - `nyash.toml` に `[env]` / `[tasks]` を記述し、CLIから `--run-task <name>` で実行可能。
  - 例:
    - `[tasks] build_llvm = "LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm"`
    - 実行: `./target/release/nyash --run-task build_llvm`
  - 備考: `{root}` 変数展開対応。OS別/依存/並列は未対応（将来拡張）。


残作業（合意順）

1) method_id 埋め込みと by-id 本線化
   - ロード時に 名前→id を確定・キャッシュ（PluginLoaderV2）し、MIR へ `method_id` 注入（実行時は常に by-id）
2) BoxCall 汎用拡張
   - 引数3個以上/戻り型の拡張（i64/handle/f64 等）。Field 系（getField/setField）を BoxCall として安全パス接続
3) by-name ラッパ（デバッグ/テスト用）
   - Lowering フォールバックとして薄く導入（env/flag 下でのみ使用）、本番は by-id 固定
4) ExternCall 網羅
   - `env.console/debug/runtime/future` 等を puts 暫定から RT関数に置換、署名整備
5) スモーク/CI 拡張
   - by-id の代表例（CounterBox等）、console/array/field/extern を .o→EXE→起動まで

- LLVM Lowering: Phi/Load/Store の最小実装を追加（inkwell 0.5 / LLVM 18）
  - Phi: 事前に各BB先頭でPhiノード生成→Branch/Jump時にincomingを配線
  - Load/Store: entryでのalloca管理（型は注釈/値から推定）。i1/i64の簡易変換、ポインタはpointer_cast対応
  - 型なしポインタ（opaque）対応のため、`alloca`の要素型を別マップで追跡
  - ビルド検証: `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --features llvm` 成功
  - 既存のConst/Unary/BinOp/Compare/Branch/Jump/Return と併せ、Phase 11.1の目標範囲は到達

---

一時メモ（MIRインタプリタ 80/20 方針）

- ConsoleBox.readLine ローカルフォールバック（標準入力1行読み）を一時実装（`--backend mir` の echo-lite 用）。
  - 後で必ず削除し、プラグイン側メソッド/Extern 経由に置換すること。
  - 追跡タスク: 「ConsoleBox メソッド群の正式実装（PluginInvoke/ExternCall）とローカルフォールバックの撤去」。
  - 影響箇所: `src/backend/mir_interpreter.rs`（BoxCall: ConsoleBox.readLine 分岐）、`apps/tests/ny-echo-lite` スモーク。

次アクション（この項に紐づく）
- ClifSem 最小Lowering（Const/Return/Add）を実装し、JITスケルトンの0終了スモークを追加。
- ConsoleBox フォールバックは温存のまま（echo-liteのみのため）。Console 正式化のタイミングで除去。

---

# Handoff (Phase 11.7) — MIR Interpreter + Cranelift Minimal JIT

目的: LLVMが重くなったため仕切り直し。新しいMIR解釈層と軽量Cranelift JITの最小機能を整備し、段階拡張しやすい骨格を確立。

実装済み（要点）
- 共通ABI/ユーティリティ:
  - `src/backend/abi_util.rs`（to_bool/eq/tag/handle）
- MIRインタプリタ（--backend mir）:
  - 対応: Const/Unary/BinOp(＋String結合)/Compare/Load/Store/Copy/Branch/Jump/Return/Print/Debug/Barrier/Safepoint(no-op)
  - NewBox/PluginInvoke/BoxCall/ExternCallの最小対応（PluginBoxV2はプラグインホスト経由）
  - ConsoleBox.readLine: 一時フォールバックで標準入力1行読み（CURRENT_TASKに削除タスク記載済）
- Cranelift最小JIT（--backend cranelift）:
  - 実JIT（jit.rs）: Const(i64/f64/bool->0/void->0)/Add/Sub/Mul/Div/Mod、Compare(Eq/Ne/Lt/Le/Gt/Ge)、Load/Store（StackSlot）、Copy、Return/Jump/Branch
  - 箱化: `src/backend/cranelift/context.rs` に ClifContext/BlockMap/ValueEnv を用意（JIT構築をカプセル化）
  - LowerCore→ClifBuilder（IRBuilder実体）: 録画→実IR生成（Const/Add/Return）を暫定実装
    - 起動切替: `NYASH_JIT_LOWERCORE=1` で LowerCore→ClifBuilder 実IR経路を実行
- スモーク:
  - `apps/tests/mir-const-add/main.nyash`（0終了）
  - `apps/tests/mir-branch-ret/main.nyash`（条件分岐で1）
  - どちらも --backend cranelift / --backend mir で確認済

使い方（コマンド）
- Cranelift有効ビルド: `cargo build --features cranelift-jit`
- MIRインタプリタ: `./target/debug/nyash --backend mir apps/tests/mir-const-add/main.nyash`
- Cranelift最小JIT: `./target/debug/nyash --backend cranelift apps/tests/mir-branch-ret/main.nyash`
- LowerCore→ClifBuilder 実IR: `NYASH_JIT_LOWERCORE=1 ./target/debug/nyash --backend cranelift apps/tests/mir-const-add/main.nyash`

次のタスク（推奨順）
1) ClifBuilder 実IR生成の拡張（LowerCore連携）
   - Compare/Branch/Jump の実IR
   - 最小Phi（Block Params）
   - StackSlotベースのLoad/Store（ValueEnvから完全移行）
2) ExternCall（env.console.log）最小対応（JIT経路でもprintln相当へ）
3) スモーク追加: Load/Store、Phi最小ケース、Compare/Branch複合ケース
4) Console/Extern 正式化完了後に ConsoleBox.readLine フォールバック削除（本ファイルにタスク済）
5) 警告/CFG整理: 使っていないfeature cfgやunusedを段階的に整理

既知の注意/制限（80/20の割り切り）
- BoolはI64の0/1として扱っており、B1専用ABIは未導入（将来拡張）。

---

Update (2025-09-02 night / jit-direct TLS単一FBリファクタ 進捗・引き継ぎ)

- 目的: jit-direct の Cranelift FunctionBuilder ライフサイクルを「関数ごとに1つ」に統一し、finalizeは end_function の一度のみとする（Craneliftの前提に整合）。

- 実装済み（最小スコープ）
  - TLSに Context/FBC/FunctionBuilder を保持（begin_functionで生成→end_functionでfinalize）。
  - per-op finalize の撤去。主要経路（const/binop/compare/select/branch/jump/return/hostcall 等）を TLS 単一FB に切替中。
  - 単一出口（ret_block + i64 block param）維持。emit_return は ret_block へ jump、end_function で epilogue return を生成。
  - prepare_blocks は begin_function 前はTLSに触れず pending_blocks に貯め、begin_function で create_block。
  - host/import 呼び出しは tls_call_import_ret/tls_call_import_with_iconsts ヘルパへ分離（module.declare_func_in_func + call を安全化）。
  - 未終端ブロック切替の安全弁: IRBuilder::switch_to_block に「未終端なら jump 注入」（cur_needs_term）を導入。

- 現状ステータス
  - cargo build --features cranelift-jit: OK
  - jit-direct 実行: まだ1箇所「you have to fill your block before switching」（未終端での block 切替）アサートが残存。
    - 再現: `NYASH_JIT_THRESHOLD=1 ./target/debug/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
    - 多くの switch_to_block は closure から排除済みだが、特定条件下で未終端のまま切替が残っている模様。

- 次の小ステップ（箱を下に積む順）
  1) IRBuilder::switch_to_block の重複抑止（同一 index への再切替は no-op）。
  2) cur_needs_term の更新確認（emit_return/br_if/jump 後は必ず false）。主要箇所は反映済みだが再点検。
  3) emit_* 内の残存 switch_to_block を整理（挿入点は LowerCore 側の switch_to_block に一本化）。
  4) トレースで最終合流（ret_block）直前の切替を観測：
     - 環境: `NYASH_JIT_TRACE_BLOCKS=1 NYASH_JIT_TRACE_BR=1`
  5) スモーク（jit-direct）を順に通す:
     - `mir-branch-ret` → 1
     - `mir-phi-min` → 10
     - `mir-branch-multi` → 1
  6) hostcall_typed / plugin_by_name の TLS 呼び出し統一（未対応部分があれば最小限で補完）。

- 実行/検証メモ
  - ビルド: `cargo build --features cranelift-jit`
  - 実行: `NYASH_JIT_THRESHOLD=1 ./target/debug/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
  - 追跡ログ: `NYASH_JIT_TRACE_BR=1`（brif出力）、`NYASH_JIT_TRACE_BLOCKS=1`（block切替通知）

- 影響範囲
  - jit-direct（CraneliftBuilder）限定。ObjectBuilder（AOT .o生成）は従来通り。
  - docs/development/roadmap/phases/phase-11.7_jit_complete 配下のフェーズ文書・計画は維持（削除・変更なし）。

備考
- まずは TLS 方式で単一FBモデルを安定化（動かすことを最優先）。その後、余力があれば IRBuilder/LowerCore に FB を明示渡しするクリーン版へ段階移行を検討。
- String/Null/Void のConstは暫定的に0へ丸め（必要箇所から段階的に正規化）。
- `jit-b1-abi` 等のunexpected cfg警告は今後整理対象。

関連ファイル
- 追加: `src/backend/abi_util.rs`, `src/backend/mir_interpreter.rs`, `src/runner/modes/mir_interpreter.rs`
- 追加: `apps/tests/mir-const-add/main.nyash`, `apps/tests/mir-branch-ret/main.nyash`
- Cranelift: `src/backend/cranelift/jit.rs`, `src/backend/cranelift/context.rs`, `src/backend/cranelift/builder.rs`
- Semantics: `src/jit/semantics/{mod.rs,clif.rs}`（スケルトン）

メモ/トグル
- LowerCore→ClifBuilder 実IR: `NYASH_JIT_LOWERCORE=1`
- カバレッジログ: `NYASH_JIT_DUMP=1`



Handoff Snapshot (2025-08-31 / Phase 11 kick-off)

- Core-15 凍結（第三案 / Box-SSA）
  - セット: { Const, UnaryOp, BinOp, Compare, TypeOp, Load, Store, Jump, Branch, Return, Phi, Call, NewBox, BoxCall, ExternCall }
  - Optimizer: ArrayGet/ArraySet/RefGet/RefSet/PluginInvoke → BoxCall に正規化（get/set/getField/setField）
  - Verifier: 上記レガシー命令を UnsupportedLegacyInstruction としてエラー化（環境で一時解除可: NYASH_VERIFY_ALLOW_LEGACY=1）
- VM: BoxCall("getField"/"setField") を InstanceBox に配線（fieldsへ委譲）。Arrayの get/set は既存BoxCall経路で動作
- 命令数固定テスト: Core‑15（第三案）へ切替済（tests/mir_instruction_set_sync.rs）
- LLVM 導入（Phase 11 開始）
  - 依存: LLVM 18 + inkwell 0.5.0（features=["llvm18-0"]）。feature `llvm` で有効化
  - ビルド要件: LLVM_SYS_180_PREFIX（例: /usr/lib/llvm-18）, 追加依存: polly, zstd（libzstd-dev 等）
  - 現状のLowering（11.1の最小スケルトン → 11.2 反映）:
    - 対応: Const(Integer/Float/Bool/String/Null), Unary(Neg/Not/BitNot), BinOp（整数/浮動の主要演算）, Compare, Branch/Jump, Return
    - 追加: Phi/Load/Store（最小実装）
    - 追加: NewBox（引数なし→nyash.box.birth_hへ; nyash.tomlの[box_types]からtype_id解決）
    - 追加: BoxCall（ArrayBox.get/set→nyash_array_get_h/set_h 経由の安全パス）
    - 追加: ExternCall（env.console.log/env.debug.trace→libc putsで暫定出力）
    - 未対応（次タスク）: NewBox（引数あり）, 一般BoxCall（by-name/slot 汎用化）, その他ExternCall
  - エントリ: Main.main のみ対象に .o 出力（backend::llvm::compile_to_object）
- ドキュメント更新（phase‑11）
  - README.md: 進行中に更新 / 4週スプリント計画（11.1→11.4）
  - MIR_TO_LLVM_CONVERSION_PLAN.md: PluginInvoke→BoxCall統一、配列はBoxCallとして安全パス→型特化の二段階Lowering
  - MIR_ANNOTATION_SYSTEM.md: setField/getField（BoxCall）前提に更新
  - INSTRUCTION_SET.md: PluginInvokeはDeprecated（BoxCallに統一）

How to Build/Run (recap)

- 通常/JIT: `cargo build --release --features cranelift-jit`
- LLVM（AOTスケルトン）: 
  - 事前: LLVM 18 / inkwell 0.5.0, polly, zstd を導入
  - 例: `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm`
- スモーク: `tools/mir15_smoke.sh release`

Next Steps (Phase 11)

1) 11.1 仕上げ（本タスク）
   - Phi のLowering（BB事前作成→incoming追加）
   - Load/Store（alloca/ローカル表現の最小規約、整数/浮動/ポインタ）
2) 11.2 安全パス（Box/Extern）
   - [実装] NewBox(引数なし)→ `nyash.box.birth_h(type_id:i64)->i64` を呼び、i8*にinttoptr（type_idはnyash.tomlから解決）
   - [実装] Arrayの BoxCall("get"/"set") → `nyash_array_get_h/set_h`（ハンドルi64渡し）
   - [実装] ExternCall: `env.console.log`/`env.debug.trace` は暫定で `puts` に接続（AOTデバッグ用）
   - [残] BoxCall 汎用（by-name/slot）, Field系（getField/setField）, ExternCallの網羅
3) 11.3 最適化導線
   - 注釈（inline/purity/gc/alias）→ LLVM属性/メタデータ
   - 型特化: Array/Field の inline GEP + write barrier
4) 11.4 高度化
   - 脱箱化、TBAA、PGO/ThinLTO

メモ

- Verifier の緩和スイッチ: `NYASH_VERIFY_ALLOW_LEGACY=1`（移行用）。通常はOFFで運用。
- Optimizer のRewrite はLLVM前提のBoxCall統一規約と整合済み。

最優先: MIR命令セットをCore-15に統一し、VM/JIT/AOTを整えてからLLVM(inkwell)へ移行する。

目的: MIR→VM→JIT→AOT の汎用化・単純化を一気に進める。命令の重複・メタ・実装露出を撤去/統合し、Builderが実際に発行するコア命令を最小化する。

現状観測（2025-08-31）

- 実装定義: 37命令（src/mir/instruction.rs）
- Docs: Canonical 26（移行注記・Core-15ターゲット追記済）
- Builder使用: 24命令（自動集計）
  - 上位頻度: Const(19), TypeOp(13), Jump(6), ExternCall(5), Return(3), Call(3)
  - 中頻度: NewBox(2), WeakRef(2), Barrier(2), BoxCall(1), Branch(1), Phi(1), PluginInvoke(1), Await(1)
- JITサポート: 約20命令（ホストコール分は外部委譲で簡素）

統合方針（Core-15）

- 重複統合
  - TypeCheck, Cast → TypeOp に完全統合（Builder 既に主に TypeOp を発行）
  - WeakNew, WeakLoad → WeakRef に統合
  - BarrierRead, BarrierWrite → Barrier に統合
- Box哲学へ移譲
  - Print → env.console.log (ExternCall)（Builder更新済）
  - Debug → DebugBox.trace()/env.debug.trace（ExternCall/BoxCall）
  - Throw, Catch → ExceptionBox（throw/catch相当のBox APIへ移譲; 移行期はRewrite）
  - Safepoint → RuntimeBox.checkpoint（ExternCall）
- 未使用/メタ
  - FutureSet → 一旦廃止（Builder未使用）
  - Copy, Nop → メタ命令（Optim/降格専用; Coreからは除外）

最終ターゲット: Core-15 命令

- 基本演算(5): Const, UnaryOp, BinOp, Compare, TypeOp
- メモリ(2): Load, Store
- 制御(4): Branch, Jump, Return, Phi
- Box(3): NewBox, BoxCall, PluginInvoke
- 配列(2): ArrayGet, ArraySet
- 外部(1): ExternCall（暫定; 将来はBox化でも可）

進め方（Core-15確定 → LLVM）

1) Builder発行の一元化（非破壊）
   - 既に Print→ExternCall 置換済み
   - Builderが TypeCheck/Cast/WeakNew/WeakLoad/BarrierRead/BarrierWrite を発行しないよう整理（既存箇所の差し替え）
   - 既存テスト（builder/optimizer）を ExternCall/TypeOp/WeakRef/Barrier に合わせて更新
2) 互換Rewriteパスの追加（MIR最適化フェーズ）
   - 古いMIR（手書き/スナップショット/ツール）が生成した命令をコア命令に機械的変換
     - TypeCheck/Cast → TypeOp
     - WeakNew/WeakLoad → WeakRef
     - BarrierRead/Write → Barrier
     - Print → ExternCall(env.console.log)
     - Debug → ExternCall(env.debug.trace)
     - Throw/Catch → ExternCall(env.exception.*) もしくは BoxCall(ExceptionBox)
     - Safepoint → ExternCall(env.runtime.checkpoint)
3) VM/JITの段階撤去と整理
   - VM/JIT: コア命令に集中（ホストコール/Box経由のI/Oや例外）
4) Docs/CI
   - INSTRUCTION_SET をCore-15へ更新（26→15マッピング表）
   - 命令数固定テストを「15」に切替

タスク分解（本フェーズ）

- [x] Builderからのレガシー発行のデフォルト停止（WeakNew/WeakLoad/BarrierRead/Writeを統一命令に切替、トグルで復活可）
- [x] MIR Rewriteパス追加（一部完了: Print/Type/Weak/Barrier、Debug/Safepointはトグル）
- [ ] Optimizer/Verifier/Printerの非互換の見直し（Verifierでレガシー命令をエラー化）
- [ ] VM: レガシー命令のコードパスに警告ログ（将来削除フラグ）
- [ ] JIT: コア命令に合わせたテーブル整理（未使用ホストコールの棚卸し）
- [ ] Docs更新（命令セット、移行ガイド、Box哲学との整合）
- [ ] 回帰テスト更新（builder_modularizedを含む一式）

追加の即応ステップ（10.8a）

- [x] Rewrite: Print → ExternCall(env.console.log)
- [x] Rewrite: TypeCheck/Cast → TypeOp、WeakNew/WeakLoad → WeakRef、BarrierRead/Write → Barrier
- [x] Rewrite(トグル): Debug → ExternCall(env.debug.trace)（NYASH_REWRITE_DEBUG=1）
- [x] Rewrite(トグル): Safepoint → ExternCall(env.runtime.checkpoint)（NYASH_REWRITE_SAFEPOINT=1）
- [x] Builder: Try/Catch/Throw/Safepoint の直接発行を抑止（トグル導入・モジュール化系にも適用）
- [x] Runtime: extern_call スタブ追加（env.runtime.checkpoint, env.debug.trace）
- [x] Rewrite(トグル・スキャフォールド): FutureNew/FutureSet/Await → ExternCall(env.future.*) 変換（NYASH_REWRITE_FUTURE=1）

引き継ぎ（2025-08-31 深夜）

サマリ

- JIT予約シンボル: `nyash.rt.checkpoint`, `nyash.gc.barrier_write` を確保（AOT/JITの双方で登録）
- Future/Await Rewrite: `NYASH_REWRITE_FUTURE=1` で ExternCall(env.future.*) に段階導入（runtime最小実装あり）
- Builderレガシー停止: Weak/Barrier 系の直接発行を既定で無効化（統一命令に集約、必要時トグル）
- JIT-direct安定化: entry seal/戻り値制御/シム登録/コード寿命を調整し落ち着かせ済み
- 次の着手順: MIR15のVM/JITカバレッジ拡張 → LLVM(inkwell) 移行

- 完了/修正
  - JIT/AOT 予約シンボルの登録完了（`nyash.rt.checkpoint`, `nyash.gc.barrier_write`）
  - JITスタブ実装（no-op＋トレース）とAOT(nyrt)エクスポートを追加
  - Future/Await Rewriteのスキャフォールド（`NYASH_REWRITE_FUTURE=1`）＋ runtime側`env.future.*`最小実装
  - Builderレガシー停止を既定化（WeakNew/WeakLoad/BarrierRead/Write→統一命令）。必要時はトグルで復活
    - `NYASH_BUILDER_LEGACY_WEAK=1`, `NYASH_BUILDER_LEGACY_BARRIER=1`
  - JIT directの安定化（segfault修正）
    - エントリblockのseal遅延（PHI/引数受け用）
    - MIRシグネチャに基づく戻り値有無（Void関数はret無し/void呼び出し）
    - `nyash.console.birth_h` のJIT内シム追加＋JITBuilder登録
    - finalize済みコードの寿命延長（JITModuleをリークして新モジュールに差し替え）

- カバレッジ確認（MIR15→VM/JIT）
  - 追加ドキュメント: docs/reference/mir/MIR15_COVERAGE_CHECKLIST.md
  - スモークスクリプト: tools/mir15_smoke.sh（実行例: `cargo build --release --features cranelift-jit` → `tools/mir15_smoke.sh release`）
  - 現状OK（JIT-direct）: BinOp, Compare(真偽戻り), Load/Store(ローカル), Branch/Jump/PHI最小, ExternCall(console.log)
  - まだoptional（フォールバックで許容）: 配列/Mapのhostcall系（len/isEmpty/get/push 等）

実行メモ

- ビルド: `cargo build --release --features cranelift-jit`
- スモーク: `tools/mir15_smoke.sh release`
- AOT(.o)簡易出力: `NYASH_AOT_OBJECT_OUT=target/aot_objects ./target/release/nyash --jit-direct examples/aot_min_return_42.nyash`
  - 生成: `target/aot_objects/main.o`
  - 備考: `tools/build_aot.sh` は jit-direct で .o を生成するよう更新済（要検証）

LLVM足場（VM側 先行）

- Escape Analysis（VMのみ）: `NYASH_VM_ESCAPE_ANALYSIS=1`
  - 非エスケープなBoxの `Barrier(Read/Write)` を保守的に `Nop` 化
  - 実装: `src/mir/passes/escape.rs`（NewBox起点のローカル追跡＋Return/Call/Store使用でescape検出）
  - 適用: VM実行前にMIRへ適用（`src/runner/modes/vm.rs`）
  - 目的: LLVM(inkwell)への最適化ヒント連携を見据えた足固め（まずVMで効果検証）

- 次の着手（この順で）
  1) MIR15のVM/JITカバレッジをもう一段拡張（配列/Map hostcallのJIT対応 or optionalのまま明確化）
  2) スモークに代表サンプルを追加し、CI/ローカルでワンコマンド確認
  3) LLVMフェーズ（inkwell）へ移行（Const/Return→BinOp/Compare→CF/PHIの順）

次フェーズ提案

- まずMIR15のVM/JITを固める（hostcallはoptional許容 or 段階実装）
- その後、LLVM（inkwell）へ移行開始

MIRセット（移行メモ）

- 現行の参照ドキュメントは「26命令（Canonical）」を維持（`docs/reference/mir/INSTRUCTION_SET.md`）。
- 実装はCore-15へ段階移行中（TypeOp/WeakRef/Barrier 統合、Print Deprecated）で、MIR15のカバレッジは `MIR15_COVERAGE_CHECKLIST.md` で運用。
- Core-15が安定した時点で参照ドキュメント側を「15命令」に更新し、命令数固定テストも切替える。

- [x] JIT/AOT: 将来のGCバリア/セーフポイント用のシンボル予約（nyash.gc.barrier_write, nyash.rt.checkpoint）

環境変数（段階移行トグル）

- NYASH_BUILDER_SAFEPOINT_ENTRY=1: 関数エントリにSafepointを発行
- NYASH_BUILDER_SAFEPOINT_LOOP=1: ループ各回でSafepointを発行
- NYASH_BUILDER_LEGACY_WEAK=1: 旧WeakNew/WeakLoad発行を有効化（既定: 無効、WeakRefに統一）
- NYASH_BUILDER_LEGACY_BARRIER=1: 旧BarrierRead/Write発行を有効化（既定: 無効、Barrierに統一）
- NYASH_BUILDER_DISABLE_TRYCATCH=1: try/catch/finallyを無効化（try本体のみ）
- NYASH_BUILDER_DISABLE_THROW=1: throwをenv.debug.traceへフォールバック
- NYASH_REWRITE_DEBUG=1: Debug命令をExternCall(env.debug.trace)に書き換え
- NYASH_REWRITE_SAFEPOINT=1: Safepoint命令をExternCall(env.runtime.checkpoint)に書き換え
- NYASH_REWRITE_FUTURE=1: FutureNew/Set/Await を ExternCall(env.future.*) に書き換え（スキャフォールド）
- NYASH_DEBUG_TRACE=1: env.debug.traceのログをstderrに出力
- NYASH_RUNTIME_CHECKPOINT_TRACE=1: env.runtime.checkpointのログをstderrに出力

直近実装（完了）

- AOT/JIT: string-like hostcalls 実装（concat_hh/eq_hh/lt_hh）とLowerer経路、シンボル登録
- Print命令の非推奨化: BuilderでExternCall(console.log)へ統一、Rewriteでも変換
- Builder（legacy抑止のトグル）: Safepoint/Try-Catch/Throwをトグル化、loop safepointも任意化
- Runtime extern_call: env.debug.trace / env.runtime.checkpoint を追加

次の着手（順序）

1. JIT/AOT: GCバリア/セーフポイントのシンボル予約と下準備（nyash.gc.barrier_write, nyash.rt.checkpoint）
2. Docs: 上記トグル/Extern API/命令マッピングの追記（INSTRUCTION_SET, runtime extern, migration）
3. Future/AwaitのRewriteスキャフォールド（NYASH_REWRITE_FUTURE=1）と最小実装方針の明文化（完了）
4. Builderのlegacy API（emit_weak_new/load, barrier_read/write）の非推奨化と使用箇所の削減
5. JIT directのBlock-Sealパニック修正（block seal順序・entry sealの見直し）

期待効果

- 命令 37→15（目安）で読みやすさ/実装コスト/検証コストを大幅削減
- JIT/AOT の対応面積が小さくなり、今回の string-like hostcall のような追加の導入が容易に
- 「Everything is Box」に合致（I/O, 例外, ランタイム機能をBox/Externに集約）

優先度/スケジュール

- 優先度: 最優先（10.5c/10.7に割り込み）
- 目安: 1〜2日でBuilder/Rewrite/Docs、続いてVM/JITの掃除を段階投入


直近スナップショット（2025-08-30 更新）

Current State

- Plugin-First/Handle-First/TLVはAOT/VMで安定（10.5e完了状態を継続）
- 10.6計画（Thread-Safety/Scheduler）と10.7計画（トランスパイルAll-or-Nothing）を確定
- Nyash-onlyパイプライン（tools/pyc）を開始（Parser/CompilerはNyashで実装方針）
- include式の最小実装を追加（式でBoxを返す／1ファイル=1static box）
  - インタプリタ: include式は実行時評価
  - VM/AOT: MIRビルダーが取り込み先を同一MIRに連結（MIR命令は増やさない）
  - nyash.tomlの[include.roots]でルート解決（拡張子省略、index.nyash対応）
- tools/pycをモジュール分割
  - tools/pyc/pyc.nyash（エントリ: includeでPyIR/PythonParserNy/PyCompilerを取り込み）
  - tools/pyc/PyIR.nyash, PythonParserNy.nyash, PyCompiler.nyash（Nyash-only実装）

How To Run（Nyash-only）

- VM: `NYASH_PY_CODE=$'def main():\n  return 42' ./target/release/nyash --backend vm tools/pyc/pyc.nyash`
  - 出力: Parser JSON → IR（return 42）→ 生成Nyashソース（現状は骨組み）
- include動作サンプル: `./target/release/nyash --backend vm examples/include_main.nyash`（Math.add(1,2)=3）

進捗（2025-08-30 夜）

- include: 循環検出を追加（インタプリタ/VM収集器ともにロード中スタックで経路出力）。examples/cycle_a/b で検証
- tools/pyc: 最小IR（return定数）→Nyash生成を通し、出力をprintまで接続
- 文字列基盤: VMにString統一ブリッジを着手（内部StringBoxとプラグインStringBoxの比較互換、内部Stringメソッドのフォールバック）
- 追加プラグイン（小粒・基底）
  - RegexBox（compile/isMatch/find/replaceAll/split）: examples/regex_min.nyash
  - EncodingBox（utf8/base64/hex）: examples/encoding_min.nyash
  - TOMLBox（parse/get/toJson）: examples/toml_min.nyash
  - PathBox（join/dirname/basename/extname/isAbs/normalize）: examples/path_min.nyash

Next Steps（優先順・更新）

1. String統一ブリッジ（実装済・一次完了）
   - VM: 比較/加算/代表メソッドのフォールバック（length/isEmpty/charCodeAt/concat/+）をstring-like正規化で実装
   - Interpreter: 比較/加算はstring-like正規化を適用（メソッドは後続で最小追補があれば対応）
   - 例: encoding_min/regex_min/toml_min/path_min で回帰確認
2. AOT/JITへのブリッジ降ろし（MIR→VM→JIT→exeの汎用性維持・ハードコーディング禁止）
   - 文字列演算のhostcall化（read-only）: nyash.string.concat_hh / eq_hh / lt_hh
   - Lowerer: BinOp(Add) / Compare(Eq/Lt) を「string-like」判定時にhostcallへフォールバック
   - 代表メソッド: length/isEmpty/charCodeAtは既存hostcall経由で維持、concat(メソッド)も追加検討
   - Registry: 署名/権限（ReadOnly）登録、シンボル解決とJITビルダー登録
   - 目標: examples/string_bridge_min.nyash をAOTでも成功
3. tools/pyc: IR→Nyashの反映強化（return/If/Assignを安定化、Strictスイッチ連動）
4. Strictスイッチ: tools/pyc（unsupported_nodes非空でErr、envでON/OFF）
5. CLI隠しフラグ `--pyc`/`--pyc-native`（Parser→Compiler→AOTの一本化導線）
6. 最小回帰（VM/AOTの差分記録）とdocs追補（include/exportとpyc、Regex/Encoding/TOML/PathのAPI概要）

Env Keys（pyc）

- NYASH_PY_CODE: Pythonソース文字列（Nyash-onlyパイプライン/Parser用）
- NYASH_PY_IR: IR(JSON)直接注入（Rust雛形Compilerの確認用・オプション）

目的: Handle-First + by-name を軸に、Python統合（PyRuntimeBox/PyObjectBox）を汎用・安全に実装する。最適化は後段。さらに10.7のNyash-onlyトランスパイルC2（pyc）を最小構成で立ち上げる。

ステータス（2025-08-30 更新）

- フェーズ: 10.5c 汎用Handle/TLV実装の拡張（Python統合開始）
- 方針: 「綺麗に作って動かす」= ハードコーディング排除・Handle/TLV統一・最適化は後回し

10.5b 完了項目（橋渡し済み）

- by-name シム（getattr/call）を実装（JIT/AOT）し、Lowerer から a0 を `nyash.handle.of` で確実にハンドル化して呼び出し
- 引数 a1/a2 はハンドル優先／なければレガシー参照から TLV 構築（String/Integer はプリミティブ化）
- 汎用 birth シムを追加
  - `nyash.box.birth_h(type_id:i64)->i64`（JIT/AOT）
  - `nyash.box.birth_i64(type_id:i64, argc:i64, a1:i64, a2:i64)->i64`（JIT/AOT）
  - Lowerer: NewBox（引数無し）は birth_h に統一。引数ありは安全なケース（Integer const／引数が既にハンドル）だけ birth_i64 に段階導入
- AOT: examples/aot_py_math_sqrt_min.nyash で Strict でも .o 生成を確認（target/aot_objects/main.o）
- ログ
  - AOT: NYASH_CLI_VERBOSE=1 で birth_h の可視化
  - JIT: events で by-name/birth の観測（必要十分の最小限）

10.5c 着手項目（進行中）
- Lowerer: PluginInvoke（type_id/method_id & by-name）の Handle-First 配線を統一（a0を常にnyash.handle.of）
- JIT/AOT: birth（_h/_i64）と by-name シムでTLV生成を汎用化（String/Integerはプリミティブ化、他はHandle）
- Strict時のJIT実行停止（コンパイル専用）でVM=仕様の原則を徹底

非対応（後回し・最適化）

- StringBox 専用の known_string/再利用最適化
- 汎用的な定数プール／birth の可変長 TLV 一括最適化

次の作業（10.5c 続き）

1) FFI仕様の短文化（a0/a1/a2=Handle優先→TLV、レガシー抑止フラグ、戻りTLVのdecodeポリシー）
2) birth引数の一般化メモ（可変長TLV、例外時ハンドリング）
3) Python統合の最小チェーン（import→getattr→call）のAOT/VM双方での実装確認サンプル追加
4) ドキュメント更新（10.5c README/INDEX、FFIガイド）

合意済みルール

- まず汎用・安全に動かす（最適化は内部に隠し、後段）
- StringBox 等の個別特化は入れない。Handle/TLV で統一し、Box 追加を阻害しない
- Strict/Fail‑Fast を維持（fallback で隠さない）
Update (2025-09-02 AM / Async unify + VM await fix + JIT AOT builder plan)

- What’s implemented (since last update)
  - Interpreter/VM/JIT await semantics unified to Result.Ok/Err.
    - Interpreter: await now returns Ok(value) or Err("Timeout") with cooperative polling and NYASH_AWAIT_MAX_MS guard.
    - VM: execute_await() changed to safepoint + scheduler.poll loop with timeout → Err("Timeout") on expiry, Ok(value) on success.
    - JIT: await_h produces handle (0 on timeout), then ok_h/err_h wrap into Result.Ok/Err (already wired).
  - TaskGroup scaffolding connected to Interpreter
    - nowait registers Future into implicit TaskGroup; function/static/parent calls push/pop task scopes to enable join on scope exit.
  - TokenBox added as a first-class Box
    - New Box: TokenBox (wraps CancellationToken). Externs: env.task.currentToken() → TokenBox, env.task.cancelCurrent() → cancel current scope token.
  - Delay future (scheduler-backed)
    - Extern: env.future.delay(ms) → FutureBox that resolves to void after ms (uses SingleThreadScheduler.spawn_after or thread fallback).
  - CLI result normalization (interpreter path)
    - When printing results, prefer semantics::coerce_to_i64/coerce_to_string and special-case plugin IntegerBox.get() so “IntegerBox(id)” prints as numeric value.

- New samples (smoke-friendly)
  - apps/tests/mir-safe-min: minimal MIR (plugins disabled)
    - Run: `NYASH_DISABLE_PLUGINS=1 ./target/debug/nyash --backend mir apps/tests/mir-safe-min/main.nyash` → Result: 3
  - apps/tests/async-nowait-basic: Interpreter nowait/await using threads
    - Run: `NYASH_DISABLE_PLUGINS=1 ./target/debug/nyash apps/tests/async-nowait-basic/main.nyash` → Result: 33
  - apps/tests/async-scope-token: VM token + delay demo (plugins on)
    - Run: `./target/debug/nyash --backend vm apps/tests/async-scope-token/main.nyash`
    - Output: token: …; after delay; token after cancel: …; Result: 0
  - apps/tests/async-await-timeout: VM await timeout demo
    - Run: `./target/debug/nyash --backend vm apps/tests/async-await-timeout/main.nyash`
    - Output: `Err(Timeout)` then Result: 0

- JIT (execute) status
  - `--backend cranelift` (skeleton) runs: `apps/tests/mir-branch-ret` → Result: 1
  - JIT-direct path compiles/executes for simple cases (single-exit return strategy in place, PHI materialization to locals, etc.).

- JIT (AOT/EXE) current blocker and plan
  - Symptom: jit-direct path panics in Cranelift FunctionBuilder finalize: “FunctionBuilder finalized, but block block0 is not sealed”.
  - Root cause: Current CraneliftBuilder repeatedly creates short‑lived FunctionBuilder instances and finalizes them per emission step; sealing discipline diverges from expected pattern (single FunctionBuilder per function, seal blocks after predecessors known). Entry sealing/ret-epilogue sealing were added, but per‑step finalize still violates constraints.
  - Plan (box-first, clean layering)
    1) Refactor CraneliftBuilder to hold a single FunctionBuilder per function lifetime.
       - Maintain current block, value stack, and IR emission without re‑creating/finalizing FB on every op.
       - Emit jump/branch/hostcall/phi consistently in the same FB.
       - Seal blocks when predecessors are determined (via LowerCore callbacks), and perform a final seal sweep before define_function.
    2) Keep ObjectBuilder (AOT .o path) returning directly (no ret_block), unchanged aside from any minimal alignment with single‑FB pattern (it already returns directly and finishes module per function).
    3) Target sample: apps/tests/mir-branch-ret for first green AOT object emission.
       - Success criteria: tools/build_aot.sh invoked via `--compile-native -o app` produces an executable that prints Result: 1.
    4) After branch/ret green, extend to minimal PHI case (mir-phi-min) ensuring paramized block args are declared prior to seals.

- Interim guidance
  - For JIT testing use `--backend cranelift` (skeleton exec) or VM path with `NYASH_JIT_EXEC=0` unless running jit-direct read‑only smokes.
  - For AOT/EXE, wait for the single‑FB refactor merge; current tools/build_aot.sh in strict mode forbids fallback and will fail on the sealing assertion.

- Env toggles / helpers
  - Await timeout: `NYASH_AWAIT_MAX_MS` (default 5000)
  - Scheduler trace/budget: `NYASH_SCHED_TRACE=1`, `NYASH_SCHED_POLL_BUDGET=N`
  - JIT lower dump/trace: `NYASH_JIT_DUMP=1`, `NYASH_JIT_TRACE_RET=1`, `NYASH_JIT_TRACE_BLOCKS=1`
  - JIT policy (read-only in jit-direct): `NYASH_JIT_STRICT=1` and policy.read_only enforced

- Next actions (execution order)
  1) CraneliftBuilder: single FunctionBuilder per function（finalize at end_functionのみ）。
     - Remove per‑op new/finalize; switch emit_* to use the persistent FB.
     - Seal entry immediately; seal successors when wiring is complete; final global seal sweep before define_function.
  2) Verify jit-direct with `apps/tests/mir-branch-ret` (NYASH_JIT_THRESHOLD=1).
  3) Enable AOT object emission for the sample and link via tools/build_aot.sh; run resulting EXE (expect Result: 1).
  4) Extend to `mir-phi-min` (ensure ensure_block_params + sealing order correct).
  5) Wire tri-backend/async/timeout smokes in tools/ (minimal, concise outputs) and add to CI.
