# 機能設計書 21-変数管理

## 概要

本ドキュメントは、mrubyランタイムにおける変数管理機能の設計を記述する。インスタンス変数、クラス変数、グローバル変数、定数の4種類の変数に対するテーブル管理と参照・設定操作を提供する。

### 本機能の処理概要

mrubyの変数管理機能は、Rubyプログラムで使用される各種変数（インスタンス変数、クラス変数、グローバル変数、定数）のライフサイクル全体を管理する。内部的にはソート済み配列ベースのテーブル（iv_tbl）を使用し、ブランチフリー二分探索による高速なルックアップを実現している。

**業務上の目的・背景**：mrubyはRuby言語の変数スコープ（インスタンス変数 `@var`、クラス変数 `@@var`、グローバル変数 `$var`、定数 `CONST`）を忠実にサポートする必要がある。変数管理機能は、オブジェクト指向プログラミングの根幹であるオブジェクトの状態管理を実現し、仮想マシン（VM）のオペコード実行において変数の読み書きを効率的に行うために不可欠である。

**機能の利用シーン**：Rubyスクリプトでのインスタンス変数の読み書き、クラス定数の定義・参照、グローバル変数の設定、C APIからの変数操作（mrb_iv_get/mrb_iv_setなど）、GCマーク処理時の変数テーブル走査など、mrubyランタイムのあらゆる場面で使用される。

**主要な処理内容**：
1. iv_tbl（インスタンス変数テーブル）の生成・破棄・コピー
2. ブランチフリー二分探索によるキー（mrb_sym）の高速検索
3. インスタンス変数の取得（iv_get）・設定（iv_put）・削除（iv_del）
4. クラス変数のスーパークラスチェーンを辿る検索・設定
5. 定数の検索（const_missing フック付き）・定義・削除
6. グローバル変数の管理（mrb->globals テーブル）
7. GCとの連携（マーク処理、ライトバリア）

**関連システム・外部連携**：ガベージコレクション（GC）機能と密接に連携し、変数テーブル内のオブジェクト参照をマーク・解放する。仮想マシン（VM）のオペコード（GETIV, SETIV, GETCV, SETCV, GETCONST, SETCONST, GETGV, SETGVなど）から直接呼び出される。

**権限による制御**：frozen（凍結）されたオブジェクトに対するインスタンス変数の設定は `mrb_check_frozen` により拒否される。クラス変数の設定時もfrozenチェックが行われる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はCLIツールおよびランタイムAPI経由で使用され、画面は関連しない |

## 機能種別

データ管理（変数テーブルのCRUD操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| mrb | mrb_state* | Yes | mrubyインタプリタ状態 | NULLでないこと |
| obj | mrb_value / struct RObject* | Yes | 変数を保持するオブジェクト | obj_iv_p()で変数保持可能な型であること |
| sym | mrb_sym | Yes | 変数名を表すシンボル | インスタンス変数は@で始まること（mrb_iv_name_sym_p） |
| v | mrb_value | 設定時Yes | 設定する値 | - |

### 入力データソース

- VM実行時のオペコードからのシンボルID
- C APIからの直接呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 変数値 | mrb_value | 取得した変数の値（未定義時はmrb_nil_value()） |
| 定義有無 | mrb_bool | 変数が定義されているか否か |
| 変数一覧 | mrb_value(Array) | instance_variables, class_variables, global_variables等の一覧 |

### 出力先

呼び出し元（VM、C API）への戻り値として返却

## 処理フロー

### 処理シーケンス

```
1. インスタンス変数の取得（mrb_iv_get）
   └─ obj_iv_p()で変数保持可能か判定
      └─ iv_get()でブランチフリー二分探索
         └─ 見つかれば値を返却、なければnil
2. インスタンス変数の設定（mrb_iv_set）
   └─ obj_iv_p()で変数保持可能か判定（不可ならE_ARGUMENT_ERROR）
      └─ mrb_check_frozen()でfrozenチェック
         └─ iv_put()でソート済み配列に挿入/更新
            └─ mrb_field_write_barrier_value()でGC通知
3. クラス変数の取得（mrb_cv_get）
   └─ スーパークラスチェーンを辿って検索
      └─ 見つからなければE_NAME_ERROR
4. 定数の取得（mrb_const_get）
   └─ mod_const_check()で型チェック
      └─ const_get()でスーパークラスチェーン検索
         └─ 見つからなければconst_missing呼び出し
5. グローバル変数の取得/設定
   └─ mrb->globalsテーブルに対してiv_get/iv_put
```

### フローチャート

