Files
hakorune/CURRENT_TASK.md

69 KiB
Raw Blame History

Restart Notes — Ny Syntax Alignment (20250907)

目的

  • SelfHosting 方針Nyのみで工具を回す前段に合わせて、Ny 構文とコーディング規約を明示化し、最小版ツールの完走性を優先。

Ny 構文(実装時の基準)

  • 1行1文セミコロン非使用。
  • break / continue を使わない(関数早期 return、番兵条件、if 包みで置換)。
  • else は直前の閉じ波括弧と同一行(} else {})。
  • 文字列の "\ は確実にエスケープ。
  • 反復は loop(条件) { …; インクリメント } を基本とし、必要に応じて「関数早期 return」型で早期脱出。

短期タスクSyntax 合意前提で最小ゴール)

  1. include のみ依存木Nyのみ・配列/マップ未使用)を完走化
    • apps/selfhost/tools/dep_tree_min_string.nyash
    • FileBox/PathBox + 文字走査のみで JSON 構築(配列/マップに頼らない)
    • make dep-treetmp/deps.json を出力
  2. using/module 対応は次段(構文・優先順位をユーザーと再すり合わせ後)
    • 優先: module > 相対 > using-path、曖昧=エラー、STRICT ゲート(要相談)
  3. ブリッジ Stage 1 は保留
    • NYASH_DEPS_JSON=<path> 読み込みログ出力のみを最小パッチで用意MIR/JIT/AOT は不変)

備考

  • Cranelift 側の作業は別ブランチで継続。SelfHosting ブランチは Ny 工具の安定化に集中。
  • 構文の最終合意後、using/module 版(配列/マップ最小 APIへ拡張。

Quick Plan — SelfHost (Restart Safe)

  • Goals: Ny-only dependency tree (include → later using/module), JSON out; simple file-bridge to existing MIR→VM→AOT without tight coupling.
  • Deliverables:
    • Minimal tool: apps/selfhost/tools/dep_tree_min_string.nyash (include-only, recursion via FileBox/PathBox, no Array/Map)
    • Full tool: apps/selfhost/tools/dep_tree_simple.nyash (include + using/module, strict/explicit resolution)
    • Task/Make: nyash.toml [tasks].dep_tree and make dep-tree (outputs tmp/deps.json)
    • Bridge Stage 1: Runner reads NYASH_DEPS_JSON=<path> and logs (no behavior change)
  • Order:
    1. Finish include-only tool to completion (Ny-only, strict 1statement lines)
    2. Harden full tool (using/module, module > relative > using-path, ambiguous=error, STRICT gate)
    3. Add Runner hook for NYASH_DEPS_JSON (log only)
  • Quick run:
    • make dep-tree → writes tmp/deps.json
    • ./target/release/nyash --run-task dep_tree

CURRENT TASK (Compact) — Phase 15 / Self-HostingNy→MIR→MIR-Interp→VM 先行)

【Quick Update — 20250907 Egui AOT/JIT 状況と次アクション】

  • 事象: Windows EXEAOT, jit-direct emitで Egui ウィンドウは開くが、open/uiLabel が反映されず M_RUN のみ実行。ログは run_window: w=320 h=240 title='Nyash GUI'(プラグイン側フォールバック)。
  • 原因推定: jit-direct 発行の Lower で汎用 PluginInvokeEguiBox.open/uiLabelが落ちていない。box_type_map/handle_values の伝播Copy 等)不足、汎用フォールバックの判定漏れが影響。
  • 暫定対応main 反映済み):
    • tools/windows/build_egui_aot.ps1 を安定化既定Input=apps/egui-hello/main.nyash、jit-direct発行時に hostcall/bridge 有効、strict=0、args-only無効
    • tools/ny_plugin.ps1 に nyrt.lib のフォールバックリンクを追加。
    • tools/windows/egui_smoke.ps1 を追加exe/vm/jit を秒指定で起動→生存判定)。
    • プラグインwith-egui側にフェイルセーフrun 時に未設定なら 320x240 + title='Nyash GUI' + 中央『hello nyash』を実装。
  • 確認結果:
    • VM 経路は M_OPEN/M_UI_LABEL/M_RUN が順に実行され、スクリプト文言が表示。
    • AOT EXE は現状フォールバック表示中央『hello nyash』M_OPEN/M_UI_LABEL が JIT Lower 上で未反映。
  • 次アクションCranelift 専用ブランチで実施):
    1. LowerCore で MirInstruction::Copy における型・ハンドル伝播を追加(box_type_map/handle_values)。
    2. lower_box_call に EguiBox 明示分岐open/uiLabel/runを追加し、名前ベースの emit_plugin_invoke で確実に落とす(暫定)。
    3. NYASH_JIT_TRACE_LOWER=1 時に汎用フォールバック失敗の理由box_type, method, param/local/known 判定を1行で診断出力。
    4. スモーク: tools/windows/egui_smoke.ps1 -Mode exe -Seconds 4 -Dbg と VM/JIT で M_OPEN/M_UI_LABEL が見えることを確認。
  • 運用メモ:
    • 開発は VM で速回し→DLL 差し替えで EXE 反映→最後に AOT リンクが最短ループ。
    • DLLだけ再ビルド: cargo build -p nyash-egui-plugin --release --features with-eguitarget/release/nyash_egui_plugin.dll を上書き。

Quick Update — 20250907 Core13 Pure P1

  • Try/Catch P1純モード Core13をビルダーで実装。Throw/Catch 命令を使用せず Jump/Branch/Phi で catch へ合流。
    • NYASH_MIR_CORE13_PURE=1 時に有効。build_throw_statement が try 文脈内では catch ブロックへ Jump するように変更。
    • catch 変数(例: catch (T e))はエントリの Phi で合流した例外値を束縛。
  • テスト追加(統合):
    • tests/mir_pure_trycatch_builder.rs: 生成 MIR が Core13 許可集合のみで構成されることを検証。
    • tests/vm_e2e.rs に純モード E2E 2件を追記throw→catch 経路/成功時に catch をスキップ)。 — 次: finally 分岐の網羅テスト、LLVM パリティ側の tobool/分岐の補強。

— WSL Egui 表示(開発効率のための恒常化)

目的

  • WSL 環境で egui の実ウィンドウを安定表示し、毎回の手間取りを解消Windows 側nyash.exe 実行に頼らず、その場で可視化)。

チェックリスト(毎回同じ手順で安定化)

  • プラグインを GUI 有効で上書きビルド
    • cargo clean -p nyash-egui-plugin
    • cargo build -p nyash-egui-plugin --release --features with-egui
  • 実行時にこのDLLを確実に掴ませる競合回避
    • export NYASH_PLUGIN_PATHS=/mnt/c/git/nyash-project/nyash_main/plugins/nyash-egui-plugin/target/release
  • WSLgWaylandで試す → ダメなら X11 に切替
    • Wayland: export WAYLAND_DISPLAY=wayland-0; export XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir; unset DISPLAY
    • X11: export DISPLAY=:0; export WINIT_UNIX_BACKEND=x11
  • 実行
    • ./target/release/nyash --backend vm apps/egui-hello/main.nyash
  • 成功判定
    • ログに run_window: w=... h=... title='...' が出る+ウィンドウが表示される
    • 参照: タイムスタンプ ls -la plugins/nyash-egui-plugin/target/release/libnyash_egui_plugin*
    • 詳細ログ: NYASH_CLI_VERBOSE=1 で loader の解決パスを確認

補足

  • Windows 側での実行(./target/release/nyash.exe / app_egui.exeは表示が確実。WSL 側の開発を優先するため、上記手順を最初に通す。
  • AOT 直後に feature 無しで上書きされると窓が消えるため、表示が出ない時は「(1)上書きビルド → (2)NYASH_PLUGIN_PATHS指定 → (3)Wayland/X11」の順で再試行。

ビルド並列(既定ポリシー)

  • 開発機は 32 論理スレッド。Cargo の並列ビルドは基本 24 並列を既定とする(温度と安定性のバランス)。
    • 例: cargo build --release -j 24 --features cranelift-jit
    • PowerShell スクリプトは可能な限り -Jobs で上書き可能にする(tools/build_egui_aot_manual.ps1 -Jobs 24)。

[ブランチ方針の注記 — 20250906 selfhostingdev 整理]

  • このブランチは VM/JIT を中心とした自己ホスト開発に専念します。
  • Cranelift AOT/JITAOT 系の詳細課題は docs/phase-15/cranelift/CRANELIFT_TASKS.md へ分離しました(このファイルへの追記は最小限に)。
  • 旧コンテンツは docs/archives/CURRENT_TASK-2025-09-06.md(要旨)および Git 履歴(完全版)を参照してください。

— Quick Update (20250906 PM)

  • Merge: origin/main の Cranelift 修正を取り込み、全スモーク緑を確認。
  • P0 達成(追加):
    • Ny→MIR 直結ブリッジCase A実装json_v0_bridge.rs)。tools/ny_roundtrip_smoke.sh PASS。
    • env.modules 最小レジストリ追加VM ExternCall name-route 対応plugins不要tools/modules_smoke.sh PASS。
    • using MVP軽量導線: スクリプト using 行ns/直パス)・指示コメント(@using/@module/@using-path・環境/CLIフラグ--using/--module/--using-pathを前処理で受理→env.modules登録。
      • 未解決時は verbose で探索ヒントと候補提示apps/lib/. を浅く走査)。
      • 直パス missing は NYASH_USING_STRICT=1 でエラー終了・デフォは警告継続。
      • スモーク: tools/using_e2e_smoke.shMVP, tools/using_resolve_smoke.sh, tools/using_unresolved_smoke.sh, tools/using_strict_path_fail_smoke.sh 追加・PASS。
    • JSON v0 拡張: Bool, Compare(op) を追加検査・判定系の表現力UP

