# 機能設計書 34-vm

## 概要

本ドキュメントは、Node.js の `vm` モジュール（JavaScript仮想マシン・サンドボックス実行）の機能設計書である。このモジュールは、V8仮想マシンのコンテキストを利用して、JavaScriptコードを分離された環境で実行する機能を提供する。

### 本機能の処理概要

vm モジュールは、JavaScriptコードをコンパイル・実行するためのAPIを提供する。異なるV8コンテキストでコードを実行することで、グローバルスコープを分離し、サンドボックス環境でのコード実行を可能にする。スクリプトのプリコンパイルやキャッシュ、動的なモジュールインポートにも対応している。

**業務上の目的・背景**：信頼できないコードを安全に実行したり、テンプレートエンジンでユーザー定義のコードを評価したり、REPL環境を構築するなど、分離された環境でのJavaScript実行が必要な場面は多い。vm モジュールはこれらのユースケースに対応する。

**機能の利用シーン**：
- REPLの実装（ユーザー入力コードの評価）
- テンプレートエンジン（EJS等）でのコード評価
- サンドボックステスト環境の構築
- 動的コード生成・実行
- プリコンパイルによる起動高速化

**主要な処理内容**：
1. Scriptクラスによるコードのコンパイルと実行
2. コンテキストの作成・管理（`createContext()`）
3. 各種実行環境での実行（`runInThisContext()` / `runInContext()` / `runInNewContext()`）
4. 関数のコンパイル（`compileFunction()`）
5. メモリ使用量の計測（`measureMemory()`）

**関連システム・外部連携**：
- V8 JavaScript エンジン
- Node.js の `inspector` モジュール（デバッグ時）

**権限による制御**：特段の権限制御は存在しない。ただし、vm はセキュリティ境界を提供しないことに注意。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | System Analyzer | 補助機能 | V8コンテキストの分析 |
| 3 | Profview (Tick Processor) | 補助機能 | スクリプト実行のプロファイリング |
| 4 | Turbolizer | 補助機能 | コンパイル最適化の可視化 |

## 機能種別

コード実行 / サンドボックス / コンパイル

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| code | string | Yes | 実行するJavaScriptコード | 文字列であること |
| contextObject | object | No | コンテキストに含めるオブジェクト | オブジェクトであること |
| options.filename | string | No | スタックトレース用ファイル名 | 文字列であること |
| options.lineOffset | number | No | 行番号オフセット | 整数であること |
| options.columnOffset | number | No | 列番号オフセット | 整数であること |
| options.timeout | number | No | 実行タイムアウト（ミリ秒） | 正の整数 |
| options.cachedData | Buffer | No | プリコンパイルされたキャッシュデータ | Buffer であること |
| options.produceCachedData | boolean | No | キャッシュデータを生成するか | 真偽値であること |

### 入力データソース

- アプリケーションコードからの文字列
- ファイルから読み込んだコード
- ネットワーク経由で受信したコード（注意が必要）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | any | スクリプト実行結果 |
| script.cachedData | Buffer | コンパイル済みキャッシュデータ |
| script.cachedDataProduced | boolean | キャッシュデータが生成されたか |

### 出力先

- スクリプト実行結果としての戻り値
- コンテキストオブジェクトへの副作用

## 処理フロー

### 処理シーケンス

```
1. スクリプト作成
   └─ new Script(code, options) でコードをコンパイル
2. コンテキスト作成（オプション）
   └─ createContext(sandbox) でV8コンテキストを作成
3. スクリプト実行
   └─ script.runInContext(context) でコードを実行
4. 結果取得
   └─ 実行結果とコンテキストの変更を取得
```

### フローチャート