```mermaid
flowchart TD
    A[変数操作要求] --> B{変数の種類}
    B -->|インスタンス変数| C{obj_iv_p?}
    C -->|Yes| D{操作種別}
    C -->|No| E[E_ARGUMENT_ERROR]
    D -->|get| F[iv_get: 二分探索]
    D -->|set| G[frozen チェック]
    G --> H[iv_put: ソート済み挿入]
    H --> I[ライトバリア通知]
    B -->|クラス変数| J[スーパークラスチェーン検索]
    B -->|定数| K[const_get_nohook]
    K --> L{見つかった?}
    L -->|Yes| M[値を返却]
    L -->|No| N[const_missing呼び出し]
    B -->|グローバル変数| O[mrb->globalsテーブル操作]
    F --> M
    J --> M
    O --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | Frozen制約 | frozenオブジェクトへの変数設定は禁止 | インスタンス変数・クラス変数設定時 |
| BR-02 | IV名バリデーション | インスタンス変数名は@で始まり2文字以上 | mrb_iv_name_sym_check呼び出し時 |
| BR-03 | CV継承チェーン | クラス変数はスーパークラスチェーンを遡って検索 | クラス変数取得・定義判定時 |
| BR-04 | 定数名規約 | 定数名は大文字で始まる | 定数一覧取得時のフィルタリング |
| BR-05 | const_missingフック | 定数が見つからない場合const_missingを呼び出す | 定数取得時 |
| BR-06 | クラス名自動設定 | 名前空間に定数としてクラスを設定すると__classname__が自動設定される | assign_class_name |

### 計算ロジック

- 二分探索インデックス計算: `iv_bsearch_idx()` はブランチフリー（CMOV使用）で O(log n) の探索を行う
- テーブル拡張: 容量が不足した場合、alloc を2倍に拡張（初期値 IV_INITIAL_SIZE = 2）

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

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

本機能はデータベースを使用しない。インメモリのiv_tblデータ構造で変数を管理する。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 変数取得 | iv_tbl | SELECT相当 | 二分探索によるキー検索 |
| 変数設定 | iv_tbl | INSERT/UPDATE相当 | ソート済み配列への挿入または更新 |
| 変数削除 | iv_tbl | DELETE相当 | 要素のシフトによる削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E_ARGUMENT_ERROR | 引数エラー | 変数保持不可能な型に対するiv_set | 適切な型のオブジェクトを使用 |
| E_NAME_ERROR | 名前エラー | 不正なインスタンス変数名 | 正しい変数名規約に従う |
| E_NAME_ERROR | 名前エラー | 未初期化のクラス変数参照 | 事前に初期化する |
| E_TYPE_ERROR | 型エラー | クラス/モジュール以外での定数操作 | クラスまたはモジュールを使用 |
| FrozenError | 凍結エラー | frozenオブジェクトへの変数設定 | freezeしないか、dupして変更 |

### リトライ仕様

リトライは不要。エラー時は例外が発生する。

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

トランザクション機構は存在しない。変数の設定は即時反映される。

## パフォーマンス要件

- iv_tblはソート済み配列で管理し、ブランチフリー二分探索により O(log n) の検索性能を実現
- メモリプリフェッチ（MRB_MEM_PREFETCH）によるキャッシュ効率の最適化
- テーブル拡張は倍増方式（amortized O(1)）

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

- frozenオブジェクトに対する変更操作は全て拒否される
- グローバル変数テーブルはmrb_state単位で管理され、インタプリタ間の分離が保証される

## 備考

- iv_tblのメモリレイアウト: `ptr`の前半が値配列（mrb_value[]）、後半がキー配列（mrb_sym[]）として使用される
- ICLASSの場合、iv_tblは実体クラス（c->c->iv）を参照する
- シングルトンクラス（SCLASS）の場合、クラス変数の検索はアタッチされたオブジェクトのクラスも探索する

---

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

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

### 推奨読解順序

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

まず、変数テーブルの内部構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | variable.h | `include/mruby/variable.h` | 公開API宣言（mrb_iv_get, mrb_gv_set等）とmrb_iv_foreach_func型定義 |
| 1-2 | variable.c | `src/variable.c` | iv_tbl構造体の定義（17-20行目）: size, alloc, ptr の3フィールド |

**読解のコツ**: iv_tblのメモリレイアウトは特殊で、`ptr`配列の前半（0〜alloc-1）にmrb_value、後半（allocオフセット以降）にmrb_symが格納される。`(mrb_sym*)&t->ptr[t->alloc]`でキー配列にアクセスしている点に注意。

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

公開API関数群がエントリーポイントとなる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | variable.c | `src/variable.c` | mrb_iv_get（358-365行目）: obj_iv_pで型チェック後、mrb_obj_iv_getを呼ぶ |
| 2-2 | variable.c | `src/variable.c` | mrb_iv_set（470-479行目）: obj_iv_pチェック、frozenチェック、iv_put |

**主要処理フロー**:
1. **358-365行目**: mrb_iv_get - インスタンス変数取得のラッパー
2. **470-479行目**: mrb_iv_set - インスタンス変数設定のラッパー
3. **764-768行目**: mrb_cv_get - クラス変数取得
4. **1001-1006行目**: mrb_const_get - 定数取得
5. **1213-1221行目**: mrb_gv_get - グローバル変数取得

#### Step 3: 内部テーブル操作を理解する

低レベルのテーブル操作関数群。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | variable.c | `src/variable.c` | iv_bsearch_idx（74-95行目）: ブランチフリー二分探索のアルゴリズム |
| 3-2 | variable.c | `src/variable.c` | iv_put（98-140行目）: ソート済み配列への挿入/更新 |
| 3-3 | variable.c | `src/variable.c` | iv_get（143-163行目）: 二分探索によるキー検索 |
| 3-4 | variable.c | `src/variable.c` | iv_del（166-192行目）: 要素削除とシフト |
| 3-5 | variable.c | `src/variable.c` | iv_rehash（42-71行目）: テーブル拡張処理 |

**主要処理フロー**:
- **74-95行目**: ブランチフリー二分探索 - CMOVによる条件分岐回避でCPUパイプラインを最適化
- **42-71行目**: リハッシュ - 容量を2倍に拡張し、キー配列を新しい位置に移動

#### Step 4: クラス変数・定数の継承チェーン検索

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | variable.c | `src/variable.c` | mrb_mod_cv_get（714-746行目）: スーパークラスチェーンを辿るCV検索 |
| 4-2 | variable.c | `src/variable.c` | const_get_nohook（933-956行目）: 定数のスーパークラスチェーン検索 |
| 4-3 | variable.c | `src/variable.c` | const_get（958-973行目）: const_missingフック付き定数検索 |

#### Step 5: GC連携

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | variable.c | `src/variable.c` | mrb_gc_mark_gv（255-259行目）: グローバル変数テーブルのGCマーク |
| 5-2 | variable.c | `src/variable.c` | mrb_gc_mark_iv（271-275行目）: オブジェクトのIVテーブルのGCマーク |
| 5-3 | variable.c | `src/variable.c` | mrb_gc_free_iv（277-283行目）: IVテーブルのGC解放 |

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

```
mrb_iv_get (公開API)
    │
    ├─ obj_iv_p (型判定)
    │
    └─ mrb_obj_iv_get
           └─ iv_get
                  └─ iv_bsearch_idx (ブランチフリー二分探索)