次アクション(短期)

  • using 解決品質の向上: 候補スコアリング/断片一致・パス優先度整理search_paths順
  • VM 経路の using 前処理の適用範囲見直し(必要時)。
  • JSON v0 の最小セット拡張(短絡評価/論理 and/or 等)。
  • ドキュメント最小追記README の SelfHosting セクションから onepager へ誘導済み)。

このドキュメントは「いま何をすれば良いか」を最小で共有するためのコンパクト版です。詳細は git 履歴と docs/phase-15を参照してください。

【Cranelift AOTEXE検証とEgui方針 — 20250907】

  • CounterBox AOTCranelift .o emit→nyrtリンク→EXE

    • 手順(確認済み):
      1. cargo build --release --features cranelift-jit
      2. cargo build -p nyash-counter-plugin --release
      3. NYASH_AOT_OBJECT_OUT=target/aot_objects/counter_min.o ./target/release/nyash --jit-direct apps/tests/plugins/counter_min.nyash
      4. cc target/aot_objects/counter_min.o -L target/release -L crates/nyrt/target/release -Wl,--whole-archive -lnyrt -Wl,--no-whole-archive -lpthread -ldl -lm -o app_counter_cranelift
      5. NYASH_PLUGIN_PATHS=... ./app_counter_cranelift → Result: 0戻り値正規化あり
    • 備考: jit-direct 実行時に稀に segfault が出るが、.o は生成されリンク・実行に支障なし(要フォローアップ)。
  • Egui 方針(汎用経路に統一):

    • Lowering への Egui 専用分岐は撤去済み。Egui はプラグインボックス呼び(一般経路)で扱う。
    • 過去に追加した Egui 専用の WSL スモークスクリプトは削除(忘れ残し防止/将来の悪影響回避)。
      • 削除: tools/egui_wsl_smoke.sh, tools/egui_cranelift_aot_wsl.sh
    • 次: apps/egui-hello/main.nyash を AOTCranelift .o emit→リンク→EXEで表示確認NYASH_PLUGIN_PATHS で DLL 解決)。

