VM Layout (Current → Target)
Current
lang/src/vm/hakorune-vm/— Hakorune VM (nyvm) implementationlang/src/vm/boxes/— Shared helpers (op_handlers, scanners, compare, etc.)- Mini‑VM minimal executor lives as boxes (e.g.,
boxes/mir_vm_min.hako)
Target (post‑20.12b, gradual)
engines/hakorune/— mainline nyvm engineengines/mini/— Mini‑VM engine (educational/minimal)boxes/— shared helperscore/— centralized execution core (value/state/reader/dispatcher + ops)
Policy
- Engines orchestrate execution and may depend on boxes and shared/*.
- Boxes are pure helpers (no engine loop, no I/O, no plugin/ABI).
- Parser/Resolver/Emitter must not be imported from engines/boxes.
- Core provides engine‑agnostic execution primitives and should not import engine‑specific modules. During migration, temporary adapters may exist.
Static Box Methods(Singleton / self)
- 規約: 静的Boxのメソッドは「self(Singleton)を先頭引数」に持つ。
- 例:
LLVMPhiInstructionBox.lower_phi(self, dst, incoming_list)
- 例:
- 互換:
HAKO_BRIDGE_INJECT_SINGLETON=1(alias:NYASH_BRIDGE_INJECT_SINGLETON)で旧スタイルPhiInst.lower_phi(dst, incoming)に Singleton を注入して実行。 - Fail‑Fast: 期待 arity と不一致は静かなフォールバックをせず、安定メッセージで失敗する。
詳細:
docs/development/architecture/llvm/static_box_singleton.md
Bridge‑B (Ny/Core 直行)
- Wrapper 経路では
include "lang/src/vm/core/dispatcher.hako"で Core Dispatcher を取り込み、NyVmDispatcher.run(json)を直接呼び出す。usingは名前解決のみで実体は登録されないため、 Core を呼ぶ目的ではincludeを用いること。 Gate‑C(Core) 直行(NYASH_GATE_C_CORE=1)は JSON→Core Interpreter 実行なのでこの問題の影響を受けない。
Toggles and Canaries
- Core canaries (quick profile): enable with
SMOKES_ENABLE_CORE_CANARY=1.- Emit→nyvm(Core) scripts:
tools/smokes/v2/profiles/quick/core/canary_emit_nyvm_core_{return,binop,if}_vm.sh - Gate‑C(Core, json→Core 直行) canaries:
tools/smokes/v2/profiles/quick/core/canary_gate_c_core_{file,pipe}_vm.sh(既定OFF) - Gate‑C(Core) array sequence:
tools/smokes/v2/profiles/quick/core/canary_gate_c_core_array_mixed_vm.sh(push→set→get をログで検証) - Gate‑C(Core) map sequence:
tools/smokes/v2/profiles/quick/core/canary_gate_c_core_map_{len,iterator}_vm.sh - Emit→Core map len/get:
tools/smokes/v2/profiles/quick/core/canary_emit_core_map_len_get_vm.sh - Gate‑C Direct sanity:
tools/smokes/v2/profiles/quick/core/canary_gate_c_core_direct_string_vm.sh
- Emit→nyvm(Core) scripts:
Exit Code Policy
- Gate‑C(Core): numeric return is mapped to process exit code。タグ付きの失敗時は安定メッセージを出し、可能な限り非0で終了。
- VM backend(Rust Interpreter): 戻り値は標準出力に出す。プロセスの終了コードは戻り値と一致しない場合があるため、スモークは安定タグや標準出力の数値で検証する(rcは参考)。
- 推奨: CIやスクリプトでは Gate‑C(Core) を優先し rc を厳密化。開発時の対話検証は VM ルートで標準出力を検証。
Tag→RC(Core Direct)
- Core Direct(
HAKO_CORE_DIRECT=1)では、数値行が見つからない場合は rc≠0 を返す(Fail‑Fast)。 - 代表タグ(例)
[core/string/bounds]→ rc=1[core/array/oob_set]→ rc=1[core/mir_call/method_unsupported]→ rc=1
Core Direct Toggle
HAKO_CORE_DIRECT=1(互換:NYASH_CORE_DIRECT)で、Gate‑C(Core) の JSON 実行を "Core Dispatcher 直行" 子経路に切り替える。- 形: 一時Hakoスクリプトに
include "lang/src/vm/core/dispatcher.hako"を埋め込み、NyVmDispatcher.run(json)を実行。 - rc: 最後の数値行を rc にマップ。数値がない場合(タグ等)は rc≠0 とする(Fail‑Fast)。
- 用途: Core の診断タグや rc を CI で直接検証したい時に使用。
- 形: 一時Hakoスクリプトに
- Runner Core toggle:
HAKO_NYVM_CORE=1(orNYASH_NYVM_CORE=1) selects the Core bridge for the nyvm wrapper path. - Gate‑C Core route: set
NYASH_GATE_C_CORE=1(orHAKO_GATE_C_CORE=1) to execute MIR(JSON v0) directly via Core (interpreter path; quiet; exit code mirrors return).- Env:
NYASH_CORE_MAX_ITERSorHAKO_CORE_MAX_ITERSoverrides the Core dispatcher loop cap (default 10000). - Plugins: when
HAKO_GATE_C_ENABLE_PLUGINS=1is set, the runner normalizes Array/Map core methods through HostHandleRouter (HAKO_ARRAY_FORCE_HOST=1,HAKO_MAP_FORCE_HOST=1) to keep value/return semantics stable. Plugins が OFF のときは ビルトインのArrayBox/MapBoxにフォールバックする。Map のlen()/size()は extern adapter が ビルトインMapBoxの内部データ長を返すフォールバックを持つため(plugins=OFF でも)0 固定にはならない。
- Env:
- Errors: VM 実行/JSON読込エラー時は非0で終了(Fail‑Fast)。
PHI Strict(既定ON)
- 目的: ループ/分岐における PHI 入力の不整合(pred 欠落や自己参照)を早期に検出し、クラッシュや未定義使用を防止する。
- 既定: ON(何も設定しない場合は厳格)
- 無効化(開発・暫定用途のみ):
HAKO_VM_PHI_STRICT=0またはNYASH_VM_PHI_STRICT=0- ON 指定:
1|true|on|yes等、OFF 指定:0|false|off|no等を受理
- 実装:
src/backend/mir_interpreter/exec.rs(PHI 適用時に pred 不一致を Fail‑Fast)
Quick profile opt‑in switches (smokes)
SMOKES_ENABLE_LOOP_COMPARE=1— Direct↔Bridge parity for loops (sum/break/continue/nested/mixed)SMOKES_ENABLE_LOOP_BRIDGE=1— Bridge(JSON v0) loop canaries (quiet; last numeric extraction)SMOKES_ENABLE_STAGEB_OOB=1— Stage‑B OOB observation (array/map)SMOKES_ENABLE_OOB_STRICT=1— Gate‑C(Core) strict OOB fail‑fast canary (gate_c_oob_strict_fail_vm.sh)SMOKES_ENABLE_LLVM_SELF_PARAM=1— LLVM instruction boxes self‑param builder tests (const/binop/compare/branch/jump/ret)SMOKES_ENABLE_STAGEB=1— Stage‑B positive canaries(emit→Gate‑C)。既定OFF(安定化後に昇格予定)。 必要に応じて各テスト内でHAKO_STAGEB_ALLOW_FALLBACK=1を付与(TTL; 既定OFF)。
Default quick canaries (regression)
- apps/json_lint_vm.sh — JSON Lint expected outputs (OK×10 / ERROR×6)
- core/array/array_length_vm.sh — ArrayBox.length returns 0→1→2→3 for push sequence
Dispatch policy: length()
- String 受けに対してのみ StringBox ハンドラが length() を処理する。
- Array/Map などは各 Box 専用ハンドラで length/len/size を処理する。
- これにより、配列に対して誤って文字列長を返す回帰を防止する(2025‑11 修正)。
Strictness & Tolerance (ENV policy)
- PHI strict(既定ON)
- 既定ON(未指定時はON)。無効化は
HAKO_VM_PHI_STRICT=0(互換:NYASH_VM_PHI_STRICT=0)。 - 目的: pred不一致などPHI入力の欠落をFail‑Fastで検出。
- 既定ON(未指定時はON)。無効化は
- VMステップ上限(無限ループ対策)
HAKO_VM_MAX_STEPS(互換:NYASH_VM_MAX_STEPS)で1関数内の実行ステップに上限(既定: 1,000,000)。
- OOB strict(配列/範囲外の観測)
HAKO_OOB_STRICT=1(互換:NYASH_OOB_STRICT=1)でOOBを観測・タグ出力。HAKO_OOB_STRICT_FAIL=1でGate‑C(Core)の実行を非0終了にする(出力のパース不要)。
- Tolerance系(開発専用)
NYASH_VM_TOLERATE_VOID=1等の寛容フラグは開発/診断専用。既定ではOFFで、CI/quickでは使用しないこと。
Deprecations
NYASH_GATE_C_DIRECTは移行中の互換トグル(TTL)だよ。将来は Gate‑C(Core) 直行(HAKO_GATE_C_CORE=1)に統一予定。新しい導線では Core の実行仕様(数値=rc, 安定化した診断タグ)が適用されるよ。- 互換トグルを使うと起動時に警告が出るよ(
HAKO_GATE_C_DIRECT_SILENCE=1で抑止可)。 - Stage‑B fallback TTL: 既定OFF(撤退方針)。必要な場合はテスト内限定で
HAKO_STAGEB_ALLOW_FALLBACK=1を付与する。
Diagnostics (stable tags)
- 本フェーズでは、Gate‑C(Core) の境界で安定タグを整形して出力する:
[core/binop] div by zero[core/mir_call] array get out of bounds[core/mir_call] array set out of bounds[core/mir_call] modulefn unsupported: …[core/mir_call] map iterator unsupported[core/mir_call] map len missing arg[core/mir_call] map set missing key|bad key|missing value|bad value[core/mir_call] map get missing key|bad key[core/mir_call] unsupported callee type: Closure[map/missing] Key not found: <key>(VM MapBox.get の既定タグ。従来文言を含むため後方互換)[array/empty/pop] empty array(VM ArrayBox.pop 空時。strict環境(HAKO_OOB_STRICT=1)で有効)
- Gate‑C Direct では、リーダー/検証レイヤの診断をそのまま用いる(例:
unsupported callee type (expected Extern): ModuleFunction)。
Strict OOB policy (Gate‑C)
- Enable
HAKO_OOB_STRICT=1(alias:NYASH_OOB_STRICT) to tag Array OOB as stable strings ([oob/array/get]…,[oob/array/set]…). - With
HAKO_OOB_STRICT_FAIL=1(alias:NYASH_OOB_STRICT_FAIL), Gate‑C(Core) exits non‑zero if any OOB was observed during execution (no need to parse stdout in tests).
Exit code differences
- Core: 数値=rc(OS仕様により 0–255 に丸められる。例: 777 → rc=9)、エラーは非0
- Direct: 数値出力のみ(rc=0)、エラーは非0
- 数値が 255 を超えるケースは標準出力の値で検証すること(rc は下位8ビットへ丸められるため)
注: これらの整形は移行中の暫定仕様で、最終的には Core 側に移管される予定(CURRENT_TASK に TTL を記載)。
Minimal mir_call semantics (Core)
- Implemented (scoped):
- Constructor:
ArrayBox(サイズメタ初期化) /MapBox(エントリ数メタ初期化) - Methods (Array):
size()/push()/pop()/get()/set()(メタデータでサイズ検証) - Methods (Map):
size()/len()/iterator()/set()/get()(エントリ数メタを返す/更新する/メタから取得する) - ModuleFunction:
ArrayBox.len/0/MapBox.len/0(メタのサイズを返す)— 他はタグ付き Fail‑Fast - Global/Extern:
env.console.{log|warn|error}(数値引数のみ印字)
- Constructor:
- Others are Fail‑Fast(安定文言を出力)。Closure 生成は v1 bridge で受理(NewClosure 発行)するが、 実行時の呼出は未実装(VM 側は Fail‑Fast)。
See also: docs/development/architecture/collection_semantics.md(Array/Map のSSOT集約)
String helpers
- Core route(Gate‑C/Core)での最小サポート(Method):
String.size/0— 文字列長(バイト)を返すString.indexOf/1— 最初の一致位置、なければ -1String.lastIndexOf/1— 最後の一致位置、なければ -1String.substring/2— 半開区間 [start, end) を返す
- インデックス規約(bytes ベース):
- start/end は範囲 [0, size] にクランプされる(負の値は 0、size 超は size)。
- start > end の場合は空文字(size==0)。
- インデックスは UTF‑8 のバイト境界(コードポイント境界ではない)。
- ModuleFunction:
StringHelpers.to_i64/1— interpreter に inline 実装あり(数値文字列のみを許容)。 数値結果が 255 超の場合、rc は下位8ビットに丸められるため、標準出力の値で検証すること。
Core dispatcher canaries(直行ルート)
profiles/quick/core/canary_core_dispatcher_*は Gate‑C(Core) 直行へ移行済み。 一部(大きな値や plugin‑enabled 経路)では rc 正規化が未整備のため、数値は標準出力を優先して検証し、 rc はフォールバックとして扱う(TTL; 収束後に rc 検証に戻す)。
Aliases
- Keep existing logical module names in
hako.tomland introduce aliases to new paths when transitioning.