# 機能設計書 8-仮想マシン（VM）

## 概要

本ドキュメントは、Nimコンパイラの仮想マシン（VM）の機能設計について記載する。VMはコンパイル時評価エンジンとして、定数式やマクロの実行を担当する。

### 本機能の処理概要

Nim VMは、コンパイル時に実行が必要なコード（定数式、static文、マクロ、テンプレート展開）を評価するレジスタベースの仮想マシンである。1-3個のint32で構成される命令を解釈実行する。

**業務上の目的・背景**：Nimはコンパイル時メタプログラミングを強力にサポートしており、マクロやstatic式の評価、定数畳み込みなどをVMで実行する。これにより、実行時ではなくコンパイル時に計算を行い、効率的なコード生成が可能になる。

**機能の利用シーン**：
- `const`式の評価
- `static`ブロック/式の評価
- マクロの実行
- テンプレートの展開
- REPL（対話型評価）

**主要な処理内容**：
1. コード生成（vmgen.nim）
2. 命令のデコード
3. レジスタ操作
4. 例外処理
5. スタックフレーム管理
6. 型変換
7. 外部関数呼び出し（FFI）

**関連システム・外部連携**：
- vmgen.nim（コード生成）
- vmdef.nim（型定義）
- vmhooks.nim（フック関数）
- evalffi.nim（FFI対応）
- semmacrosanity.nim（マクロ健全性チェック）

**権限による制御**：TSandboxFlagsによるサンドボックス制御（cast許可、無限ループ許可等）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | コマンドラインインターフェース | 参照画面 | エラーメッセージ、スタックトレース表示 |

## 機能種別

コード実行処理 / コンパイル時評価処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| c | PCtx | Yes | VMコンテキスト | 非nil |
| s | PSym | Yes | 実行するシンボル | 非nil |
| n | PNode | Yes | 評価するAST | 非nil |

### 入力データソース

- 型付きAST（PNode）
- シンボル情報（PSym）
- 型情報（PType）
- コンパイラ設定（ConfigRef）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 評価結果 | PNode | コンパイル時計算結果のAST |
| 例外 | PNode | 発生した例外のAST |

### 出力先

- 評価結果はASTノードとして返される
- エラーメッセージはコンパイラのメッセージシステムへ

## 処理フロー

### 処理シーケンス

```
1. コード生成（compile）
   └─ vmgen.genProcでバイトコード生成
2. スタックフレーム作成（TStackFrame）
   └─ レジスタ配列の初期化
3. 命令フェッチ/デコード
   └─ TInstrからopcode/ra/rb/rc/rbx取得
4. 命令実行
   ├─ 算術演算（opcAddInt等）
   ├─ メモリアクセス（opcLdArr等）
   ├─ 制御フロー（opcJmp等）
   └─ 関数呼び出し（opcIndCall等）
5. 例外処理
   └─ findExceptionHandlerで適切なハンドラ検索
6. 結果返却
   └─ レジスタからPNodeに変換
```

### フローチャート