【Handoff — 再起動/並行ブランチ運用計画20250907 深夜)】

  • 目的: Rustフルビルド負荷を避けつつ、Cranelift lower 修正を安全に前進。main はドキュメント/ツール整備に限定。
  • 推奨運用git worktree:
    • 準備: git fetch --all --prune
    • main 用: git worktree add ../nyash_main_main main
    • 開発用(例): git worktree add ../nyash_main_cranelift cranelift-dev(無ければブランチ作成)
    • 以後、各フォルダで独立ビルド/実行。
  • 役割分担:
    • main: CURRENT_TASK/docs、ビルド/スモーク用スクリプトの安定化のみ。
    • cranelift-dev: Lower 修正EguiBox.open/uiLabel を確実に Lower
  • 直近TODOcranelift-dev:
    1. Copy 伝播強化: MirInstruction::Copybox_type_maphandle_values を src→dst にコピー。
    2. 診断拡充: NYASH_JIT_TRACE_LOWER=1 時、汎用 PluginInvoke フォールバック失敗の理由box_type/method/param/local/knownを1行で出力。
    3. EguiBox 暫定フォールバックenvゲート: NYASH_JIT_EGUI_FORCE=1 時のみ、open/uiLabel/run を名前で emit_plugin_invoke して確実に Lower恒久化は原因修正後に再検討
    4. 受け入れ基準: jit-direct と AOT(EXE) の双方で [EGUI] M_OPEN/M_UI_LABEL/M_RUN が順に出力され、タイトル/ラベルがスクリプト値で表示。
  • 実行/確認コマンド:
    • VM 速回し: tools/ny_plugin.ps1 -Mode vm -Script apps/egui-hello/main.nyash -Debug
    • JIT 直: NYASH_JIT_TRACE_LOWER=1 NYASH_JIT_EVENTS=1 tools/ny_plugin.ps1 -Mode jit -Script apps/egui-hello/main.nyash -Debug
    • AOT(EXE): tools/windows/build_egui_aot.ps1 -Input apps/egui-hello/main.nyash -Out app_egui.exe -Verboserun_egui_debug.bat
    • 簡易スモーク: tools/windows/egui_smoke.ps1 -Mode exe|vm|jit -Seconds 4 -Dbg
  • 環境メモ:
    • プラグイン差し替えで高速反映: cargo build -p nyash-egui-plugin --release --features with-eguitarget/release/nyash_egui_plugin.dll を上書き。
    • NYASH_PLUGIN_PATHS は各 worktree の plugins/*/target/release;target/release を指す(取り違い防止)。

— 最終更新: 20250906 (Phase 15.16 反映, AOT/JIT-AOT 足場強化 + Phase A リファクタ着手準備)

— Handoff (20250906 EOD) — Phase 15 進捗と次アクション

Done本セッションで完了

  • JSON v0: 短絡 &&/||and/or 互換を追加し、MIR で Branch+Phi 降ろし。
    • 実装: src/runner/json_v0_bridge.rsLogical追加、逐次BBで短絡組立
    • MIRインタプリタ: Phi はエントリで解決、非Phiのみ実行backend/mir_interpreter.rs)。
    • スモーク: apps/smokes/json_v0_short_or.json, ..._and.jsonゼロ除算を短絡で回避。VM/Interpreter一致。
  • CollectionsVM側: プラグイン無効で最小op動作を確認。
    • NYASH_DISABLE_PLUGINS=1 --backend vm apps/smokes/std/array_smoke.nyash → OK
    • NYASH_DISABLE_PLUGINS=1 --backend vm apps/smokes/jit_aot_map_min.nyash → OK
  • JIT安定化小修正: tls_call_import_ret に空引数ガードを追加Cranelift 検証器エラー「引数数不一致」を抑止)。
    • 影響: 引数不在でも import 呼を無理に発行しない。戻り値が必要な場合は iconst 0 を合成。

Nextこのまま継続してOK

  • M2 継続: Collections 最小 hostcalllen/get/set/push/size/has policy 認可の再確認JIT直も
    • 追加スモーク: --jit-direct + NYASH_JIT_READ_ONLY=1 で mutpush/set拒否を確認ビルダー安定化後に実行
    • ops_ext の handle.of → *_H 経路の整合性を軽く棚卸し(定数 SYM_* の統一を優先)。
  • M3 着手: plugin invoke by-id/by-name の最小衛生化(成功/失敗時のフォールバック方針明記、2件スモーク追加。
  • Telemetry軽量: observe::lower_hostcalllower_shortcircuit を代表ポイントに追加(イベント 1 呼=1 件)。

Constraints再掲

  • AOT/リンク最適化・GUI拡張の深追いはしないmain側。Phase A リファクタは挙動不変で小刻みに。

Quick Verify代表

  • 短絡: ./target/release/nyash --json-file apps/smokes/json_v0_short_or.json → true / ..._and.json → falseVM も一致)
  • CollectionsVM: NYASH_DISABLE_PLUGINS=1 --backend vm apps/smokes/std/array_smoke.nyashResult: 0
  • MapVM: NYASH_DISABLE_PLUGINS=1 --backend vm apps/smokes/jit_aot_map_min.nyashResult: 1

— Phase 15 実行計画2週間 / VM先行・JITはcompiler-only

方針とガードレール

  • フォーカス: Ny→MIR→VM/JIT 経路の自己ホスト実用化。JITは「独立実行/コンパイラ用途」に限定。
  • スコープ外: AOT/リンカ/GUI/大規模リファクタmain側で継続。本ブランチは最小実装観測整備に集中。
  • 常にスモーク先行で小刻みに前進。半日詰まりは撤退→Issue化。

マイルストーン

  1. M112日: JSON v0 短絡 &&/|| 追加
    • 受け入れ: VM/JIT一致--jit-direct。短絡で副作用が実行されないことをsmokeで確認。
  2. M223日: コレクション最小 hostcalllen/get/set/push/size/has整備policyガード再確認
    • 受け入れ: 変異系は既定denypolicy。許可時のみ allow がログに残る。smoke 6件緑。
  3. M312日: プラグイン橋の衛生by-id/by-name最小
    • 受け入れ: 2種invokeのsmoke、ログで呼び分け確認。
  4. M41日: using/module の最終調整(候補提示“ほどほど”)
    • 受け入れ: 既存smokeの文言/挙動が期待どおり。
  5. M51日: 可観測性の整理observe::lower_hostcall 等)
    • 受け入れ: 代表ケースでイベントが一貫op/collection_type/mutates/has_policy
  6. M61日: 安定化と1ページメモ更新入口誘導

3日スタートプラン詳細

  • Day1: JSON→MIR で LogicalAnd/LogicalOr を追加。JumpIfFalse/True で短絡表現。
  • Day2: MIR→VM で分岐網羅collections最小 hostcall 経路の確認。
  • Day3: VM→JIT で短絡のLowerとイベントlower_shortcircuit。VM/JIT一致--jit-direct

Do-Not-Do本期はやらない

  • AOT/リンクの最適化・調査の深追い、GUI/egui拡張、機能の広げ過ぎ、最適化、新規依存追加。

進捗メトリクス/撤退基準

  • 毎日: 新規/更新smokeの件数と緑率、VM/JIT一致率、イベントログ件数hostcall 1回=1件上限
  • 撤退: 半日詰まり→いったん落とす・Issue化・次のマイルストーンへ。

【ハンドオフ20250906 final— String.length 修正 完了JIT 実行を封印し四体制へ】

概要

  • 目的: AOT/JITAOT で発生していた StringBox.length/len が 0 になる不具合の是正Lower の二段フォールバック:nyash.string.len_hnyash.any.length_h)。
  • 結果: 当該不具合は修正・確認完了AOT/VM で期待値。JIT 直実行の継続調査は打ち切り、実行モードは「インタープリターVMCranelift(EXE)LLVM(EXE)」の4体制へ移行。

実装(済)

  • LowerCore: 二段フォールバック実装を追加Param/Local/リテラル)。
    • emit_len_with_fallback_param/_local_handle/_literal
    • core.rslen/length で二段フォールバックを使用。結果をローカルスロットへ保存Return で拾えるように)
  • BoxCall 共通ops_ext:
    • StringBox の len/length を最優先で処理Param/Local/リテラル/handle.of
    • リテラル new StringBox("...")length は即値畳み込みconst 返却)。
  • Hostcall registry 追補: nyash.string.len_h を ReadOnly 登録 + 署名 (Handle)->I64 追加。
  • JIT ブリッジ: extern_thunks.rsnyash_string_len_h を追加、cranelift ビルダーに SYM_STRING_LEN_H を登録。
  • ポリシー: StringBox.length/len マッピングを nyash.any.length_hnyash.string.len_h に是正。
  • デッドコード整理: 旧 lower_boxcall_simple_reads を削除conflict 回避)。
  • ツール/スモーク: tools/aot_smoke_cranelift.sh 追加、apps/smokes/jit_aot_string_length_smoke.nyash 追加。

確認状況(最終)

  • apps/smokes/jit_aot_string_min.nyashconcat/eq: AOT で Result: 1OK
  • apps/smokes/jit_aot_string_length_smoke.nyash: AOT .o 生成/リンク・実行とも良好(稀発の segfault 調査は「低優先」に移行)。
  • apps/smokes/jit_aot_any_len_string.nyash: AOT で Result が期待値0 問題は解消)。
  • 備考: JIT 直実行の既知の不安定性は、JIT 実行封印に伴い調査終了とする(アーカイブ扱い)。

残課題(方針更新後) P0: 実行モード整理JIT 実行封印)

  • ランタイム実行は「InterpreterVM」に限定。ネイティブ配布は「Cranelift AOT(EXE)LLVM AOT(EXE)」。JIT 関連のランタイムフラグ説明は docs で封印明記。

P1: AOT 安定化(低頻度 segfault の追跡:低優先)

  • 稀な DT_TEXTREL 警告・segfault は PIE/LTO/relro/TLS/extern 登録順の再確認を残課題として維持(優先度は下げる)。

P2: リファクタPhase A継続振る舞い不変

  • Hostcall シンボル SYM_* 統一、core/string_len.rs への集約、観測フックの整理は継続。JIT 実行依存の観測は停め、VM/AOT 観測を優先。

進捗20250906 終了報告)

  • ops_ext: StringBox.len/length の結果を必ずローカルに保存するよう修正Return が確実に値を拾える)
    • 対象: param/local/literal/handle.of 各経路。dst があれば local_index に slot を割当てて store_local_i64
  • デバッグ計測を追加
    • JIT Lower 追跡: NYASH_JIT_TRACE_LOWER=1BoxCall の handled 判定box_typedst 有無)
    • Return 追跡: NYASH_JIT_TRACE_RET=1known/param/local の命中状況)
    • ローカルslot I/O: NYASH_JIT_TRACE_LOCAL=1store/load idx=<N> を吐く)
    • String.len_h 実行: NYASH_JIT_TRACE_LEN=1thunk 到達と any.length_h フォールバック値を吐く)
  • 再現確認
    • apps/smokes/jit_aot_any_len_string.nyash は依然 Result: 0JIT-direct
    • 追跡ログ(要 NYASH_JIT_TRACE_LOWER=1 NYASH_JIT_TRACE_RET=1 NYASH_JIT_TRACE_LOCAL=1
      • BoxCall ... method=length handled=true box_type=Some("StringBox") dst?=true
      • ローカル slot の流れ: idx=0 recv(handle) → idx=1 string_len → idx=2 any_len → idx=3 cond → select → idx=4 dst 保存 → Return で load idx=4
      • つまり lowering/Return/ローカル材化は正しく配線されている。 JIT 直実行に関する未解決点import 解決先の差異疑い 等)は封印に伴いアーカイブ化。必要時に docs/development/current/ へ復元して再開する。

暫定変更(フォールバック強化)

  • ops_ext の StringBox.len で「リテラル復元NewBox(StringBox, Const String))」を param/local より先に優先。
    • JIT-AOT 経路で文字列リテラルの length は常に即値化select/hostcall を経由せず 3 を返す)。
    • ただし今回のケースでは local 経路が発火しており、まだ 0 のままhostcall 実行が 0 を返している疑い)。

未解決/次アクション(デバッグ指針)

  • nyash.string.len_h が実際にどの関数へリンクされているかを確認
    • Cranelift JIT: src/jit/lower/builder/cranelift.rsbuilder.symbol(...) 群は設定済みだが、実行時に thunk 側の eprintln が出ない。
    • 追加案: emit_host_call で宣言した func_idbuilder.symbol 登録可否の整合をダンプ(シンボル直列化や missing import の検知)。
  • extern_thunks::nyash_string_len_h へ確実に到達させるため、一時的に emit_len_with_fallback_*SYM_STRING_LEN_H を文字列リテラル直書きではなく定数経由に統一。
  • nyash.string.from_u64x2 の呼び出し可否を同様にトレース(NYASH_JIT_TRACE_LOCAL=1 の直後に NYASH_JIT_TRACE_LEN=1 が見えるか)
  • ワークアラウンド検証: NYASH_JIT_HOST_BRIDGE=1 強制でも 0 → host-bridge 経路の呼び出しが発火していない可能性。bridge シンボル登録も再確認。

メモ/所見

  • lowering と Return 材化ローカルslot への保存→Return で loadは動いている。値自体が 0 になっているので hostcall 側の解決/戻りが疑わしい。
  • AOT .o の生成は成功。segv は今回は再現せず。

実行コマンド(デバッグ用)

  • NYASH_JIT_TRACE_LOWER=1 NYASH_JIT_TRACE_RET=1 NYASH_JIT_TRACE_LOCAL=1 NYASH_AOT_OBJECT_OUT=target/aot_objects/test_len_any.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_any_len_string.nyash
  • 追加で thunk 到達確認: NYASH_JIT_TRACE_LEN=1 ...(現状は無出力=未到達の可能性)

Phase A 進捗(実施済)

  • A1: Hostcall シンボルの定数化(直書き排除)完了

【ハンドオフ20250906 4th— GUI/egui 表示テスト計画Cranelift/LLVM × Windows/WSL

目的

  • 以前は Windows exe で egui ウィンドウ表示を確認できていたが、現状で再現が不安定な報告あり。Cranelift/LLVM と OS 組み合わせ別に手順と期待結果を明文化し、再現性を担保する。

前提・重要ポイント

  • プラグイン版 EguiBox は with-egui 有効時にクロスプラットフォームeframe 使用。Windows では実ウィンドウ表示、WSL/Linux でも WSLg/Wayland 環境なら表示可能。開発機の描画バックエンドに依存する点に注意。
  • Windows でウィンドウ表示を行うには、nyash-egui-plugin--features with-egui でビルドし、nyash.tomlplugin_paths(または NYASH_PLUGIN_PATHS)に DLL のパスが解決できること。
  • Linux でウィンドウ表示を確認したい場合は「Rust 例gui_simple_notepad」または「ビルトイン EguiBoxnyash 本体を --features gui でビルドし、専用 Nyash スクリプトを使用)」も利用可。
  • Linux/WSL で --features gui を使う場合、システムの GL/X11/Wayland 開発ライブラリが必要(例: Ubuntu sudo apt install pkg-config libx11-dev libxkbcommon-dev libwayland-dev libgl1-mesa-dev)。

テストマトリクス(手順と期待結果)

  1. Windows × CraneliftJIT-direct/EXE 相当)

    • 準備: cargo build --release --features cranelift-jit
    • プラグイン: cargo build -p nyash-egui-plugin --release --features with-egui
    • 実行JIT-direct 経路): powershell -ExecutionPolicy Bypass -File tools\egui_win_smoke.ps1
    • 期待: Egui ウィンドウが表示される(アプリ終了までブロッキング)。
  2. Windows × LLVMEXE/直実行)

    • LLVM 準備: tools\windows\ensure-llvm18.ps1 -SetPermanent
    • プラグイン: cargo build -p nyash-egui-plugin --release --features with-egui
    • Nyash 本体: cargo build --release --features llvm
    • 直実行: .\target\release\nyash.exe --backend llvm apps\egui-hello\main.nyash
    • AOT EXE: tools\build_llvm.ps1 apps\egui-hello\main.nyash -Out egui_hello.exe .\egui_hello.exe
    • 期待: どちらの経路でも Egui ウィンドウが表示されるDLL が plugin_paths に解決可能であること)。
  3. WSL × CraneliftJIT-direct/EXE 相当)

    • 準備: cargo build --release --features cranelift-jit
    • 実行: ./target/release/nyash --jit-direct apps/egui-hello/main.nyash
    • 期待: 実ウィンドウ表示WSLg/Wayland 環境で成功することを想定。描画不可環境ではエラーなく終了voidにフォールバック。
    • 備考: 表示が出ない場合は X11/Wayland 変数の切替(WINIT_UNIX_BACKEND=x11 / WAYLAND_DISPLAYや必要パッケージの導入を確認。Rust 例(cargo run --features gui-examples --example gui_simple_notepad --release)で先に動作確認するのが無難。
  4. WSL × LLVMEXE/直実行)

    • 準備: ./tools/llvm_check_env.shLLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm
    • 実行: ./target/release/nyash --backend llvm apps/egui-hello/main.nyash
    • 期待: 実ウィンドウは出ない(スタブ)。
    • 備考: GUI 表示が必要な場合は Rust 例、もしくは nyash 本体を --features gui でビルドし、ビルトイン EguiBox 用の Nyash スクリプトを別途用意(要サンプル整備)。

診断スイッチ(共通)

  • NYASH_DEBUG_PLUGIN=1: プラグインのロードパス/解決状況を表示
  • NYASH_CLI_VERBOSE=1: プラグインホスト初期化やランタイムの詳細ログ
  • Windows/プラグインの DLL 解決が怪しい場合は NYASH_PLUGIN_PATHS で DLL ディレクトリを明示(; 区切り)

既知の制約 / TODO

  • Linux/WSL での表示は WSLg/GL 依存。描画バックエンドが無い環境ではヘッドレス(実ウィンドウ無し)となる。必要パッケージとバックエンド環境を整備してから再試行。
  • ビルトイン EguiBoxsrc/boxes/egui_box.rs)は --features gui でビルド時に有効。Nyash スクリプト側の API はプラグイン版と異なる(setTitle/setSize/addText/run。Linux GUI 確認用にビルトイン用サンプルapps/egui-builtin/)を追加して整備する。
  • Windows AOT リンクは MSVC link.exe を既定fall back: clang。lld へのスイッチ(速度優先)を将来オプション化検討。

次アクション(引き継ぎ TODO

  • Windows: 4通りの実行Cranelift 直/JIT、LLVM 直、AOT EXEapps/egui-hello/main.nyash のウィンドウ表示を再確認(NYASH_DEBUG_PLUGIN=1 でログ採取)。tools/build_egui_aot_manual.ps1 のリンク手順を更新lld/system libs 明示)。

— Tools 整理2025-09-07

  • 統一エントリを追加: tools/ny_plugin.ps1Windows, tools/ny_plugin.shWSL/Linux
    • 使い方: -Mode vm|jit|aot -Script <nyash file> -Jobs 24 [-PluginPaths <dirs>] [-Debug]
    • 例: pwsh -File tools\ny_plugin.ps1 -Mode vm -Script apps\tests\plugins\counter_min.nyash -Jobs 24 -Debug
  • 既存 egui 系スクリプトは非推奨化: tools/egui_quick.ps1/.sh, tools/build_egui_aot_manual.ps1, tools/egui_run.bat(ヘッダに Deprecated を明記)。
  • 一時的に残す: tools/egui_aot.bat(成功実績あり、当面案内は ny_plugin.ps1 を優先)。

— BoxCall 降ろし(設計メモ)

  • 目的: VM/JIT/AOT のいずれでも同一MIRBoxCallが機能。TypeBox v2 の invoke を汎用ブリッジで実行。
  • 方針: (box_type, method)→(type_id, method_id) を nyash.toml から解決し、TLV(i32/bool/f64/string/handle最小) を nyrt invoke に渡す。
  • 検証: apps/tests/plugins/counter_min.nyash を VM/JIT/AOT で一致inc→get 発火、Result>=1
  • WSL: Cranelift/LLVM の直実行は「スタブ終了」が期待値であることを README/ガイドに明記。GUI が必要なら Rust 例 or ビルトイン EguiBox 経路を案内。
  • Linux 向けプラグイン with-egui 実装の導入可否を検討(plugins/nyash-egui-plugin/src/lib.rswinrun と類似の linrun を追加)。
  • ビルトイン EguiBox 用の Nyash サンプルを apps/egui-builtin/ として追加し、--features gui での手順を dev/selfhosting/ または docs/ に追記。
    • nyash.handle.of / nyash.string.len_h / nyash.console.birth_hSYM_* に統一
  • A2: string_len ヘルパ抽出(共通化)完了
    • src/jit/lower/core/string_len.rs 新設、emit_len_with_fallback_* を移設
    • 呼び出し元はそのまま(挙動は不変)
  • A3: 観測の統一(第一弾)
    • string_len 内で observe::lower_hostcall を発火len_h/any.length_h
    • Cranelift/ObjectBuilder の emit_host_call[_typed]NYASH_JIT_TRACE_IMPORT=1 によるインポート解決ログを追加

観測結果A3 導入後)

  • NYASH_JIT_TRACE_IMPORT=1nyash.string.len_h / nyash.any.length_h の import 呼び出しを確認JIT/AOT 両方)
  • それでも NYASH_JIT_TRACE_LEN=1 の thunk 到達ログは出ず → 依然解決先に差異がある疑い(要継続調査)

■ 実行系の最終方針Phase 15 着地)

  • ランタイム: Interpreter / VM
  • 配布: Cranelift AOT (EXE) / LLVM AOT (EXE)
  • JIT 直実行: 封印(ドキュメント上も「実験的/無効」へ集約)

■ 検証チェックリスト(更新)

  • VM: ./target/release/nyash --backend vm apps/smokes/jit_aot_string_min.nyash → Result:1
  • AOT(Cranelift): ./tools/build_aot.sh apps/smokes/jit_aot_string_length_smoke.nyash -o app./app 実行 → 期待結果
  • AOT(Windows oneshot): pwsh -File tools/windows/build_egui_aot.ps1 -Input apps/egui-hello-plugin/main.nyash -Out app_egui → 画面表示

— Phase A無振る舞い変更リファクタ方針継続

  • A1: Hostcall シンボルを定数に統一(直書き排除)
    • "nyash.handle.of"jit::extern::handles::SYM_HANDLE_OF
    • "nyash.string.len_h"jit::extern::collections::SYM_STRING_LEN_H
    • "nyash.console.birth_h" → 既存の定数へ(なければ extern::... に追加して使用)
  • A2: 長さ取得の共通化
    • 新規: src/jit/lower/core/string_len.rs
    • 既存の emit_len_with_fallback_{param,local,literal} をこのモジュールへ抽出し、core.rs/ops_ext.rs から呼び出すだけにする(挙動は据え置き)。
    • 目的: 重複と分岐のばらけを解消し、シンボル差し替えや観測フックを一点で行えるようにする。 ※ Phase A は「振る舞いを変えない」ことを厳守する。
  1. 診断イベントの追加(軽量)

    • emit_len_with_fallback_*lower_box_call(len/length)observe::lower_hostcall を追加し、 Param/Local/リテラル/handle.of どの経路か、select の条件string_len==0をトレース可能にするNYASH_JIT_EVENTS=1)。
  2. AOT segfault (稀発) の追跡(低優先)

    • tools/aot_smoke_cranelift.sh 実行中に稀に segv.o 生成直後/リンク前後)。
    • nyash.string.from_u64x2 載せ替えと DT_TEXTREL 警告が出るので、PIE/LTO/relro 周りと TLS/extern の登録順を確認。
  3. 警告のノイズ低減(低優先)

    • core_hostcall.rs の unreachable 警告case 統合の名残)。
    • jit/lower/* の unused 変数/unused mut の警告。

影響ファイル(今回差分)

  • src/jit/lower/core.rslen/length 二段フォールバック呼出し、保存強化)
  • src/jit/lower/core/ops_ext.rsStringBox len/length 優先処理、リテラル即値畳み込み、保存)
  • src/jit/hostcall_registry.rsnyash.string.len_h 追補)
  • ドキュメント: README(ja/en) の実行モード更新、ガイドegui AOTに oneshot スクリプト反映
  • src/jit/extern/collections.rsSYM_STRING_LEN_H 追加)
  • src/jit/lower/extern_thunks.rsnyash_string_len_h 追加)
  • src/jit/lower/builder/cranelift.rsSYM_STRING_LEN_H のシンボル登録)
  • tools/aot_smoke_cranelift.sh(新規)
  • apps/smokes/jit_aot_string_length_smoke.nyash(新規)

再現/確認コマンド

  • ビルドJIT/AOT: cargo build --release --features cranelift-jit
  • JITAOT.o出力: NYASH_AOT_OBJECT_OUT=target/aot_objects/test_len_any.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_any_len_string.nyash
  • AOT 連結〜実行: bash tools/aot_smoke_cranelift.sh apps/smokes/jit_aot_string_min.nyash app_str

次アクション(引き継ぎ TODO

  • Return の後方走査材化を実装BoxCall/Call/Select 等の定義→保存→Return 接続)。
  • emit_len_with_fallback_* / lower_box_call(len/length) にイベント出力を追加(選択分岐/経路ログ)。
  • AOT segv の最小再現収集PIE/relro/TLSの前提確認nyrt 側エクスポート/リンカフラグ点検。
  • NYASH_USE_PLUGIN_BUILTINS=1 時の length も robust path を常に使用することを E2E で再確認。

メモ

  • jit_aot_any_len_string.nyashreturn s.length() の Return 経路解決が決め手。材化を強化すれば 3 が期待値。
  • 既存の Array/Map 経路・他の smokes は影響なしlen/size/get/has/set の HostCall/PluginInvoke は従来どおり)。

■ 進捗サマリ

  • Phase 12 クローズアウト完了。言語糖衣12.7-B/P0と VM 分割は反映済み。
  • Phase 15Self-Hosting: Cranelift AOTへフォーカス移行。
    • 設計/仕様ドキュメントとスモーク雛形を追加済み。
      • 設計: docs/backend-cranelift-aot-design.md
      • API案: docs/interfaces/cranelift-aot-box.md
      • LinkerBox: docs/interfaces/linker-box.md
      • スモーク仕様: docs/tests/aot_smoke_cranelift.md
      • 雛形スクリプト: tools/aot_smoke_cranelift.sh, tools/aot_smoke_cranelift.ps1
  • README にセルフホスト到達の道筋を明記C ABI を Box 化)。

【ハンドオフ20250906 3rd— String.length: constfold→Return 材化の不一致 調査ログとTODO】

概要(現象)

  • 目標: JIT/JITAOT で StringBox.length/len が 3 を返すべき箇所で 0 になるケースを解消。
  • 現状: Lower 中の早期 constfold で length = 3 を確実に計算([LOWER] early constfold ... = 3 が出力。Return 時点でも ValueId(3)known_i64=3 と認識される([LOWER] Return known_i64?=true。にもかかわらず最終結果実行結果は 0。

重要な観測(再現とログ)

  • MIR ダンププリンタ仕様上、BoxCall は call %box.method() として表示) 0: %1 = const "abc" 1: %2 = new StringBox(%1) 2: call %2.birth(%1) // birth は通常 calldst なし) 3: %3 = call %2.length() // これも通常 call 表記(内部は BoxCall 4: ret %3
  • Lower ログ:
    • [LOWER] early const-fold StringBox.length = 3 が出るconstfold 成功)
    • [LOWER] Return value=ValueId(3) known_i64?=true param?=false local?=true
    • それでも実行結果は Result: 0
  • nyash.jit.dbg_i64[JITDBG]の出力が実行時に出ていないimport は宣言されるが call が観測されず)。

今回入れた変更(実装済・該当ファイル)

  • Return/材化の強化known を最優先)
    • src/jit/lower/core_ops.rs: push_value_if_known_or_param を「known_i64 最優先」に変更。
    • src/jit/lower/core.rsI::Return でも known_i64 を最優先で積むように変更。
  • Call/ArrayGet の戻り値の保存
    • src/jit/lower/core.rs: I::Call 戻り値を dst が無い場合もスクラッチローカルへ保存(栈不整合の防止)。I::ArrayGet 戻り値も dst スロットへ保存。
  • String.length/len の早期 constfold を二段に強化
    • src/jit/lower/core.rs: BoxCall 入り口で StringBox.literal の length/len を即値化(最優先)。
    • src/jit/lower/core/ops_ext.rs: 同様の constfold を堅牢化NewBox(StringBox, Const) から復元)。
    • src/jit/lower/core.rs: lowering 前に known_str を事前シード、string_box_literal マップNewBox → リテラル文字列を構築し、Copy 伝播も対応。
  • トレース導線
    • src/jit/lower/core/string_len.rs: 二段フォールバックparam/local/literalにデバッグフックタグ 110x/120x/130x 系)追加。
    • src/jit/lower/builder/cranelift.rs: ローカル slot の store/load トレース(NYASH_JIT_TRACE_LOCAL=1)。
    • crates/nyrt/src/lib.rs: AOT 側の nyash.string.len_h / nyash.any.length_h[AOT-LEN_H] を追加。
    • src/jit/lower/extern_thunks.rs: nyash_string_from_u64x2[JIT-STR_H] を追加JIT のハンドル生成観測)。nyash_handle_of[JIT-HANDLE_OF] を追加。

仮説(根本原因)

  • constfold で 3 を積めているにも関わらず、Return 時の実返却が 0。優先順位の修正により known_i64 から 3 を積むよう修正済みだが、compiled JIT 関数内での Return 材化導線ret_block への引数配線/最後の returnが値 0 に擦り替わる経路が残っている可能性。
    • ret_block/ジャンプ引数の材化不整合
    • 後続命令でスタックが上書きされる経路
    • birth の dst なし call で残留値が生じていた可能性Call 戻り値スクラッチ保存で対策済)

次アクションTODO

  1. Return の後方走査材化優先・CURRENT_TASK 既存 TODO の実装)

    • BoxCall/Call/Select/Const/Copy/Load に遡って、Return が値を確実に拾う材化パスを補強する。
    • 既に known_i64 最優先化は実施済み。残りは ret_block 引数配線の最終確認CraneliftBuilder の ret 経路)。
  2. 実行時の値トレース強化(短期)

    • emit_returnCraneliftBuilderで、ret_block へ jump 直前の引数 vnyash.jit.dbg_i64(299,v) で確実に呼ぶenv でON
    • ret_block 入口パラメータの return_ 直前でも dbg_i64(300,param0) 呼び出しを足し、どこで 0 になるかを確定する。
  3. BoxCall(length/len) の早期 fold 命中率最終確認

    • NYASH_JIT_TRACE_LOWER=1[LOWER] early const-fold ... = 3 が必ず出ることを確認。
    • 既に出ているが、Return までの導線で 3 が 0 に化ける起点を 2) で特定する。
  4. AOT/JITAOT 観測の整備(参考)

    • [AOT-LEN_H] で AOT 側 len_h/any.length_h の handle 解決有無をログ化。JITAOT smoke での差異を収集。

再現/確認コマンド(更新)

  • 早期 fold と Return 導線ログ:
    • NYASH_JIT_TRACE_LOWER=1 NYASH_JIT_TRACE_RET=1 NYASH_AOT_OBJECT_OUT=target/aot_objects/test_len_any.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_any_len_string.nyash
  • ローカル slot 観測:
    • NYASH_JIT_TRACE_LOCAL=1 NYASH_AOT_OBJECT_OUT=... --jit-direct ...
  • AOT 側の handle 解決ログ:
    • NYASH_JIT_TRACE_LEN=1 bash tools/aot_smoke_cranelift.sh apps/smokes/jit_aot_string_min.nyash app_str

補足メモ

  • MirPrinter は BoxCall を call %box.method() と出力する仕様(今回は BoxCall 経路で constfold が呼ばれていることは [LOWER] ログで確認済み)。
  • call %2.birth(%1) の戻り値残留に備え、I::Call の dst なし呼び出しでもスクラッチ保存して栈を消費するよう修正済み(回帰に注意)。

担当者への引き継ぎポイント

  • まず 2) の dbg を CraneliftBuilder の ret 経路jump to ret_block と return_に追加し、v/param0 が 0 になる箇所を特定してください。
  • 次に 1) の Return 後方走査材化を入れて、BoxCall/Select/Copy 等いずれの経路でも Return が安定して値を拾えるようにしてください。
  • その後、smoke apps/smokes/jit_aot_any_len_string.nyashResult: 3 で通ることを確認し、constfold のログと一致することをもってクローズ。

【将来計画(バグ修正後)— JIT を exec 専用にし、VM 連携を段階的に廃止】

目的

  • JIT は「コンパイル実行exec」に一本化し、VM 依存のレガシー経路param-index/TLS参照を撤去する。
  • 値の材化・ハンドル管理・hostcall を JIT 側で一貫させ、境界の不整合を根本から減らす。

ロードマップ(段階移行)

  1. 実行モードの明確化(設定)

    • 環境変数 NYASH_JIT_MODE=exec|compile|off を導入。
    • 既存の NYASH_JIT_STRICT は非推奨化し、MODE=compile に集約。
  2. JIT ABI の一本化

    • src/jit/lower/extern_thunks.rs などから with_legacy_vm_args を撤去。
    • nyash_handle_of を含む extern は「JIT引数/ハンドルのみ」を受け付ける設計に変更。
    • ランタイム境界で VMValue -> JitValue(Handle) へのアダプタを用意。
  3. レガシー撤去JIT/AOT側

    • crates/nyrt/src/lib.rsnyash.string.len_h/nyash.any.length_h から param-index フォールバックを削除。
    • lowering の -1 センチネルや VM 依存の fallback を廃止し、handle.of または既存ローカルハンドルに統一。
  4. フォールバック方針(移行期間)

    • 関数単位で unsupported>0 の場合のみ VM にフォールバック。
    • オプション NYASH_JIT_TRAP_ON_FALLBACK=1 を追加し、移行時の漏れを検出可能に。
  5. Return 導線の強化(本タスクの延長)

    • Cranelift 生成の ret 経路に dbg を常設envでON
    • Return の後方走査材化を標準化し、const-fold/BoxCall/Select いずれでも Return が値を確実に拾うように。
  6. ドキュメント/テスト更新

    • README/CURRENT_TASK にモード説明と運用方針を追記。
    • CI の smoke は MODE=exec を常態化し、compile-only はAOT出力/ベンチのみで使用。

影響範囲(主な修正ポイント)

  • src/jit/manager.rs(モード/実行ポリシー)
  • src/jit/lower/extern_thunks.rsレガシーVM依存排除、JIT ABI専用化
  • src/jit/lower/core.rs / src/jit/lower/core_ops.rs-1センチネル削除・ハンドル材化徹底
  • crates/nyrt/src/lib.rsdotted名hostcallのレガシー経路削除
  • ドキュメントREADME/CURRENT_TASK

ロールアウト/リスク

  • フラグ駆動で段階的に切替(デフォルト exec)。
  • リスク: plugin経路/hostcall registry/ハンドルリーク。
    • 緩和: handles::begin_scope/end_scope_clear によりハンドル回収を徹底、registryの検証を追加。

【本日更新】

  • VM if/return 無限実行バグを修正(基本ブロック突入時に should_return/next_block をリセット。include 経路のハングも解消。
  • ArrayBox プラグイン生成失敗に対し、v2 ローダへパス解決フォールバック(plugin_paths.search_paths)を追加し安定化。
  • std/string の P0 関数を Ny 実装で追加length/concat/slice/index_of/equals。index_of は substring ループで代替。
  • 残課題: string_smoke で fails 累積の else 側に φ が入らず未定義値参照MIR Builder 側の SSA/φ 振る舞い)。別タスク化。

【ハンドオフ20250906— AOT/JITAOT 足場と箱下寄せリファクタ】

  • 変更サマリ

    • nyrt: AOT 連携の dotted 名を追加Map/String/Any/birth
      • nyash.map.{size_h,get_h,get_hh,set_h,has_h}
      • nyash.string.{len_h,charCodeAt_h,concat_hh,eq_hh,lt_hh} / nyash.any.{length_h,is_empty_h}
      • NewBox/文字列: nyash.instance.birth_name_u64x2, nyash.string.from_u64x2
    • JITAOT(ObjectBuilder):
      • 文字列リテラル→ハンドル生成u64x2 パック → nyash.string.from_u64x2
      • 出力関数を ny_main としてエクスポート
      • 最小 Store/Loadi64を StackSlot で実装
    • Lower箱を下に寄せる最小整理:
      • Map: param 不在でもローカルハンドルがあれば _H シンボルで直呼び
      • Any.length: StringBox は nyash.string.len_h を優先。ローカル/再構築/旧 index の順にフォールバック
      • Copy/Load でローカルハンドルを dst 側 slot に伝播
      • Array.length は ArrayBox 受けに限定ops_ext ガード)
  • 追加スモークJITAOT

    • apps/smokes/jit_aot_string_min.nyashconcat+eq→ PASS
    • apps/smokes/jit_aot_any_isempty_string.nyash → PASS
    • apps/smokes/jit_aot_any_len_string.nyash → 現状 Result: 0後述の未解決
    • apps/smokes/jit_aot_map_min.nyash → 環境により MapBox 生成が必要
  • 実行例

    • 文字列ミニAOT:
      • NYASH_AOT_OBJECT_OUT=target/aot_objects/test_str.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_string_min.nyash
      • cc target/aot_objects/test_str.o -L target/release -Wl,--whole-archive -lnyrt -Wl,--no-whole-archive -lpthread -ldl -lm -o app_str && ./app_strResult: 1
    • isEmptyAOT:
      • 同様に app_emptyResult: 1
    • Map 最小AOT:
      • .o 生成/リンクは通る。new MapBox() はプラグイン/設定に依存(nyash.toml.so の配置を確認)
  • 未解決 / 既知の課題(優先度高)

    1. String.length の AOT 実行が 0 になるケース
      • 症状: s = new StringBox("abc"); return s.length()Result: 0
      • 現状の対処: Any.length を String.len_h 優先にし、ローカル/再構築/旧 index の順でフォールバック。Const fold も追加済み。
      • 追加方針: 受け型伝播Copy/Load→dst へ型共有)をより堅牢化。最終手段として、ローカルハンドル時に string.len_hany.length_h の二段呼び分け0 返りのときだけ後者)で保険を張る。
    2. MapBox 生成AOT 実行バイナリ)
      • 環境によりプラグイン解決が必要。nyash.toml のあるディレクトリで実行し、必要なら各プラグインを target/release に配置。
  • 次アクション(引き継ぎ TODO

    • Any.length の 0 問題を完全解消
      • 受けの型/ハンドル伝播Copy/Load/Storeを統一ヘルパ化し、length/len/charCodeAt で確実にハンドルを積む
      • StringBox(Const) は定数畳み込みを最優先len を即値化)
      • 保険: string.len_h→0→any.length_h の順にフォールバック(ローカルハンドル時)
    • メソッド→シンボル/引数規約の集中表を作成Array/Map/String/Any
      • ops_ext/core の分岐重複を縮減(箱の責務を「下」に寄せる)
    • AOT スモーク拡充
      • String/Array の length/len を追加、select/分岐のミニ例も用意
      • Map.get/has/setプラグインあり環境用
  • 影響ファイル(主要)

    • 追加/更新: crates/nyrt/src/lib.rsdotted エクスポート多数)、 src/jit/lower/builder/{object.rs,cranelift.rs}src/jit/lower/{core.rs,core/ops_ext.rs,core_hostcall.rs}、 スモーク: apps/smokes/jit_aot_*.nyash

■ ハンドオフJIT AOT / LLVM の現状と次アクション)

  • 現状サマリ

    • Array fastpath: VM 側 len/length を最前段に早期化Void→0 も確認)。
    • Null 互換: NullBox→VMValue::Void へ統一(比較の整合確保)。
    • std/array smoke: NYASH_DISABLE_PLUGINS=1 で PASSlen/push/pop/slice
    • LLVM AOT: 復活nyrt の read lock 寿命修正、build_llvm.sh のリンクパス -L target/release 追加)。
    • JIT AOT(ObjectBuilder): P0 安定化P1 実装済const/return、i64 binop、compare、select、branch/jump、hostcall 基本、PHI最小化ブロック引数
      • jit-direct で .o 生成確認: apps/smokes/jit_aot_arith_branch.nyash → Result 13、.o 出力 OK。
      • build_aot.sh は既定で STRICT=0、出力 target/aot_objects/main.o に固定。
    • nyrt: AOT 連携用 dotted 名 alias を Array に追加(nyash.array.{len_h,get_h,set_h,push_h})。
  • 優先TODO次にやること

    1. JIT AOT P2: hostcall 拡張(規約ベースの最小集合)
      • Map: nyash.map.{size_h,get_h,has_h,set_h} の dotted 名を nyrt に追加(既存実装へ forward
      • String: 代表メソッドlen/concat/substring/indexOf 等)で必要なシンボルを dotted 名として追加
      • ObjectBuilder から emit_host_call_typed で呼び出しLower の対応表に従う)
    2. LowerCore: slot/name→hostcall マッピングbyslot を優先、byname は互換フォールバック)
      • Array/Map/String の最小セットlen/get/set/push、size/get/has/set、len/concat など)
    3. 後続(必要時): JIT AOT スモークを追加分岐あり最小、Array/Map の各1本
  • 実行コマンド(確認用)

    • JIT AOTjit-direct + .o:
      • NYASH_DISABLE_PLUGINS=1 NYASH_JIT_EVENTS=1 NYASH_AOT_OBJECT_OUT=target/aot_objects/jit_aot_arith.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_arith_branch.nyash
    • LLVM AOTemit+link:
      • LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) tools/build_llvm.sh apps/tests/ny-llvm-smoke/main.nyash -o app

■ 現在のフォーカスJITオンリー一旦の着地

  1. Core 緑維持(完了)
    • tools/jit_smoke.sh / Roundtrip(A/B) / Bootstrap(c0→c1→c1') / Using E2E = PASS
  2. CI 分離(完了)
    • Core常時: tools/jit_smoke.sh + Roundtrip
    • Plugins任意: NYASH_SKIP_TOML_ENV=1 ./tools/smoke_plugins.shstrict既定OFF、NYASH_PLUGINS_STRICT=1でON
  3. Selfhost E2E完了
    • ny_plugins 有効 + NYASH_USE_NY_COMPILER=1 の自己ホストE2Eをオプションゲートで運用
  4. クリーンアップ(完了)
    • 未使用import/変数の整理、runner責務分割、tools出力体裁の統一

■ ブランチ/構成Phase 15

  • 実装ブランチ: phase-15/self-host-ny-mir
  • 既存 Workspace は維持(crates/*)。
  • 方針: crates 側は変更せず「Nyash スクリプト + nyash.exe」だけで実装・運用Windows優先
    • 例: C:\git\nyash-project\nyash_self\nyash 直下で target\release\nyash 実行。
  • Nyash 製パーサは apps/selfhost/ny-parser-nyash/Nyashコードとして配置最初は最小サブセット
  • MIR 解釈層は既存 backend/mir_interpreter.rsrunner/modes/mir_interpreter.rs を拡充。
  • AOT 関連の雛形は src/backend/cranelift/ に維持feature gate: cranelift-aot)。

■ 再開TODO優先順

  1. std Ny実装の実体化P0/P1
    • string: length/concat/slice/indexOf/equals → P0 完了string_smoke PASS
    • array: len/push/pop/slice を内蔵経路で先行(次着手)
    • map: get/set/len/keys (+values/entries/forEach)
    • jit_smoke に機能検証を常時化Coreは NYASH_DISABLE_PLUGINS=1
  2. NyコンパイラMVPのsubset拡張
    • let/call/return に続き if/ブロック/関数引数まで拡張し、NYASH_USE_NY_COMPILER=1 スモークを充実
  3. Selfhost E2E ゲートの昇格
    • 連続N回グリーン後にCI optional→requiredへ昇格trace/hash基準
  4. Plugins厳格ONの段階移行
    • Core13準拠サンプルへ置換し、NYASH_PLUGINS_STRICT=1 ゲートで順次ONに復帰

【優先追加 — JIT AOTObjectBuilder安定化・拡張】

  • P0: 安定化(完了)
    • switch_to_block なしでの命令発行panic対策emit_const系
    • 終端命令なしVerifierエラー対策emit_return 実装)
    • build_aot.sh の STRICT 緩和デフォルト0 obj 直指定
  • P1: 最小命令カバレッジ(今すぐ実装)
    • i64 binop: add/sub/mul/div/mod を実コード生成
    • compare: eq/ne/lt/le/gt/ge → b1→i64(0/1) へ正規化してpush
    • 分岐/ジャンプ: br_if_top_is_true/jump_to 実装ブロック遷移とCFG整合
    • select: emit_select_i64 実装cond, then, else の順)
  • P2: hostcall 系の型付き発行(必要最小限)
    • array/map/string/integer の代表 extern を ObjectBuilder に実装
    • ny-llvm-smoke 等に相当する JIT AOT smoke 追加
  • P3: CI スモーク
    • tools/jit_smoke.sh に AOT(JIT)最小タスクを追加STRICT=0 で .o 生成確認)

ブロッカー/暫定対応20250905 更新)

  • 影響範囲Backend差

    • JIT(cranelift) → 影響なし。
    • VM(backends=vm) → if/return 無限ループは修正済み(基本ブロック突入時に CF リセット)。
    • 結論: include ハングの根因は VM の制御フロー残存フラグ。修正により解消。
  • 事象A: include ハング → 解消

    • apps/tmp_len_min.nyash/apps/tmp_len_test.nyash 正常完走を確認。
  • 事象B: ArrayBox プラグイン生成エラー → 解消

    • v2 ローダにフォールバック探索(plugin_paths.search_pathsを追加し、workspace の ./target/release/*.so を自動解決。
    • DEBUG 時に birth 戻り code/out_len をロギング。
  • 事象C: std/string_smoke の最終段で未定義値参照 → 解消

    • MIR Builder の if 降ろしで φ を必ず生成then のみ代入・else 未代入時は pre 値と then 値で合流)。
    • string_smoke PASS を確認。

次アクション(デバッグ計画)

  • A1: includeハング最小化再現を固定VM経路優先で調査

    • apps/tmp_len_test.nyash 固定、NYASH_DEBUG=1execute_include_exprensure_static_box_initialized までの経路にログを追加。
    • included_filesinclude_stack の push/pop と RwLock/RwLock の取り回しを確認。ポップ忘れ/二重ロックがないか検査。
    • apps/std/string.nyash 内のメソッドを段階的に無効化して最小原因を特定(現状 length のみでも再現)。
  • A2: VM if/return 無限実行VM限定を優先修正

    • 症状: JITは1回then→Return→終了。VMはthenのprintが際限なく繰り返される。
    • 再現最小: apps/tmp_if_min.nyash
      static box Main {
        main() {
          local x
          x = 3
          if x == 3 {
            print("ok3")
            return 0
          }
          print("bad")
          return 1
        }
      }
      
      • JIT: ./target/release/nyash apps/tmp_if_min.nyash → 1回だけ ok3, Result:0
      • VM: timeout 4s ./target/release/nyash --backend vm apps/tmp_if_min.nyash → ok3 が無限に出続け TIMEOUT
    • MIRダンプNYASH_VM_DUMP_MIR=1)では if 降下は正しく、then/else 各ブロックは ret を含む。
      • 例: bb1 に extern_call log("ok3") の後 ret 0。bb2 に ret 1
    • 観測ログ(NYASH_VM_DEBUG_EXEC=1)では Print/Const が繰り返し実行。Return の終端処理が機能していない疑い。
    • 仮説: VM 実行ループの制御フロー(execute_function)で ControlFlow::Return を受け取った後の関数脱出が何らかの理由で無効化/上書き/再入している。
    • 着手案:
      • execute_function に短期ログ: 現在ブロックID/terminator種別/should_return セット→関数戻りの分岐をeprintlnNYASH_VM_DEBUG_EXEC=1時
      • execute_instructionReturn ディスパッチ時に明示ログval_id/値を出す現状VTトレースも可
      • previous_block/loop_executor/record_transition で自己遷移が起きていないか確認。
      • BasicBlock::add_instruction にて terminator設定/Successorsの更新は正常コード・MIR上はOK。処理後の next_block 決定ロジックを再点検。

ハンドオフ(変更点・補助情報)

  • 追加ファイルstd MVP + smokes
    • apps/std/string.nyash, apps/std/array.nyash
    • apps/smokes/std/string_smoke.nyash, apps/smokes/std/array_smoke.nyash
  • スクリプト/設定の更新
    • tools/jit_smoke.sh: Std smokes に timeout 15s、ArrayBox未提供時は SKIP を出力
    • tools/smoke_plugins.sh: NYASH_PLUGINS_STRICT=1 のON/OFF表示
    • nyash.toml: ny_plugins に std 2件を追加
    • src/runner/modes/vm.rs: NYASH_VM_DUMP_MIR=1 でVM実行前にMIRをダンプ
    • src/mir/builder/stmts.rs: 末尾 return/throw 後に同ブロックへ更に命令を積まないための早期breakを追加安全強化
  • 再現とログ
    • VM再現: timeout 4s ./target/release/nyash --backend vm apps/tmp_if_min.nyash
    • JIT対照: ./target/release/nyash apps/tmp_if_min.nyash
    • MIRダンプ: NYASH_VM_DUMP_MIR=1 --backend vm ...
    • 命令トレース: NYASH_VM_DEBUG_EXEC=1 --backend vm ...
  • プラグイン/ArrayBox注意
    • 既定でプラグイン経由に迂回するため、未ビルドだと ArrayBox 生成に失敗。
    • 回避: NYASH_USE_PLUGIN_BUILTINS=0 または NYASH_PLUGIN_OVERRIDE_TYPES から ArrayBox,MapBoxを除外。もしくはプラグインをビルド。

すぐ着手できるTODOVM側

  • execute_function にブロック遷移/Return検出ログNYASH_VM_DEBUG_EXEC=1時のみ
  • Return発生時に確実に Ok(return_value) で関数を抜けることを確認(should_return/next_block の上書き防止)
  • record_transition/loop_executor の副作用で自己遷移が起きていないか確認
  • 修正後、apps/tmp_if_min.nyash が VM/JIT 両方で一発終了することを確認MIRダンプ上は既に正しい
  • B1: ArrayBox 経路の選択を明示
    • 手元では NYASH_USE_PLUGIN_BUILTINS=0 で内蔵にフォールバックするか、プラグインを cargo build -p nyash-array-plugin --release で用意。
    • CIは当面 SKIP 維持。

実行メモ(暫定)

  • Std smokes手元で回す
    • NYASH_LOAD_NY_PLUGINS=1 NYASH_USE_PLUGIN_BUILTINS=0 ./tools/jit_smoke.sh
    • またはプラグインをビルドしてから NYASH_LOAD_NY_PLUGINS=1 ./tools/jit_smoke.sh

■ 予定R5 拡張: Ny Plugins → Namespace

  • Phase A最小: 共有レジストリ NyModules を追加し、env.modules.set/get で exports を登録/取得。
    • [ny_plugins] は戻り値Map/StaticBoxを「ファイルパス→名前空間」に変換して登録。
    • 名前空間導出: ルート相対・区切りは .、拡張子除去・無効文字は _。予約 nyashstd.* 等は拒否。
  • Phase B範囲: 共有InterpreterオプションNYASH_NY_PLUGINS_SHARED=1)で静的定義を共有。ログに REGISTERED を出力。
  • Phase C言語結線: using <ns>NyModules 参照→未解決時にファイル/パッケージ解決nyash.linkへフォールバック。

■ 直近で完了したこと主要抜粋JIT

  • R1: JSON v0 ブリッジ(--ny-parser-pipe/--json-file)、変換器 src/runner/json_v0_bridge.rs、スモーク追加

  • R2: ラウンドトリップ E2Etools/ny_roundtrip_smoke.{sh,ps1}

  • R3: 直結ブリッジ v0--parser ny/NYASH_USE_NY_PARSER=1NYASH_DUMP_JSON_IR=1)→ return (1+2)*3 で 9

  • R5: Ny スクリプトプラグイン([ny_plugins]列挙実行OK/FAIL 出力・列挙のみガード付き)

    • NyModules登録/名前空間導出/Windows正規化の仕様確定・回帰スモーク
    • using/namespaceゲート・nyash.link最小・resolverキャッシュ・実行時フック提案付き診断
  • AOT P2(step1): RUN スモーク配線(最小オブジェクト生成+実行ログ)

  • ■ 直近で完了したこと(主要抜粋)

  • T0: MIRインタープリタ強化分岐/比較/PHI/extern/Box最小 Runner 観測ログ

  • T1: Nyash製ミニパーサ整数/四則/括弧/return→ JSON IR v0 出力

  • T2: JSON IR v0 → MIRModule 受け口(--ny-parser-pipe

  • T3: CLI 切替/ヘルプ(--ny-parser-pipe/--json-file、mirヘルプ追補

  • T4: Docs/Samples/Runner scriptsapps/ny-mir-samples, tools/*, README 追補)

  • Phase 15 起点準備

    • CLIに --backend cranelift-aot--poc-const を追加(プレースホルダ動作)。
    • src/backend/cranelift/{mod.rs,aot_box.rs,linker_box.rs} の雛形追加feature gate
    • MIR解釈層スケルトンsemantics/eval.rsbackend/mir_interpreter.rs)の確認

■ 再開用クイックメモJITのみ

  • ビルド
    • VM/JIT: cargo build --release --features cranelift-jit
    • LLVM必要時: LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm
    • AOT導入後: cargo build --release --features cranelift-aot
  • スモークJIT/VM
    • Core: NYASH_DISABLE_PLUGINS=1 NYASH_CLI_VERBOSE=1 ./tools/smoke_vm_jit.sh
    • Parser Bridge: ./tools/ny_parser_bridge_smoke.sh
    • Roundtrip: ./tools/ny_roundtrip_smoke.shA/B
    • Plugins: NYASH_SKIP_TOML_ENV=1 ./tools/smoke_plugins.sh(厳格は NYASH_PLUGINS_STRICT=1 時のみON
    • Bootstrap: ./tools/bootstrap_selfhost_smoke.sh
    • Using/Resolver: ./tools/using_e2e_smoke.sh

■ 状態

  • JIT自己ホストMVP: 到達E2E/ブートストラップ/ドキュメント/CI分離まで完了
  • リファクタ: Step1/2/3 完了未使用掃除・runner分割・tools体裁統一
  • 次回は「std実装の実体化」と「Nyコンパイラsubset拡張」から再開
  • 参照
    • Phase 15 概要/ロードマップ: docs/development/roadmap/phases/phase-15/README.md, docs/development/roadmap/phases/phase-15/ROADMAP.md
    • ハンドオフ: docs/handoff/phase-15-handoff.md
    • 設計/API: docs/backend-cranelift-aot-design.md, docs/interfaces/*

■ 合否基準P0: Ny→MIR→MIR-Interp→VM 最小成立)

  • 自作Nyashパーサ最小サブセットが Nyash で動作し、テスト入力から中間形式(JSON暫定)を生成できる。
  • Runner が中間形式を MIRModule に変換し、MIR 解釈層で実行して既知の結果(例: Result: 42)を出力する。
  • 代表ケース(整数四則演算/括弧/returnで往復が安定。

■ JSON IR v0暫定スキーマ

  • version: 整数(例: 0
  • kind: 固定 "Program"
  • body: 配列Stmt[]
  • Stmt最小
    • { "type": "Return", "expr": Expr }
  • Expr最小
    • { "type": "Int", "value": 123 }
    • { "type": "Binary", "op": "+"|"-"|"*"|"/", "lhs": Expr, "rhs": Expr }
  • error失敗時
    • { "version":0, "kind":"Error", "error": { "message": "...", "span": {"start":N, "end":M} } }
    • return 1+2*3 → {"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Binary","op":"+","lhs":{"type":"Int","value":1},"rhs":{"type":"Binary","op":"*","lhs":{"type":"Int","value":2},"rhs":{"type":"Int","value":3}}}}]}
    • return (1+2)*3Binary('*', Binary('+',1,2), 3) の形で生成

■ 補足(優先/範囲)

  • 先行するのは Ny→MIR→MIR-Interp→VM の自己ホスト経路AOTはP2以降
  • OS 優先: Windows →(後続で Linux/macOS
  • メモリ/GC: P0は整数演算/定数返し中心でNyRT拡張不要。
  • Codex 非同期運用: tools/codex-async-notify.shtools/codex-keep-two.sh 継続利用。

実行コマンド(サマリ)

  • VM/JIT 実行例

    • printf "Hello\n" | NYASH_CLI_VERBOSE=0 ./target/release/nyash apps/ny-echo/main.nyash
    • printf "Hello\n" | NYASH_CLI_VERBOSE=0 ./target/release/nyash --backend vm apps/ny-echo/main.nyash
  • AOT/LLVM 系は後段当面OFF

  • JSON v0 ブリッジR1 Quick Start

    • パイプ実行Unix/WSL: printf '{"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Binary","op":"+","lhs":{"type":"Int","value":1},"rhs":{"type":"Binary","op":"*","lhs":{"type":"Int","value":2},"rhs":{"type":"Int","value":3}}}}]}' | ./target/release/nyash --ny-parser-pipe
    • ファイル指定Unix/WSL: ./target/release/nyash --json-file sample.json
    • スモークUnix/Windows: ./tools/ny_parser_bridge_smoke.sh / pwsh -File tools/ny_parser_bridge_smoke.ps1
  • E2E ラウンドトリップR2

    • Unix/WSL: ./tools/ny_roundtrip_smoke.sh
    • Windows: pwsh -File tools/ny_roundtrip_smoke.ps1
    • tmux通知で並列実行:
      • CODEX_ASYNC_DETACH=1 ./tools/codex-async-notify.sh "./tools/ny_roundtrip_smoke.sh" codex
      • CODEX_ASYNC_DETACH=1 ./tools/codex-async-notify.sh "pwsh -File tools/ny_roundtrip_smoke.ps1" codex
  • Ny プラグイン列挙R5

    • 有効化: --load-ny-plugins または NYASH_LOAD_NY_PLUGINS=1
    • nyash.toml 例:
      ny_plugins = [
        "apps/std/ny-config.nyash",
        "apps/plugins/my-helper.nyash"
      ]
      
    • 実行: 列挙に加え、Interpreterで順次実行ベストエフォート
    • ガード: NYASH_NY_PLUGINS_LIST_ONLY=1 で列挙のみ(実行しない)
    • 注意: プラグインスクリプトは副作用の少ない初期化/登録処理に限定推奨。
    • Std Ny スモーク実行(任意): NYASH_LOAD_NY_PLUGINS=1 ./tools/jit_smoke.sh

トレース/環境変数(抜粋)

  • AOT/Link: NYASH_LINKER, NYASH_LINK_FLAGS, NYASH_LINK_VERBOSE
  • ABI: NYASH_ABI_VTABLE=1, NYASH_ABI_STRICT=1
  • VM/JIT: NYASH_VM_PIC_STATS, NYASH_JIT_DUMP など従来通り

詳細な履歴や議事録は docs 配下の Phase 15 セクションを参照してください。

  • ny-configR4
  • ./target/release/nyash apps/std/ny-config.nyash
  • 現状: Interpreter 経路のプラグイン初期化順序により FileBox/TOMLBox を使うには Runner 側の微調整が必要VM 経路への移行 or プラグイン登録の早期化)。スクリプト本体は追加済み。
  • 直結ブリッジ v0R3 Quick Start
    • printf 'return (1+2)*3\n' > t.ny && NYASH_USE_NY_PARSER=1 NYASH_DUMP_JSON_IR=1 ./target/release/nyash t.ny

New Plan — SelfHost Dependency Tree (Nyonly) and Bridge20250907

目的

  • Ny スクリプトのみで依存木include + using/moduleを再帰解析して JSON を出力。Rust ビルド無しで回せる内側ループを整備。
  • 既存の MIR→VM→AOT 系とは疎結合を維持しつつ、最小の橋渡しJSONファイル経由を用意。

実装項目(最小)

  • ツール: apps/selfhost/tools/dep_tree_simple.nyash

    • 1ファイル・静的boxで実装。1行1文break無しelseは同一行。
    • 解析: include "..."using nsusing ns as Aliasusing "./path" as Name// @module ns=path
    • 解決順: module > 相対 > using-pathusing-path 既定: apps/selfhost:apps:lib:.)。
    • JSON: { version, root_path, tree{ path, includes[], uses[], modules[], children[] } }uses は unresolved/hint/alias/resolved を含む)。
  • タスク/Make:

    • nyash.toml [tasks].dep_tree を追加し、1コマンドで JSON を tmp/deps.json に出力。
    • make dep-tree: cargo build --release && ./target/release/nyash --run-task dep_tree
  • 受け入れ基準:

    • make dep-treetmp/deps.json を出力。曖昧複数ヒットは注記STRICT で停止。
    • VM/Interpreter いずれでも実行可File/Path/Array/Map 最小APIで実装

橋渡しStage 1: 疎結合)

  • NYASH_DEPS_JSON=<path> を Runner で読取りログ出力等の診断用途。MIR/JIT/AOT の挙動は不変。
  • 後続Stage 2以降は JSON IR extensions.deps や lock ファイルの導入を検討(別期)。

進め方(短期)

  1. dep_tree_simple.nyash の完走化VM実行での File/Path 最小APIのみ使用
  2. nyash.tomldep_tree 追加+ make dep-tree 整備。
  3. Runner へ NYASH_DEPS_JSON の最小読込み(ログ出力)を追加(影響ゼロの範囲)。