# 機能設計書 7-irep管理

## 概要

本ドキュメントは、mrubyの命令列（irep: instruction representation）管理機能の設計を記述する。irepの参照カウント管理・解放・追加を行う。

### 本機能の処理概要

irep管理は、コンパイルされたmrubyバイトコードの内部表現であるirep構造体のライフサイクルを管理する。参照カウント方式でirepの共有と解放を制御し、不要になったirepのメモリを回収する。

**業務上の目的・背景**：mrubyではコンパイルされたコードがirep構造体で表現される。同一のirepが複数のProcから参照される場合があるため、参照カウントによるライフサイクル管理が必要である。また、irepは階層構造（サブirep）を持つため、再帰的な解放処理が必要となる。

**機能の利用シーン**：バイナリロード時のirep生成、メソッド定義時のirep参照、GCによるProc回収時のirep解放、irep参照カウントのオーバーフロー防止。

**主要な処理内容**：
1. `mrb_add_irep()` - 新規irepの生成（refcnt=1）
2. `mrb_irep_incref()` - 参照カウントの増加
3. `mrb_irep_decref()` - 参照カウントの減少（0になったら解放）
4. `mrb_irep_cutref()` - サブirepの参照切断
5. `mrb_irep_free()` - irepとその全リソースの解放

**関連システム・外部連携**：バイナリローダ（load.c）、コンパイラ、GC、VM。

**権限による制御**：なし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングにデータなし |

## 機能種別

リソース管理処理（参照カウント方式）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| mrb | mrb_state* | Yes | mrubyインタプリタ状態 | NULLでないこと |
| irep | mrb_irep* | Yes | 操作対象irep | NULLでないこと |

### 入力データソース

コンパイラまたはバイナリローダが生成したirep。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| irep | mrb_irep* | mrb_add_irepの戻り値（新規irep） |

### 出力先

呼び出し元への戻り値、またはメモリ解放。

## 処理フロー

### 処理シーケンス

```
1. mrb_add_irep()
   └─ mrb_irep構造体をmalloc、ゼロ初期化、refcnt=1
2. mrb_irep_incref(irep)
   ├─ MRB_IREP_NO_FREEフラグ時: 何もしない
   ├─ refcnt == UINT16_MAX時: GC実行→再チェック→RuntimeError
   └─ refcnt++
3. mrb_irep_decref(irep)
   ├─ MRB_IREP_NO_FREEフラグ時: 何もしない
   ├─ refcnt--
   └─ refcnt == 0 時: mrb_irep_free()
4. mrb_irep_cutref(irep)
   └─ 全サブirep（reps[]）の参照をNULL化し、decref
5. mrb_irep_free(irep)
   ├─ iseq解放（MRB_ISEQ_NO_FREE未設定時）
   ├─ pool[]解放（文字列・BigInt型のデータ含む）
   ├─ syms解放
   ├─ reps[]の各サブirepをdecref後解放
   ├─ lv解放
   ├─ debug_info解放
   └─ irep構造体自体を解放
```

### フローチャート