```mermaid
flowchart TD
    A[コード入力] --> B[new Script/code, options]
    B --> C{コンテキスト指定?}
    C -->|runInThisContext| D[現在のコンテキストで実行]
    C -->|runInContext| E[指定コンテキストで実行]
    C -->|runInNewContext| F[新規コンテキスト作成]
    F --> G[createContext/sandbox]
    G --> E
    D --> H{タイムアウト?}
    E --> H
    H -->|Yes| I[タイムアウトエラー]
    H -->|No| J[実行結果返却]
    I --> K[エラー処理]
    J --> L[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | コンテキスト分離 | 別コンテキストでは異なるグローバルオブジェクトを持つ | createContext使用時 |
| BR-02 | タイムアウト制御 | timeout指定時、超過するとエラー発生 | timeout オプション指定時 |
| BR-03 | キャッシュ互換性 | cachedDataは同一V8バージョンでのみ有効 | cachedData 使用時 |
| BR-04 | SIGINT割り込み | breakOnSigint有効時、Ctrl+Cで実行中断可能 | breakOnSigint:true |

### 計算ロジック

特段の複雑な計算ロジックはなし。

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

該当なし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR_INVALID_ARG_TYPE | TypeError | 引数の型が不正 | 正しい型を渡す |
| SyntaxError | SyntaxError | JavaScriptコードの構文エラー | コードを修正 |
| ERR_CONTEXT_NOT_INITIALIZED | Error | コンテキスト未初期化でmeasureMemory実行 | コンテキストを初期化 |
| Script execution timed out | Error | タイムアウト超過 | timeout値を増やすか処理を最適化 |

### リトライ仕様

リトライは行わない。

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

該当なし

## パフォーマンス要件

- cachedData を使用することで再コンパイルを回避し高速化可能
- タイムアウトを適切に設定して無限ループを防止

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

- **重要**: vm モジュールはセキュリティメカニズムではない
- 信頼できないコードの実行には適さない
- サンドボックスからのエスケープが可能な脆弱性が存在する可能性あり
- 完全なサンドボックスが必要な場合は別プロセスまたはvm2等の外部ライブラリを検討

## 備考

- `--experimental-vm-modules` フラグでESMサポートが利用可能
- `constants.USE_MAIN_CONTEXT_DEFAULT_LOADER` でメインコンテキストのローダーを使用可能
- `constants.DONT_CONTEXTIFY` でコンテキスト化なしの実行が可能

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、vm モジュールの主要クラスと定数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | vm.js | `lib/vm.js` | モジュール全体の構造 |

**読解のコツ**: `Script` クラスは `ContextifyScript` を継承しており、V8のネイティブ機能にアクセスしている。

#### Step 2: エントリーポイントを理解する

モジュールのエクスポートと主要クラスを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | vm.js | `lib/vm.js` | module.exports（404-415行目） |
| 2-2 | vm.js | `lib/vm.js` | Script クラス（84-156行目） |
| 2-3 | vm.js | `lib/vm.js` | createContext 関数（225-266行目） |

**主要処理フロー**:
1. **33-37行目**: internalBinding('contextify') からネイティブ機能をインポート
2. **84-130行目**: Script クラスのコンストラクタ - コードのコンパイル
3. **132-155行目**: runInThisContext / runInContext / runInNewContext
4. **225-266行目**: createContext - V8コンテキストの作成

#### Step 3: Script クラスの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | vm.js | `lib/vm.js` | Script コンストラクタ（84-130行目） |
| 3-2 | vm.js | `lib/vm.js` | runInThisContext（132-138行目） |
| 3-3 | vm.js | `lib/vm.js` | runInContext（140-150行目） |
| 3-4 | vm.js | `lib/vm.js` | runInNewContext（152-155行目） |

**主要処理フロー**:
- **85-91行目**: オプション処理とデフォルト値設定
- **103-109行目**: cachedDataのバリデーション
- **117-127行目**: ネイティブScriptの作成（super()呼び出し）
- **132-138行目**: runInThisContext - 現在コンテキストでの実行
- **140-150行目**: runInContext - 指定コンテキストでの実行

#### Step 4: コンテキスト管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | vm.js | `lib/vm.js` | createContext（225-266行目） |
| 4-2 | vm.js | `lib/vm.js` | isContext（78-82行目） |
| 4-3 | vm.js | `lib/vm.js` | validateContext（158-163行目） |

**主要処理フロー**:
- **78-82行目**: isContext - オブジェクトがコンテキストか判定
- **225-266行目**: createContext - V8コンテキストの作成と設定
- **232-238行目**: オプションの解析（name、origin、codeGeneration）
- **262行目**: makeContext() の呼び出し（ネイティブ関数）

#### Step 5: 高度な機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | vm.js | `lib/vm.js` | compileFunction（320-370行目） |
| 5-2 | vm.js | `lib/vm.js` | measureMemory（382-394行目） |
| 5-3 | vm.js | `lib/vm.js` | vmConstants（396-402行目） |

**主要処理フロー**:
- **320-370行目**: compileFunction - 関数のコンパイル
- **382-394行目**: measureMemory - メモリ使用量計測（実験的）
- **396-402行目**: 定数定義（USE_MAIN_CONTEXT_DEFAULT_LOADER、DONT_CONTEXTIFY）

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

```
new Script(code, options)
    │
    ├─ validateString(code)
    ├─ validateObject(options)
    ├─ getHostDefinedOptionId(importModuleDynamically, filename)
    │
    └─ super(code, filename, lineOffset, columnOffset, ...)
           └─ ContextifyScript（ネイティブ）
                  └─ V8 ScriptCompiler::Compile()

script.runInContext(context, options)
    │
    ├─ validateContext(context)
    ├─ getRunInContextArgs(context, options)
    │      └─ timeout, displayErrors, breakOnSigint の解析
    │
    └─ super.runInContext(args)
           └─ V8 Script::Run()

createContext(sandbox, options)
    │
    ├─ isContext(sandbox) チェック
    ├─ validateObject(options)
    ├─ getHostDefinedOptionId(importModuleDynamically, name)
    │
    └─ makeContext(sandbox, name, origin, strings, wasm, ...)
           └─ V8 Context::New()
```

### データフロー図

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

code (string) ─────────▶ V8 ScriptCompiler ─────────▶ Script インスタンス
      │
      ▼
options ───────────────▶ Script コンストラクタ ────────▶ cachedData (optional)
      │
      ▼
context ───────────────▶ runInContext() ───────────────▶ 実行結果
                               │
                               ▼
                        コンテキストオブジェクト
                        への副作用（グローバル変数等）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| vm.js | `lib/vm.js` | ソース | メインモジュール実装 |
| internal/vm.js | `lib/internal/vm.js` | ソース | 内部ヘルパー関数 |
| validators.js | `lib/internal/validators.js` | ソース | 入力バリデーション |
| errors.js | `lib/internal/errors.js` | ソース | エラーコード定義 |
| contextify | `src/node_contextify.cc` | C++ | V8コンテキスト操作のネイティブ実装 |
