# Nyash VM 実行基盤ガイド（更新）

- プラグインBox引数の最小対応を追加（TLV: BoxRef）
- TLVタグ: 1=Bool, 2=I32, 3=I64, 4=F32, 5=F64, 6=String, 7=Bytes, 8=Handle(BoxRef)
  - BoxRefはプラグインBox参照（type_id:u32, instance_id:u32）を8バイトでエンコード
  - ユーザー定義/複雑なBoxは当面一部非対応（toStringフォールバック）。標準Boxはプラグイン経由で統一

現状のルーティング（Plugin-First）:
- User-defined: MIR関数（{Box}.{method}/{N}) にCall化（関数存在時）。それ以外はBoxCall。
- Plugin: BoxCall → PluginInvoke（method_idが解決可能）→ それ以外は名前解決で PluginHost.invoke_instance_method。

今後のタスク:
- VM側のfrom Parent.method対応（Builder/VM両対応）
- TLVの型拡張（Float/配列/BoxRef戻り値など）

## 🧮 VM実行統計（NYASH_VM_STATS / JSON）

VMは命令カウントと実行時間を出力できます。

使い方（CLIフラグ）:
```bash
# 人間向け表示
nyash --backend vm --vm-stats program.hako

# JSON出力
nyash --backend vm --vm-stats --vm-stats-json program.hako
```

環境変数（直接指定）:
```bash
NYASH_VM_STATS=1 ./target/debug/nyash --backend vm program.hako
NYASH_VM_STATS=1 NYASH_VM_STATS_JSON=1 ./target/debug/nyash --backend vm program.hako
# 代替: NYASH_VM_STATS_FORMAT=json
```

出力は `total`（総命令数）, `elapsed_ms`（経過時間）, `counts`（命令種別→回数）, `top20`（上位20種）を含みます。

## 既知の制約とTips（VM×プラグイン）
- Netプラグイン（HTTP）
  - unreachable（接続不可/タイムアウト）は `Result.Err(ErrorBox)`。
  - HTTP 404/500 は `Result.Ok(Response)`（アプリ側で `response.status` を確認）。
  - デバッグ: `NYASH_NET_LOG=1 NYASH_NET_LOG_FILE=net_plugin.log`。
- FileBox
  - `close()` は `Ok(Void)`。`match Ok(_)` で受けるか、戻り値を無視してよい。
- Handle（BoxRef）戻り
  - TLV tag=8（type_id:u32, instance_id:u32）。Loaderが返り値typeに対応する `fini_method_id` を設定し `PluginBoxV2` を構築。
  - `scope_tracker` がスコープ終了時に `fini()` を呼ぶ（メモリ安全）。
- 大きいボディ/多ヘッダー/タイムアウト
  - 逐次拡張中。異常時の挙動は上記Result規約に従う。実行ログと `--vm-stats` を併用して診断。
- 反復タイムアウト: `local_tests/socket_repeated_timeouts.hako` で `acceptTimeout/recvTimeout` の連続ケース確認
- BoxCallデバッグ: `NYASH_VM_DEBUG_BOXCALL=1` でBoxCallの受け手型・引数型・処理経路（enter/fastpath/unified）・結果型をstderr出力
  - 例: `NYASH_VM_DEBUG_BOXCALL=1 ./target/release/nyash --backend vm local_tests/test_vm_array_getset.hako`

## 🔧 BoxCallの統一経路（Phase 9.79b）

### method_id（スロット）によるBoxCall
- Builderが受け手型を推論できる場合、`BoxCall`に数値`method_id`（スロット）を付与。
- 低スロットはユニバーサル予約（0=toString, 1=type, 2=equals, 3=clone）。
- ユーザー定義Boxは宣言時にインスタンスメソッドへスロットを4番から順に予約（決定論的）。

### VMの実行経路（thunk + PIC）
- ユニバーサルスロット（0..3）はVMのfast-path thunkで即時処理。
  - toString/type/equals/cloneの4種は受け手`VMValue`から直接評価。
- それ以外は以下の順で処理:
  1. Mono-PIC（モノモーフィックPIC）直呼び: 受け手型×method（またはmethod_id）のキーでホットサイトを判定し、
     `InstanceBox`は関数名キャッシュを使って `{Class}.{method}/{arity}` を直接呼び出す（閾値=8）。
  2. 既存経路: `InstanceBox`はMIR関数へCall、それ以外は各Boxのメソッドディスパッチへフォールバック。

環境変数（デバッグ）:
```bash
NYASH_VM_DEBUG_BOXCALL=1   # BoxCallの入出力と処理経路を出力
NYASH_VM_PIC_DEBUG=1       # PICヒットのしきい値通過時にログ
```

今後の拡張:
- 一般`method_id`（ユーザー/プラグイン）に対するvtableスロット→thunk直呼び。
- PICのキャッシュ無効化（型version）と多相PICへの拡張（Phase 10）。
 - SocketBox（VM）
   - 基本API: `bind/listen/accept/connect/read/write/close/isServer/isConnected`
   - タイムアウト: `acceptTimeout(ms)` は接続なしで `void`、`recvTimeout(ms)` は空文字を返す
   - 簡易E2E: `local_tests/socket_timeout_server.hako` と `socket_timeout_client.hako`
 - Void 比較の扱い（VM）
   - `Void` は値を持たないため、`Eq/Ne` のみ有効。`Void == Void` は真、それ以外の型との `==` は偽（`!=` は真）。
   - 順序比較（`<, <=, >, >=`）は `TypeError`。

## E2E 実行例（HTTPのResult挙動）

代表ケースを `tools/run_vm_stats.sh` で実行できます。`--vm-stats-json` により命令プロファイルも取得可能です。

```bash
# 別ターミナルでサーバ起動
./target/release/nyash local_tests/http_server_statuses.hako

# クライアント（別ターミナル）
tools/run_vm_stats.sh local_tests/vm_stats_http_ok.hako vm_stats_ok.json
tools/run_vm_stats.sh local_tests/vm_stats_http_404.hako vm_stats_404.json
tools/run_vm_stats.sh local_tests/vm_stats_http_500.hako vm_stats_500.json

# 到達不能（サーバ不要）
tools/run_vm_stats.sh local_tests/vm_stats_http_err.hako vm_stats_err.json
```

期待されるResultモデル
- unreachable（接続不可/タイムアウト）: `Result.Err(ErrorBox)`
- 404/500 等のHTTPエラー: `Result.Ok(Response)`（アプリ側で `response.status` を評価）

詳細: `docs/reference/architecture/mir-to-vm-mapping.md` と `docs/guides/examples/http_result_patterns.md` を参照。