```mermaid
flowchart TD
    A[compile: コード生成] --> B[スタックフレーム作成]
    B --> C[命令フェッチ]
    C --> D[命令デコード]
    D --> E{opcode判定}
    E -->|算術| F[算術演算実行]
    E -->|メモリ| G[メモリアクセス]
    E -->|ジャンプ| H[PC更新]
    E -->|呼び出し| I[関数呼び出し]
    E -->|例外| J[例外処理]
    F --> K{終了?}
    G --> K
    H --> K
    I --> K
    J --> K
    K -->|No| C
    K -->|Yes| L[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | レジスタベース | TFullRegで値を管理 | 全ての値操作 |
| BR-02 | 6種類のレジスタ | rkNone/rkInt/rkFloat/rkNode/rkRegisterAddr/rkNodeAddr | 値の種類に応じて |
| BR-03 | ループ制限 | maxLoopIterationsVMで無限ループ防止 | whileループ |
| BR-04 | サンドボックス | TSandboxFlagsで危険な機能を制御 | cast/無限ループ等 |
| BR-05 | 例外チェーン | safePointsで例外ハンドラを管理 | 例外発生時 |

### 計算ロジック

- **命令エンコード**: regO(8bit) + regA(16bit) + regB(16bit) + regC(16bit) = 56bit in uint64
- **即値**: excess-K形式（byteExcess=128）
- **拡張即値**: wordExcess = 2^23

## データベース操作仕様

該当なし（VMはデータベースを使用しない）

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| N/A | N/A | N/A | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| errTooManyIterations | 実行時エラー | ループ回数超過 | ループ回数制限確認 |
| errGenerated | 内部エラー | 予期しない状態 | バグ報告 |
| unhandled exception | 例外 | 未捕捉例外 | try/exceptで捕捉 |

### リトライ仕様

VMはリトライを行わない。

## トランザクション仕様

該当なし

## パフォーマンス要件

- レジスタベースVMによる効率的な命令実行
- computedGotoによる高速ディスパッチ（対応環境のみ）
- プロファイラ対応（vmprofiler.nim）

## セキュリティ考慮事項

- TSandboxFlagsによるサンドボックス制御
- 無限ループ/再帰の検出と防止
- castの制限（allowCastフラグ）

## 備考

- vmhooks.nimをinclude
- FFI対応（hasFFIフラグ）
- REPLモード対応（emRepl）
- プロファイリング対応

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する（vmdef.nim）

まず、VMで使用されるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | vmdef.nim | `compiler/vmdef.nim` 17-45行目 | 命令フォーマットの定義を理解 |
| 1-2 | vmdef.nim | `compiler/vmdef.nim` 52-187行目 | TOpcode（オペコード一覧）を理解 |
| 1-3 | vmdef.nim | `compiler/vmdef.nim` 221-231行目 | TFullReg（レジスタ型）を理解 |
| 1-4 | vmdef.nim | `compiler/vmdef.nim` 251-281行目 | TCtx（VMコンテキスト）を理解 |

**読解のコツ**:
- **17行目**: `TInstrType = uint64`で命令は64ビット整数
- **19-24行目**: レジスタフィールドのビット幅定義
  - regO: 8bit（オペコード）
  - regA: 16bit（デスティネーション）
  - regB/C: 各16bit（オペランド）
  - regBx: 24bit（拡張即値）
- **221-222行目**: `TRegisterKind`で6種類のレジスタ種別
  - rkNone: 未使用
  - rkNode: ASTノード
  - rkInt: 整数
  - rkFloat: 浮動小数点
  - rkRegisterAddr: レジスタアドレス
  - rkNodeAddr: ノードアドレス
- **223-231行目**: `TFullReg`はcase objectで種別に応じた値を保持

#### Step 2: オペコードを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | vmdef.nim | `compiler/vmdef.nim` 52-109行目 | 基本オペコード（算術、メモリ、制御） |
| 2-2 | vmdef.nim | `compiler/vmdef.nim` 110-187行目 | 拡張オペコード（AST操作、システム） |

**主要オペコード**:
- **53-54行目**: opcEof、opcRet（終了、リターン）
- **58-69行目**: 代入系（opcAsgnInt、opcAsgnFloat、opcAsgnRef等）
- **71-84行目**: メモリアクセス（opcLdArr、opcWrArr、opcLdObj等）
- **86-109行目**: 算術・論理演算
- **161-169行目**: 制御フロー（opcTJmp、opcFJmp、opcJmp、opcTry等）

#### Step 3: VMコンテキストを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | vmdef.nim | `compiler/vmdef.nim` 251-281行目 | TCtx構造体 |
| 3-2 | vmdef.nim | `compiler/vmdef.nim` 283-291行目 | TStackFrame構造体 |

**主要処理フロー**:
- **252-254行目**: code（命令配列）、debug（行情報）
- **255-258行目**: globals、constants（グローバル/定数）、types
- **259-260行目**: 例外情報
- **264-265行目**: mode（評価モード）、features（サンドボックス）
- **267行目**: loopIterations（ループカウンタ）
- **284-291行目**: TStackFrameでスタックフレーム管理

#### Step 4: 命令デコードマクロを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | vm.nim | `compiler/vm.nim` 93-127行目 | デコードマクロ/テンプレート |

**主要処理フロー**:
- **93-95行目**: `ensureKind`でレジスタ種別を確保
- **100-107行目**: `decodeB`、`decodeBC`でレジスタBとCをデコード
- **113-116行目**: `decodeBImm`で即値をデコード（excess-K形式）
- **118-120行目**: `decodeBx`で拡張即値をデコード

#### Step 5: 例外処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | vm.nim | `compiler/vm.nim` 289-293行目 | ExceptionGoto列挙型 |
| 5-2 | vm.nim | `compiler/vm.nim` 295-364行目 | findExceptionHandler関数 |

**主要処理フロー**:
- **290-293行目**: `ExceptionGoto`の3種類
  - ExceptionGotoHandler: ハンドラへジャンプ
  - ExceptionGotoFinally: finallyへジャンプ
  - ExceptionGotoUnhandled: 未処理
- **295-364行目**: `findExceptionHandler`でsafePointsを走査
  - opcExceptチェーンを辿る
  - 型マッチングでハンドラ決定
  - opcFinallyブロック処理

#### Step 6: スタックトレースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | vm.nim | `compiler/vm.nim` 35-65行目 | stackTraceAux関数 |
| 6-2 | vm.nim | `compiler/vm.nim` 67-83行目 | stackTraceImpl関数とテンプレート |

**主要処理フロー**:
- **35-65行目**: `stackTraceAux`でスタックフレームを再帰的に出力
- **46行目**: c.debug[pc]から行情報取得
- **62-64行目**: プロシージャ名を出力
- **80-83行目**: `stackTrace`テンプレートでスタックトレース出力後return

#### Step 7: 型変換を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 7-1 | vm.nim | `compiler/vm.nim` 383-481行目 | opConv関数 |

**主要処理フロー**:
- **385-427行目**: 文字列への変換（enum、int、float、bool等）
- **429-481行目**: 数値間の変換（int、uint、float、bool）
- **475-479行目**: オブジェクト変換（基本的にno-op）

### プログラム呼び出し階層図

```
rawExecute (メイン実行ループ)
    │
    ├─ 命令フェッチ (c.code[pc])
    │
    ├─ opcodeによる分岐
    │      │
    │      ├─ 算術演算
    │      │      ├─ opcAddInt
    │      │      ├─ opcSubInt
    │      │      ├─ opcMulInt
    │      │      └─ opcDivInt
    │      │
    │      ├─ メモリアクセス
    │      │      ├─ opcLdArr
    │      │      ├─ opcWrArr
    │      │      ├─ opcLdObj
    │      │      └─ opcWrObj
    │      │
    │      ├─ 制御フロー
    │      │      ├─ opcJmp
    │      │      ├─ opcTJmp/opcFJmp
    │      │      └─ opcRet
    │      │
    │      ├─ 関数呼び出し
    │      │      ├─ opcIndCall
    │      │      └─ opcIndCallAsgn
    │      │
    │      └─ 例外処理
    │             ├─ opcRaise
    │             ├─ opcTry
    │             ├─ opcExcept
    │             └─ opcFinally
    │
    ├─ findExceptionHandler (例外時)
    │
    └─ stackTraceAux (エラー時)
