docs: restore docs/private/roadmap from 7b4908f9 (Phase 20.31)
This commit is contained in:
@ -0,0 +1,386 @@
|
||||
# Phase‑31 — Box Normalization(Static→Singleton 正規化)
|
||||
|
||||
最終更新: 2025‑10‑22(Verifier 移行表追加/quick profile の intern 監視を静音化)
|
||||
|
||||
## サマリ
|
||||
- ねらい: すべてのメソッド呼び出し形を「me + args」に統一し、static box を型ごとのシングルトンインスタンス(`Type.singleton`)に正規化する。
|
||||
- 効果: ルータ分岐削減、receiver 有無によるバグ根絶(今回の ArrayBox(1) 類)、Extern/HostBridge 経路の単純化、AOP/計測の注入点の一元化。
|
||||
- 方式: Builder で `Static(Type.method(args)) → Instance(Type.singleton.method(args))` に書換。ルータは常に receiver を渡す。Verifier で逸脱を Fail‑Fast。
|
||||
- 導入: フラグ既定OFFで段階導入(A→B→C)。プラグイン側で `len`/`length` エイリアスを正規化(トランポリン撤退済み)。
|
||||
|
||||
### 追加計画(Phase‑31 取り込み)— MIR 正規化とアーキ境界の固定
|
||||
- MirCall 一本化(最小カノニカル形)
|
||||
- 許可: `Method` / `ModuleFunction("Box.m/arity")` / `Constructor` / `Extern`(補助: `Value`/`Closure`)
|
||||
- 禁止: Legacy `BoxCall/ExternCall/Print/生 NewBox`、Box Eq/Ne(Enum は `.equals()`、その他は `nyrt.ops.op_eq`)
|
||||
- 参考: `docs/development/architecture/mir/mir-canonical-calls.md`
|
||||
- Three Rings(Core/Meta/Domain)で責務を分離
|
||||
- Meta は「プラグイン様式で実装」だが既定は内蔵(LTO/inline)。Domain は外部プラグイン。Core は不可抜き。
|
||||
- 参考: `docs/development/architecture/three-rings.md`
|
||||
- 二層エクスポート(Stable ABI + Inlinable API)
|
||||
- 既知先は直呼び(Known/Rewrite)/未知先は rt_boxcall 集約。Intern(安定ID)で解決子を決定化。
|
||||
- 参考: `docs/development/architecture/abi/two-layer-export.md`
|
||||
|
||||
実施方針(段階導入・既定OFF)
|
||||
- Phase A(Docs/型定義のみ): 文書の追加・MirCall::CallFlags の拡張(may_throw/tail_ok/inline_hint)
|
||||
- Phase B(Builder/Verifierの小正規化): NewBox→Constructor、Print撤退、Box Eq/Ne 正規化(strictガードは既存を拡張)
|
||||
- Phase C(Known/Rewrite 最適化・Metaのみ): Enum/Callable の純粋メソッドを直呼び(パリティスモーク追加)
|
||||
- Phase D(恒久化): レガシー禁止を既定ON、Intern ID 既定ON(ダンプは name+id 併記)
|
||||
|
||||
### Phase C.1(Selfhost Parity — MirCall/Static Box/Constructor)
|
||||
- 目的: Rust 線(Builder/VM/LLVM)の MirCall 正規形と Selfhost(Hakorune Script)の Compiler/VM を同形に揃える(SSOT)。
|
||||
- 範囲:
|
||||
- Selfhost VM: ModuleFunction 名を受理時に `Box.method/arity` へ正規化(将来は Emitter 側で常時 `/arity` 付与)。
|
||||
- Selfhost VM: `Callee::Constructor{box_type}` を処理し birth 呼び出しまでを担当。legacy `NewBox` は不可。
|
||||
- Selfhost Emitter: ModuleFunction 発行ヘルパを追加し、`/arity` の付与を一元化。
|
||||
- 非目標:
|
||||
- Stage‑1 JSON の糖衣→正規形(RewriteKnown 本実装)は次フェーズで導入。
|
||||
- 検証:
|
||||
- quick/integration スモークのパリティ回帰ゼロ(ModuleFunction `/arity` 有無・Constructor 0/1/2/3)。
|
||||
|
||||
### 今日の更新(P0仕上げ+P1 部分)
|
||||
- host anchors: `nyash_array_new_h` を既定ON(feature gate 撤去)。
|
||||
- extern_adapter(Array/Map): `nyrt.array.size` 受領者の HostHandle unwrap/Map.keys/values/size の dev ログ追加。
|
||||
- Router 再配線: `PluginBoxV2` の Array/Map スロットを表テーブル前提で正規に通す(builtin/plugin 両経路)。
|
||||
- env 読み統一: runtime 配下の直 `std::env::var` を `env_gate_box` に寄せ(進行中)。
|
||||
- Router/Adapter 回帰テスト: `map_host_keys_values_return_arrays` / `map_remove_returns_removed_array_len` などを追加し、HostSlot/Plugin 両経路で ArrayBox が返ることを固定。
|
||||
- Type ID 単一起点: Router/extern/loader から直 `builtin_type_id("MapBox")` や固定値参照(11/12/13)を排除し、`crate::types::ids::{map,array,string,by_name}` へ統一。rg 監視で再発チェックを継続。
|
||||
- Reentrant Guard(host slot 中の再入許可): Map.values() → Array.set の再入を slot 配下のみ許可し、連鎖を安定化。
|
||||
- 実装: `host_api::nyrt_host_call_slot` 実行中に thread‑local `IN_HOST_SLOT=true` を設定し、`plugin_loader_unified` のガードを `recursed && !in_slot` に変更。
|
||||
- 効果: values→Array.set→Array.size の連鎖が正しく成立。代表スモーク `map_values_array_element_vm` は PASS。
|
||||
|
||||
#### Runtime meta 層(Callable/Future)の箱化(追加)
|
||||
- ねらい: 言語機能の足場(Callable/Future)をホスト所有の薄い箱として分離し、プラグイン/外部I/Oの逆流を構造で防止。
|
||||
- 実装: `src/runtime/meta/{callable,future}/` を新設。README と LAYER_GUARD で責務を明記。
|
||||
- 互換: 既存の `runtime::{callable_box,future_box}` re-export は撤去済み。新規・既存ともに `runtime::meta::{callable,future}` を使用。
|
||||
- 影響: plugin-only/legacy いずれのビルドでも Callable/Future が安定(router/scheduler への依存のみ)。
|
||||
|
||||
#### HostHandle -14 検知(境界テストの安定化・追加)
|
||||
- ENV: `HAKO_HOSTHANDLE_TEST_RET_MISMATCH=1`(互換 `NYASH_HOSTHANDLE_TEST_RET_MISMATCH=1`)で String.len 経路を -14 として観測。
|
||||
- 実装: VM の HostSlot/Extern で rc を stdout に `hosthandle-test rc=-14` として出力(テスト専用)。
|
||||
- スモーク: `tools/smokes/v2/profiles/plugins/hosthandle_boundary_suite_vm.sh` は一時ファイルに退避してから `-14` を grep(PIPE 経由の出力欠落を回避)。
|
||||
|
||||
#### P1 安定化(今回分)
|
||||
- builtin ルータ: ARRAY/MAP の host route 判定を dev‑only ログで観測可能に(`HAKO_DEBUG_HOST_SLOT=1`)。
|
||||
- extern_adapter: Array/Map のレガシー分岐を撤去し、HostHandle unwrap をハブ化。`nyrt.array.size`/`nyrt.map.{keys,values,size}` の戻り値を正規化。
|
||||
- 回帰テスト追加:
|
||||
- ParameterGuardBox(ENV ON/OFF)。
|
||||
- ループヘッダ PHI 即時挿入(先頭固定・更新 in‑place)。
|
||||
- DCE: Method 受け手/Closure captures の Copy 温存。
|
||||
- Router/Adapter(今回追記):
|
||||
- `map_host_keys_values_return_arrays` — HostSlot 強制下で keys/values → ArrayBox → len が成立することを固定(ユニット)。
|
||||
- `map_remove_returns_removed_array_len` — remove が削除値(ArrayBox)を返し、直後に len を呼べることを固定(ユニット)。
|
||||
|
||||
### 次の一手(B段)— プラグイン互換トランポリン撤退(完了)
|
||||
- 旧互換ラッパ(`HAKO_PLUGIN_TRAMPOLINE`)は 2025-10-18 時点で撤去。
|
||||
- len/length エイリアスは各プラグイン(ArrayBox/MapBox/StringBox)が直接解決済み。
|
||||
- 追加ガードは不要。以降はプラグイン本体と Router テーブルで整合を維持する。
|
||||
|
||||
## スコープ / 非対象
|
||||
- 対象
|
||||
- 呼び出し形状の統一(MIR/Builder/Router/Verifier)
|
||||
- プラグイン/Extern/HostBridge の呼び出し規約整合
|
||||
- selfhost 側の静的メソッド(Hako)→ instance 形の糖衣
|
||||
- 非対象(今回やらない)
|
||||
- 言語仕様の新規拡張(デフォルト引数・可変長シンタックスなど)
|
||||
- 既存最適化のチューニング(導入後に計測して別フェーズ)
|
||||
|
||||
## ゴール(受け入れ基準)
|
||||
- すべての static 呼び出しが MIR 上で `receiver=Type.singleton` に正規化される。
|
||||
- ルータは receiver を常に受ける前提で動作し、static/instance の分岐が無い。
|
||||
- Verifier が「receiver 欠落」や「static 直呼び」を検出して Fail‑Fast(開発時)。
|
||||
- プラグイン ABI は各 Box resolver が直接エイリアスを提供(トランポリンなし)。既存スモーク(quick→plugins→full)緑。
|
||||
- HostBridge/Extern の呼び出しは `me + args` 規約に統一。引数正規化(プリミティブ化)で再発無し。
|
||||
|
||||
## 非機能(性能/安定)
|
||||
- LLVM/VM: `me` 未使用は inlining + DCE で最終的に消える(同一バイナリ/LTO 前提)。
|
||||
- 動的リンク(.so)越し: 追加 1 引数のコストは微小。必要箇所は旧 ABI のエイリアスを維持。
|
||||
|
||||
---
|
||||
|
||||
## 設計(構造)
|
||||
### 1) 呼び出し正規化(Builder)
|
||||
- 変換規則(疑似):
|
||||
- `Call ModuleFunction("Type.method/N", args)` かつ `method != birth` → `Callee::Method { box_name: "Type", receiver: Some(Type.singleton), method }`
|
||||
- 既に instance の場合は変換無し。
|
||||
- 影響ファイル(予定):
|
||||
- `src/mir/builder/calls/method_resolution.rs`
|
||||
- `src/mir/builder/builder_calls/*`(ModuleFunction 経路)
|
||||
|
||||
### 2) ルータ(VM/ランタイム)
|
||||
- 常に `receiver` を渡す前提に一本化(static/instanceの分岐を削除)。
|
||||
- 不変: `birth()` の取り扱い(自動/明示)は既存契約維持。
|
||||
- 影響(例):
|
||||
- `src/backend/mir_interpreter/handlers/calls/function.rs`(ModuleFunction ブリッジ)
|
||||
- `src/backend/mir_interpreter/handlers/boxes/legacy/mod.rs`(BoxCall ディスパッチ)
|
||||
- `src/runtime/method_router_box/*`(外部/Plugin 経路の期待形)
|
||||
|
||||
### 3) Verifier(Fail‑Fast)
|
||||
- ルール:
|
||||
- ModuleFunction 直呼び(static 形)が残っていたらエラー。
|
||||
- Method の `receiver=None` は禁止。
|
||||
- static 正規化の `me` は観測不可(反射禁止)…観測を試みるパスを警告/エラー。
|
||||
- 影響: `src/mir/verify/*`
|
||||
|
||||
### 4) プラグイン ABI 互換(直接 alias)
|
||||
- len/length などの互換は各プラグインの `resolve` 実装で提供。
|
||||
- 追加トランポリンや自動生成スクリプトは不要。
|
||||
|
||||
### 5) HostBridge/Extern(橋渡しの一元化)
|
||||
- 規約: `Extern(iface.method)` のハンドラは常に `me + args` 形に揃える(必要なら内部で `singleton` を補う)。
|
||||
- 引数正規化: BoxRef(ArrayBox 等)→プリミティブ化は既存の `normalize_extern_arg`(VM)へ集約。
|
||||
|
||||
---
|
||||
|
||||
## ガード/フラグ
|
||||
- `HAKO_STATIC_AS_SINGLETON=1`(NYASH_* alias 可) … 既定OFF、A/B/C 段階で切替。
|
||||
- CLI 既定は変更しない。ENV は短命(導入〜安定化まで)。
|
||||
|
||||
## ドキュメント / LAYER_GUARD
|
||||
- `docs/development/proposals/` に本設計の背景と対処(この文書を索引)。
|
||||
- LAYER_GUARD(意図)
|
||||
- Router 層: 「receiver 必須」。ModuleFunction の直参照禁止。
|
||||
- Builder 層: static→singleton 正規化必須。抜けはテストで遮断。
|
||||
- Extern 層: プリミティブ引数化と `me+args` 契約。
|
||||
|
||||
---
|
||||
|
||||
## 段階導入(A/B/C)
|
||||
### Phase A(実験・既定OFF)
|
||||
- 実装
|
||||
- Builder 正規化(static→singleton)
|
||||
- ルータ分岐の掃除(receiver 常時)
|
||||
- Verifier 追加(開発時のみ Fail)
|
||||
- プラグイン resolver の alias 対応を確認
|
||||
- スモーク
|
||||
- static/instance 同名メソッドの一致
|
||||
- HostBridge 経路(extern)での等価性
|
||||
- 成果: quick 緑 + plugins 代表 PASS
|
||||
|
||||
### Phase B(小正規化・互換検証)
|
||||
- Builder 正規化
|
||||
- ModuleFunction の `me` 注入を emit 段に集約。Builder 出力はユーザ引数のみ。
|
||||
- Print を入口で `env.console.log` 経路へ統一(`MirInstruction::Print` 撤退)。
|
||||
- `NewBox` 発行を Constructor 呼び出しに統一(tests では `crate::tests::support::constructor_call` で固定)。
|
||||
- Eq/Ne の Box 比較は既定で `nyrt.ops.op_eq`/Enum は `.equals()` 正規化。プリミティブのみ Compare を維持。
|
||||
- Verifier 強化
|
||||
- Legacy 禁止リストに `NewBox` を追加(既定ON)。
|
||||
- static ModuleFunction の `me` 欠落/型不一致を Fail-Fast する検査を追加。
|
||||
- Optimizer / Runtime
|
||||
- Constructor callee を VM handler で取り扱い(既存 `handle_new_box` に委譲)。
|
||||
- Lifecycle ガード(NewBox→birth)の検査を Constructor 経路にも対応。
|
||||
- テスト
|
||||
- 既存 MIR ユニットを Constructor 経路に移行し、受領者/Alloc 効果を固定。
|
||||
|
||||
### Phase C(完了: Meta Known + Intern 観測)
|
||||
- Meta Known/Rewrite
|
||||
- `EnumBox` 純粋メソッド(tag/arity/get/equals/toString)を ModuleFunction 経由で統一 → Optimizer が `Method(receiver=Type.singleton)` に縮約。
|
||||
- `ArrayBox`/`StringBox` `methodRef/2` を ModuleFunction 呼び出しへ統一し、CallableBox 経路の素材化を一本化。
|
||||
- `CallableBox.arity/0` は READ 効果に固定(call/async pipeline と分離)。
|
||||
- Gate: `NYASH_REWRITE_META_KNOWN`(既定ON/opt‑out: `=0`)。
|
||||
- Intern 観測
|
||||
- `NYASH_DUMP_INTERN=1` で ModuleFunction/Extern 名 ↔ 64bit 安定ID を逐次ダンプ(デバッグ向け)。
|
||||
- `NYASH_DUMP_INTERN_TABLE=1` で関数単位の集計を1回ダンプ(必要時に quick profile で opt-in)。
|
||||
- Selfhost(Hakorune Script)ラインも同じ MirCall 正規形で出力し、Rust VM/LLVM とパリティ確保済み。
|
||||
|
||||
### Phase D(恒久化へ移行中)
|
||||
- Verifier
|
||||
- Legacy 禁止(Print / 生 NewBox / Box Eq・Ne / ModuleFunction `me` 注入違反)を既定ONに固定。strict モードは警告専用へ移行。
|
||||
- Optimizer
|
||||
- Builder で完了した Print/Constructor 正規化の重複Rewriteを撤去し、統一経路のみ残す。
|
||||
- Known/Rewrite の safe whitelist をメタ箱全般に拡張(CallableBox など追加分を段階導入)。
|
||||
- Intern
|
||||
- Stable ID 採用(Callee payloadに name+id を併記)への布石として API/ドキュメントを整備。
|
||||
- スモーク/プロファイル
|
||||
- integration profile の自己ホスト parity 期待値を現行 resolver 診断に合わせて更新し、常緑化を完了。
|
||||
- quick profile は既定で quiet(`NYASH_DUMP_INTERN_TABLE=0`)。観測が必要なときのみ opt-in する。
|
||||
- 2025‑10‑22 時点: quick profile で `userbox_birth_to_string_vm` など 9 件が未緑。
|
||||
- `setField` が static singleton 正規化前の経路を通っており、Phase‑31 B/C の follow-up(UserBox/Enum マクロ)で修正予定。
|
||||
- HakoruneJsonCursorBox.* の `/arity` 付与、using strict 系の exit code/nyash.toml 整理も同バッチで扱う。
|
||||
- Integration 既定(env/log ポリシー):
|
||||
- `HAKO_QUIET=1`, `HAKO_DISCOVER_MODULES=0`, `NYASH_NYRT_SILENT_RESULT=1`
|
||||
- Meta Known/Rewrite 既定ON(`NYASH_REWRITE_META_KNOWN=1`)/Intern Table は既定OFF
|
||||
- Macro runner の子プロセスを無効化(argv超過/ノイズ抑止)
|
||||
- `NYASH_MACRO_BOX_CHILD=0`, `NYASH_MACRO_BOX_CHILD_RUNNER=1`, `NYASH_NY_COMPILER_TIMEOUT_MS=4000`
|
||||
- ランナーの `filter_noise` で `[macro]` 系/`-- child stderr --` を抑制(詳細は env ガイド参照)
|
||||
|
||||
### P0(直近の仕上げ — 小さく強い箱の固定化)
|
||||
- UsingResolver の SSOT 化(入口一本化)
|
||||
- `UsingResolver.resolve(entry) -> ModuleSet` を runner/CLI/tests の単一起点にする。
|
||||
- ENV の解釈は UsingResolver 内に集約。下流は `ModuleSet` のみを受領。
|
||||
- Verifier 既定ONの拡張
|
||||
- Legacy 命令(Print/BoxCall/ExternCall/生 NewBox)を禁止(既定ON)。
|
||||
- Box Eq/Ne の Compare を禁止(Enum は `.equals()`/その他は `nyrt.ops.op_eq`)。
|
||||
- ModuleFunction `me` 注入違反(欠落/型不一致)を Fail‑Fast。
|
||||
- LLVM Resolver 健全性ガード(debug)
|
||||
- ret 値が Exit 内定義 or Exit‑PHI の不変条件を debug_assert で検査。
|
||||
- Exit‑PHI 作成時に preds と incoming が一致することを検査。
|
||||
|
||||
#### Verifier 移行表(strict → 既定ON)
|
||||
|
||||
| チェック内容 | strict 導入 | 既定ON | 備考 |
|
||||
| --- | --- | --- | --- |
|
||||
| `MirInstruction::Print` 検出(Print 経路の禁止) | Phase B(dev gate) | Phase D | Builder/Emitter で `env.console.log` 正規化済み。 |
|
||||
| `NewBox` 命令の禁止(Constructor 経路のみ許容) | Phase B | Phase B | Builder 正規化と同時に既定ON。 |
|
||||
| Box Eq/Ne の直接 Compare 禁止(Enum は `.equals`) | Phase B | Phase D | `NYASH_ENUM_STRICT` 併用で Enum の診断を強化。 |
|
||||
| ModuleFunction `me` 注入違反(欠落/型不一致) | Phase B | Phase D | `emit_guard` 側での receiver 素材化と連動。 |
|
||||
| Enum Compare(Eq/Ne)(`.equals` 以外の経路) | Phase B | (開発フラグ) | `NYASH_ENUM_STRICT=1` で強制。将来 Phase‑32 で既定ON 予定。 |
|
||||
|
||||
---
|
||||
|
||||
## 変更対象(実施済/予定ファイル・開始行)
|
||||
- Builder
|
||||
- `src/mir/builder/calls/method_resolution.rs`(静的→受領者注入)
|
||||
- VM/Router
|
||||
- `src/backend/mir_interpreter/handlers/calls/function.rs`
|
||||
- `src/backend/mir_interpreter/handlers/boxes/legacy/mod.rs`
|
||||
- `src/runtime/method_router_box/*`
|
||||
- Verifier
|
||||
- `src/mir/verify/*`(新規/既存拡張)
|
||||
- プラグイン/Extern
|
||||
- `src/backend/mir_interpreter/handlers/calls/legacy/extern_handler.rs`(規約コメント追加・整合)
|
||||
|
||||
---
|
||||
|
||||
## テスト計画
|
||||
- 単体
|
||||
- static→singleton 正規化の生成確認(MIR 形状)
|
||||
- receiver 欠落時の Verifier エラー
|
||||
- 結合
|
||||
- Router(builtin/plugin)での一貫ディスパッチ
|
||||
- HostBridge(extern)経路の文字列/数値/配列の正規化
|
||||
- スモーク
|
||||
- quick→plugins→full の差分比較(代表)
|
||||
- selfhost 側の静的 API(Hako)
|
||||
- meta 層の代表確認(plugins プロファイル):
|
||||
- `tools/smokes/v2/profiles/plugins/callable_async_plugin_vm.sh`(Future 表示安定)
|
||||
- `tools/smokes/v2/profiles/plugins/plugin_map_len_vm.sh`(len エイリアス整合)
|
||||
- `tools/smokes/v2/profiles/plugins/set_bad_arity_vm.sh`(arity ガード Fail‑Fast)
|
||||
- 受け入れ基準
|
||||
- 既存スモーク緑 + 新規スモーク(static/instance 等価)緑
|
||||
- LLVM/VM 出力差異がゼロ/許容範囲
|
||||
|
||||
---
|
||||
|
||||
## リスクと対策
|
||||
- 互換性リスク(プラグイン): resolver alias を Fail-Fast 方針で維持。段階導入。
|
||||
- 反射の観測: LAYER_GUARD と Verifier。ドキュメントで未定義化を宣言。
|
||||
- 性能劣化: ベンチで観測し、必要ならホットパスのみ旧 ABI 直呼びエントリを併存。
|
||||
|
||||
## ロールバック
|
||||
- `HAKO_STATIC_AS_SINGLETON=0` で旧挙動へ即時復帰。
|
||||
|
||||
---
|
||||
|
||||
## 実装 TODO(P0→)
|
||||
1. Builder に static→singleton 正規化を実装(最小: String/Array/Map 代表)
|
||||
2. Router の receiver 常時渡しを再点検(不要分岐の撤去)
|
||||
3. Verifier 追加(ModuleFunction 直呼び/receiver 欠落の Fail)
|
||||
4. スモーク追加(static/instance 等価、extern 経路)
|
||||
5. Docs 反映(ガイド/リファレンス/ENV 記載)
|
||||
|
||||
### 本日の優先P0(追記)
|
||||
- Array.size 正規化の徹底(Builder normalize → `Extern("nyrt.array.size")` 固定、Optimizer で巻き戻し禁止)
|
||||
- EmitGuard 後の LocalSSA 素材化の再確認(values→size 連鎖で未定義参照を出さない)
|
||||
|
||||
|
||||
## 付録(インターフェース最小定義)
|
||||
- `Type.singleton(): &Type`(内部/once 初期化、外部観測不可)
|
||||
- 呼び出し正規化: `Static(Type.method(args)) → Method(Type.singleton, args)`
|
||||
- Verifier: ModuleFunction 直呼び/receiver=None を禁止
|
||||
|
||||
---
|
||||
|
||||
> 補足: 今回のバグ(ArrayBox(1) 漏れ)の根は「受け渡し規約が2通りあった」こと。構造で1通りに揃えるのが再発防止の最短路だよ。
|
||||
|
||||
---
|
||||
|
||||
## 進捗(実装済み)
|
||||
|
||||
### Phase A‑1b — 関数スコープのシングルトン・キャッシュ導入(完了)
|
||||
- 目的: `emit_static_me_placeholder()` を各所で都度呼ぶ“分散生成”をやめ、関数内で 1 回だけ生成して再利用する。
|
||||
- 実装:
|
||||
- `MirBuilder.current_fn_singletons: HashMap<String, ValueId>` を追加。
|
||||
- 関数開始時にスコープを作り、関数終了時に復元(キャッシュは関数単位で生存)。
|
||||
- `maybe_prepend_static_me()` から `current_fn_singleton(box_name)` を利用し、ModuleFunction 経由の静的呼び出しに一貫して `me` を付与。
|
||||
- 変更点(主な参照):
|
||||
- `src/mir/builder.rs:176, 448-468` — キャッシュ本体とプレースホルダ生成の単一ルート。
|
||||
- `src/mir/builder/builder_calls/build.rs:39-46, 138-149, 232-241, 249-258, 265-274` — `maybe_prepend_static_me()` による受領者注入。
|
||||
- `src/mir/builder/builder_calls/lowering.rs` — メソッド/静的メソッドを関数化する際にキャッシュを save/restore。
|
||||
- `src/mir/builder/lifecycle.rs:50` — `main` 構築時のキャッシュ初期化。
|
||||
- 効果:
|
||||
- 同一関数内の静的メソッド連続呼び出しで `me` プレースホルダの重複生成が解消。
|
||||
- 将来の OnceLock 実体置換を 1 箇所で行える導線ができた。
|
||||
|
||||
### Phase A‑1c — ModuleFunction alias 整備 & Verifier 補強(完了)
|
||||
- 目的: ModuleFunction 経由の静的呼び出しで receiver 欠落を早期検出し、VM 側も常に receiver あり前提に揃える。
|
||||
- 実装:
|
||||
- Verifier: `ModuleFunction(box.method/arity)` で Known かつ Box 型の受領者が無い場合に Fail‑Fast。
|
||||
- Runtime: MethodRouter が Void 受領者を即時 InvalidInstruction とし、legacy fallback も receiver 前提に統一。
|
||||
- ModuleFunction alias: `handlers/calls/trampolines.rs` を追加し、Array/Map/String/Console の ModuleFunction → Method 変換を表駆動化。
|
||||
|
||||
### Phase A‑1d — LegacyCallBridgeBox 導入(完了)
|
||||
- 目的: `emit_instruction(MirInstruction::Call)` の直叩きを Builder から排除し、ガード済みの入口に集約する。
|
||||
- 実装:
|
||||
- `src/mir/builder/calls/legacy_bridge/` に LegacyCallBridgeBox を新設し、旧 `emit_legacy_call` の本体を移設。
|
||||
- すべてのレガシー Call 発行を `emit_call_with_guard`(EmitGuard)経由に統一するヘルパ `emit_call()` を追加。
|
||||
- BoxCall/PluginCall も `emit_boxcall()` でローカルSSA素材化→`emit_box_or_plugin_call` へ流すようガード化。
|
||||
- `src/mir/builder/builder_calls/emit.rs` の `emit_legacy_call` は Box への委譲のみとし、モジュール境界でレガシー経路を閉じ込めた。
|
||||
- 効果:
|
||||
- Guard を通さない Call が発生しなくなり、Extern/Method/Global いずれも素材化漏れを検出可能に。
|
||||
- レガシー経路が単一ファイルに箱化されたことで、段階的削除(将来的なフェーズB/C)や差分追跡が容易に。
|
||||
|
||||
### Phase A‑2 — singleton 実体(lazy 初期化)導入(完了)
|
||||
- 目的: `emit_static_me_placeholder()` が生成する Void const を実体 BoxRef に置き換える。
|
||||
- 実装:
|
||||
- `runtime/static_singleton.rs` を追加し、`OnceCell<Mutex<…>>` で Box 名ごとのシングルトンを lazy 作成。
|
||||
- Interpreter `handle_const` が `MirType::Box(..)` を検知した場合に `static_singleton::get()` を参照し、`VMValue::BoxRef` を登録。
|
||||
- 効果:
|
||||
- MIR 側は Box 型として `me` を扱い、VM 実行時に実体 Arc<NyashBox> が注入される。後続のマクロ/Verifier 強化に備えて受領者が具体化された。
|
||||
|
||||
### Phase A‑3 — ループヘッダー PHI の「真のループキャリア変数」化(完了)
|
||||
- 目的: ループ条件で一時文字列(例: `ch`)が PHI 化され、`i < s.size()` が誤って `ch < s.size()`(String vs Integer)になる問題を根治する。
|
||||
- 実装:
|
||||
- `build.rs` 側で preheader の変数スナップショットを取得し、事前スキャンで得た `assigned_vars` との積を取って PHI 対象を決定。
|
||||
- 実装箇所: `src/mir/loop_builder/build.rs:36` 付近(preheader_vars キャプチャと loop_carried 生成)、`src/mir/loop_builder/phi.rs:14-48`(PHI 対象の retain)。
|
||||
- 効果:
|
||||
- ループ条件の比較型が安定。`tools/smokes/v2/profiles/quick/apps/json_query_vm.sh` が PASS(以前の `String("0") < 1` 失敗が消失)。
|
||||
|
||||
### 残タスク(Phase A 継続)
|
||||
- ✅ **ParameterGuardBox 拡張**
|
||||
Builder(pending entry copy を含む)と optimizer `repair_*` で `dst ∈ params` を禁止済み。v%0 上書き事故を構造的に遮断。
|
||||
- ✅ **Verifier 層の追加**
|
||||
`check_no_parameter_reassignment` を追加し、MIR 完成後もパラメータ再定義を Fail‑Fast。
|
||||
- **EmitGuard 後の ArrayBox.size 固定(継続中)**
|
||||
`map.values()` → `.size()` の連鎖を `nyrt.array.size` へ確実に正規化し、EmitGuard の一度だけで素材化が済むよう整理する(Normalizer で Method 巻き戻し禁止)。現在 json_query_vm で `String("0") < 1` という残バグを追跡中。
|
||||
- **RouterPolicy のログ拡張**
|
||||
`Route::BoxCall` 強制時の理由を mat-trace に記録し、Singleton 正規化後の逸脱調査を容易にする。
|
||||
|
||||
### Phase A‑1e — Map.size 正規化 & Extern 安定化(完了)
|
||||
- 目的: `MapBox.(size|len|length)` を `Extern("nyrt.map.size")` に統一し、Method 形の残存で起きる受領者素材化漏れを排除。
|
||||
- 実装:
|
||||
- `src/mir/builder/normalize/map_length.rs` 新設。`normalize::apply_all` に組み込み。
|
||||
- Optimizer 側で `nyrt.map.size` の Method への巻き戻しを抑止。
|
||||
- Lowering で `MapBox.size/0` → `nyrt.map.size(recv)` の直下ろしを追加。
|
||||
- 効果: plugins プロファイルの `parity_map_size_has_vm` / `strict_plugin_map_size_vm` が PASS。
|
||||
|
||||
### Phase A‑1f — Map.keys/values と remove の整備(完了)
|
||||
- 目的: `Map.values()` の戻り値を ArrayBox として統一し、`.size()` 連鎖で未定義値/HostHandle 漏れが発生しないよう構造化。
|
||||
- 実装:
|
||||
- `extern_adapter/collections.rs` を新設し、HostHandle unwrap をハブ化。`nyrt.map.{keys,values}` / `nyrt.array.size` が常に実体 Box を扱うよう統一。
|
||||
- Extern adapter を host slot テーブル経由+ PluginV2 経路の二本で正規化し、両経路で `VMValue::BoxRef` を返却。
|
||||
- Map プラグインの `remove()` を HostHandle/TLV 返却へ統一し、削除した値を呼び出し元で即利用できるよう調整。
|
||||
- テスト:
|
||||
- `map_host_keys_values_return_arrays` / `map_remove_returns_removed_array_len` を追加し、HostSlot 強制と plugin route の双方で ArrayBox が返る・`len()` が成立することを固定。
|
||||
- `map_values_array_element_vm.sh` / `map_remove_returns_value_vm.sh` / `plugin_map_len_vm.sh` で代表スモークを常時監視。
|
||||
|
||||
### Known issues(2025‑10‑19 時点)
|
||||
- me 注入の誤適用により plugin ModuleFunction へ影響する懸念。
|
||||
- 対処: `method_index.static_signature()` に該当する静的シグネチャのみ `me` 合成を許可(Builder/VM 双方でガード)。
|
||||
- FileBox 系の `use of undefined value` は引数素材化の漏れが原因。
|
||||
- 対処: mir_call 作成前後の LocalSSA を全発行経路に適用済みかスイープし、欠落箇所を補強(EmitGuard で統一)。
|
||||
- Plugin ABI: 既存 C ABI 互換エントリを registry に登録し、外部呼び出し経路を段階移行(resolver alias で完結)。
|
||||
- Docs/Tests: Phase-31 変更点のドキュメント整備とスモーク追加(singleton/Verifier 回り)。
|
||||
|
||||
### 現在の既知問題(dev)
|
||||
- quick→plugins→full でのカテゴリ 2/3(出力差・モジュール解決)の再確認が未実施。LegacyCallBridgeBox 導入後、差分の再スキャンが P0‑5 で残っている。
|
||||
- Plugin ABI の追加トランポリンは不要。残りは resolver/Router 側の整合性チェックのみ。
|
||||
Reference in New Issue
Block a user