```mermaid
flowchart TD
    A[mrb_irep_decref] --> B{NO_FREEフラグ?}
    B -->|Yes| C[何もしない]
    B -->|No| D[refcnt--]
    D --> E{refcnt == 0?}
    E -->|No| F[終了]
    E -->|Yes| G[mrb_irep_free]
    G --> H[iseq解放]
    G --> I[pool解放]
    G --> J[syms解放]
    G --> K[reps再帰decref]
    G --> L[lv解放]
    G --> M[debug_info解放]
    G --> N[irep構造体解放]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 参照カウント上限 | UINT16_MAX（65535）に達するとGC実行→RuntimeError | mrb_irep_incref時 |
| BR-02 | NO_FREEフラグ | MRB_IREP_NO_FREEフラグ付きirepは解放しない | 静的irep（リテラルバイナリ）|
| BR-03 | ISEQ_NO_FREE | MRB_ISEQ_NO_FREEフラグ付きiseqは個別解放しない | 静的命令列 |

### 計算ロジック

特になし。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| RuntimeError | 参照カウントオーバーフロー | refcnt==UINT16_MAXかつGC後も変わらない | irepの過剰参照の見直し |

### リトライ仕様

refcnt==UINT16_MAX時にmrb_garbage_collect()を実行してリトライ。

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

該当なし

## パフォーマンス要件

- 参照カウントによる即時解放（GC不要）
- サブirepの再帰的decrefにより深い階層のirep木も効率的に解放

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

- MRB_DEBUG時にmrb_irep_free後のメモリを-1で埋める（use-after-free検出）

## 備考

- irep管理関数はstate.cに実装されている
- irepの構造はinclude/mruby/irep.hで定義
- pool[].tt==IREP_TT_STRまたはIREP_TT_BIGINTの場合、pool内の文字列データも個別に解放が必要

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | irep.h | `include/mruby/irep.h` | mrb_irep構造体（55-80行目）: nlocals, nregs, clen, flags, iseq, pool, syms, reps, lv, debug_info, refcnt |
| 1-2 | irep.h | `include/mruby/irep.h` | mrb_irep_pool構造体（30-40行目）: tt, u（str/i32/i64/f） |
| 1-3 | irep.h | `include/mruby/irep.h` | フラグ定義（82-84行目）: MRB_ISEQ_NO_FREE, MRB_IREP_NO_FREE, MRB_IREP_STATIC |

**読解のコツ**: irepは木構造（reps[]でサブirepを持つ）。ブロック定義やメソッド内メソッド定義でサブirepが生成される。

#### Step 2: 参照カウント操作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | state.c | `src/state.c` | mrb_irep_incref()（94-105行目）: NO_FREEチェック、UINT16_MAXオーバーフロー防止 |
| 2-2 | state.c | `src/state.c` | mrb_irep_decref()（107-115行目）: NO_FREEチェック、refcnt==0でfree |
| 2-3 | state.c | `src/state.c` | mrb_irep_cutref()（117-131行目）: サブirepの参照切断 |

**主要処理フロー**:
- **97-101行目**: refcnt==UINT16_MAX時にGC実行→再チェック→RuntimeError
- **112-114行目**: refcnt--後に0ならmrb_irep_free

#### Step 3: irep解放処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | state.c | `src/state.c` | mrb_irep_free()（133-164行目）: 全リソースの段階的解放 |
| 3-2 | state.c | `src/state.c` | mrb_add_irep()（206-217行目）: 新規irep生成 |

**主要処理フロー**:
- **138-140行目**: NO_FREEチェック、ISEQ_NO_FREE時はiseq非解放
- **141-149行目**: pool配列の走査とデータ解放
- **151-157行目**: サブirepの再帰的decref
- **159行目**: デバッグ情報の解放
- **163行目**: irep構造体自体の解放

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

```
mrb_add_irep()
    └─ mrb_malloc() ─── irep構造体割り当て

mrb_irep_incref() ─── refcnt++
mrb_irep_decref()
    └─ mrb_irep_free()
           ├─ mrb_free(iseq)
           ├─ mrb_free(pool[].u.str) × N
           ├─ mrb_free(pool)
           ├─ mrb_free(syms)
           ├─ mrb_irep_decref(reps[i]) × N ─── 再帰
           ├─ mrb_free(reps)
           ├─ mrb_free(lv)
           ├─ mrb_debug_info_free(debug_info)
           └─ mrb_free(irep)
```

### データフロー図

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

コンパイラ/ローダ ────────▶ mrb_add_irep()              ──▶ mrb_irep* (refcnt=1)
RProc生成 ───────────────▶ mrb_irep_incref()            ──▶ refcnt++
RProc解放 ───────────────▶ mrb_irep_decref()            ──▶ refcnt-- (0なら解放)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| state.c | `src/state.c` | ソース | irep参照カウント管理・解放 |
| irep.h | `include/mruby/irep.h` | ヘッダ | mrb_irep構造体定義 |
| load.c | `src/load.c` | ソース | バイナリからのirep生成 |
| debug.c | `src/debug.c` | ソース | mrb_debug_info_free |