```

### データフロー図

```
[入力]                          [処理]                              [出力]

型付きAST ────────────────────▶ vmgen.genProc ───────────────────▶ バイトコード
(PNode)                          (コード生成)                         (TInstr[])
       │
       ▼
バイトコード ─────────────────▶ rawExecute ──────────────────────▶ 評価結果
(TInstr[])                       (命令実行)                          (TFullReg)
       │
       ▼
レジスタ ─────────────────────▶ regToNode ───────────────────────▶ 結果AST
(TFullReg)                       (変換)                              (PNode)
       │
       ▼
例外情報 ─────────────────────▶ findExceptionHandler ────────────▶ ハンドラPC
(PNode)                          (ハンドラ検索)
       │
       ▼
スタックフレーム ─────────────▶ stackTraceAux ───────────────────▶ トレース出力
(TStackFrame)                    (トレース生成)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| vm.nim | `compiler/vm.nim` | ソース | VM実行エンジンメイン |
| vmdef.nim | `compiler/vmdef.nim` | ソース | VM型定義 |
| vmgen.nim | `compiler/vmgen.nim` | ソース | VMコード生成 |
| vmhooks.nim | `compiler/vmhooks.nim` | ソース | VMフック関数（includeされる） |
| vmdeps.nim | `compiler/vmdeps.nim` | ソース | VM依存関係 |
| evalffi.nim | `compiler/evalffi.nim` | ソース | FFI評価（オプション） |
| vmprofiler.nim | `compiler/vmprofiler.nim` | ソース | VMプロファイラ |
| semmacrosanity.nim | `compiler/semmacrosanity.nim` | ソース | マクロ健全性チェック |
| nimsets.nim | `compiler/nimsets.nim` | ソース | 集合操作 |