mrb_iv_set (公開API)
    │
    ├─ obj_iv_p (型判定)
    │
    └─ mrb_obj_iv_set
           ├─ mrb_check_frozen
           └─ mrb_obj_iv_set_force
                  ├─ assign_class_name (名前空間処理)
                  ├─ iv_new (テーブル初期化)
                  ├─ iv_put
                  │     ├─ iv_rehash (テーブル拡張)
                  │     └─ iv_bsearch_idx
                  └─ mrb_field_write_barrier_value (GC通知)

mrb_const_get (公開API)
    │
    ├─ mod_const_check (型チェック)
    │
    └─ const_get
           ├─ const_get_nohook (スーパークラスチェーン検索)
           │     └─ iv_get
           └─ const_missing (フック呼び出し)
```

### データフロー図

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

mrb_sym (変数名)    ───▶  iv_bsearch_idx()     ───▶  インデックス
                           │
mrb_value (設定値)  ───▶  iv_put()              ───▶  iv_tbl更新
                           │
struct RObject*     ───▶  iv_get()              ───▶  mrb_value (変数値)
                           │
struct RClass*      ───▶  スーパークラスチェーン  ───▶  クラス変数/定数値
                           検索
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| variable.c | `src/variable.c` | ソース | 変数管理機能の実装本体 |
| variable.h | `include/mruby/variable.h` | ヘッダ | 変数管理の公開API宣言 |
| mruby.h | `include/mruby.h` | ヘッダ | mrb_state, mrb_value等の基本型定義 |
| class.h | `include/mruby/class.h` | ヘッダ | struct RClass定義（ivフィールド含む） |
| gc.c | `src/gc.c` | ソース | GCマーク・解放処理からの呼び出し元 |
| vm.c | `src/vm.c` | ソース | GETIV/SETIV等のオペコード実装（変数操作の呼び出し元） |
| presym.h | `include/mruby/presym.h` | ヘッダ | MRB_SYM()マクロによるプリシンボル定義 |
