# HAKO MIR/FFI/ABI Design (Front-Checked, MIR-Transport) 目的: フロントエンドで型整合を完結し、MIR は「最小契約+最適化ヒント」を運ぶだけ。FFI/ABI は機械的に引数を並べる。バグ時は境界で Fail‑Fast。Box Theory に従い境界を1箇所に集約し、A/B で即切替可能にする。 ## 境界(Box)と責務 - フロントエンド型チェック(Type Checker Box) - 全ての型整合・多相解決を完結(例: map.set → set_h / set_hh / set_ha / set_ah)。 - 必要な変換は明示命令(box/unbox/cast)を挿入。暗黙推測は残さない。 - MIR ノードへ `Tag/Hint` を添付(reg→{value_kind, nullability, …})。 - MIR 輸送(Transport Box) - 役割: i64 値+Tag/Hint を「運ぶだけ」。 - 最小検証: move/phi の Tag 一致、call 期待と引数の Tag 整合(不一致はビルド時エラー)。 - FFI/ABI ローワリング(FFI Lowering Box) - 受け取った解決済みシンボルと Tag に従い、C ABI へ並べ替えるだけ。 - Unknown/未解決は発行禁止(Fail‑Fast)。デバッグ時に 1 行ログ。 ## C ABI(x86_64 SysV, Linux) - 引数: RDI, RSI, RDX, RCX, R8, R9 → 以降スタック(16B 整列)。返り値: RAX。 - 値種別: - Int: `int64_t`(MIR の i64 そのまま) - Handle(Box/オブジェクト): `HakoHandle`(`uintptr_t`/`void*` 同等の 64bit) - 文字列: 原則 Handle。必要時のみ `(const uint8_t* p, size_t n)` 専用シンボルへ分岐 ### 例: nyash.map - set(キー/値の型で分岐) - `void nyash_map_set_h(HakoHandle map, int64_t key, int64_t val);` - `void nyash_map_set_hh(HakoHandle map, HakoHandle key, HakoHandle val);` - `void nyash_map_set_ha(HakoHandle map, int64_t key, HakoHandle val);` - `void nyash_map_set_ah(HakoHandle map, HakoHandle key, int64_t val);` - get(常に Handle を返す) - `HakoHandle nyash_map_get_h(HakoHandle map, int64_t key);` - `HakoHandle nyash_map_get_hh(HakoHandle map, HakoHandle key);` - アンボックス - `int64_t nyash_unbox_i64(HakoHandle h, int* ok);`(ok=0 なら非数値) ## MIR が運ぶ最小契約(Hard)とヒント(Soft) - Hard(必須) - `value_kind`(Int/Handle/String/Ptr) - phi/move/call の Tag 整合(不一致はフロントで cast を要求) - Unknown 禁止(FFI 発行不可) - Soft(任意ヒント) - `signedness`, `nullability`, `escape`, `alias_set`, `lifetime_hint`, `shape_hint(len/unknown)`, `pure/no_throw` など - 解釈はバックエンド自由。ヒント不整合時は性能のみ低下し、正しさは保持。 ## ランタイム検証(任意・A/B) - 既定は OFF。必要時のみ軽量ガードを ON。 - 例: ハンドル魔法数・範囲、(ptr,len) の len 範囲。サンプリング率可。 - ENV(案) - `HAKO_FFI_GUARD=0/1`(ON でランタイム検証) - `HAKO_FFI_GUARD_RATE_LG=N`(2^N に 1 回) - `HAKO_FAILFAST=1`(失敗即中断。0 で安全パスへデオプト) ## Box Theory と A/B(戻せる設計) - 境界は 3 箇所(フロント/輸送/FFI)で固定。各境界で Fail‑Fast は 1 か所に集約。 - すべて ENV で A/B 可能(ガード ON/OFF、サンプリング率、フォールバック先)。 ## Phase(導入段階) 1. Phase‑A: Tag サイドテーブル導入(フロント)。phi/move 整合のビルド時検証。 2. Phase‑B: FFI 解決テーブル(`(k1,k2,…)→symbol`)。デバッグ 1 行ログ。 3. Phase‑C: ランタイムガード(A/B)。魔法数/範囲チェックの軽量実装。 4. Phase‑D: ヒント活用の最適化(pure/no_throw, escape=false など)。 ## サマリ - フロントで型を完結 → MIR は運ぶだけ → FFI は機械的。 - Hard は Fail‑Fast、Soft は最適化ヒント。A/B で安全と性能のバランスを即時調整可能。 --- ## Phase 追記(このフェーズでやること) 1) 実装(最小) - Tag サイドテーブル(reg→Tag)をフロントで確定・MIRへ添付 - phi/move で Tag 整合アサート(不一致ならフロントへ cast を要求) - FFI 解決テーブル(引数の Tag 組→具体シンボル名)+デバッグ 1 行ログ(A/B) - Unknown の FFI 禁止(Fail‑Fast) - ランタイム軽ガードの ENV 配線(HAKO_FFI_GUARD, HAKO_FFI_GUARD_RATE_LG, HAKO_FAILFAST) 2) スモークチェック(最小ケースで通電確認) - map.set(Int,Int) → set_h が呼ばれる(ログで確認) - map.set(Handle,Handle) → set_hh が呼ばれる - map.get_h 返回 Handle。直後の unbox_i64(ok) で ok=0/1 を確認 - phi で (Int|Handle) 混在 → ビルド時エラー(cast 必須) - Unknown のまま FFI 到達 → Fail‑Fast(1 回だけ) - ランタイムガード ON(HAKO_FFI_GUARD=1, RATE_LG=8)で魔法数/範囲の軽検証が通る 3) A/B・戻せる設計 - 既定: ガード OFF(perf 影響なし) - 問題時: HAKO_FFI_GUARD=1 だけで実行時検証を有効化(Fail‑Fast/デオプトを選択)