# 機能設計書 16-Symbolクラス

## 概要

本ドキュメントは、mrubyにおけるSymbolクラスの機能設計を記述する。Symbolクラスはシンボル（内部化された文字列識別子）の管理を提供し、シンボルテーブルによる一意性保証とid変換を行う組み込み型クラスである。

### 本機能の処理概要

Symbolクラスは、文字列を内部化した不変の識別子を管理する。ISO 15.2.11に準拠する。シンボルは一度生成されると実行期間中にGCされず、同じ文字列からは常に同じシンボルが返される（一意性保証）。メソッド名、変数名、クラス名等の内部識別子として広く使用される。mrubyでは、プリコンパイルシンボル（presym）と動的シンボルの2層構造を採用し、静的に決定可能なシンボルのルックアップコストを最小化している。また、チャンクベースのメモリプールによるシンボル名の効率的なメモリ管理を行う。

**業務上の目的・背景**：シンボルはRuby言語の基本的な識別子機構であり、メソッドディスパッチ、インスタンス変数アクセス、定数参照など内部処理の至る所で使用される。文字列と異なり不変であるため、ハッシュキーとして使用した場合にハッシュ値の再計算が不要で高速である。プリコンパイルシンボルにより、コンパイル時に決定されるシンボルは実行時のルックアップが不要となる。

**機能の利用シーン**：メソッド名の参照（:method_name）、ハッシュのキー（{key: value}）、メソッドディスパッチ（send(:method)）、変数名の内部表現、パターンマッチング等。

**主要な処理内容**：
1. プリコンパイルシンボルの二分探索ルックアップ
2. 動的シンボルの生成とシンボルテーブルへの登録
3. シンボルから文字列への逆引き（to_s, id2name）
4. 文字列からシンボルへの変換（to_sym, intern）
5. シンボルの比較（==, <=>）
6. シンボルの検査（inspect）
7. チャンクベースメモリプールによるシンボル名管理
8. LSBポインタタギングによるリテラル/非リテラル識別

**関連システム・外部連携**：Stringクラスのto_sym/internメソッド、VMのメソッドディスパッチ、クラス定義、変数テーブルなど、ランタイム全体で使用される中核的な機構。

**権限による制御**：Symbol.newは未定義化されており、直接のインスタンス生成は不可。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIベースのランタイム機能のため関連画面なし |

## 機能種別

データ操作 / 識別子管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes（シンボル生成時） | シンボル名の文字列 | UINT16_MAX未満の長さ |
| len | size_t | Yes（C API） | シンボル名の長さ | UINT16_MAX未満 |

### 入力データソース

シンボルリテラル、文字列のto_sym/intern、C APIからのmrb_intern呼び出し。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| シンボル | Symbol | 生成/参照されたシンボル（mrb_sym型=整数ID） |
| 文字列 | String | to_s, id2name, inspectの変換結果 |
| 整数 | Integer | to_iの変換結果（シンボルID） |

### 出力先

呼び出し元への戻り値として返却。

## 処理フロー

### 処理シーケンス

```
1. シンボルの検索/生成
   └─ プリコンパイルシンボルテーブルを二分探索
       └─ 見つかった場合: presym ID を返却
   └─ 動的シンボルテーブルを検索
       └─ 見つかった場合: 既存ID を返却
   └─ 新規シンボルの登録
       └─ チャンクメモリプールから名前用メモリを確保
       └─ LSBタグでリテラル/非リテラルを識別
       └─ シンボルテーブルに登録
       └─ 新規ID を返却
2. シンボルから文字列への逆引き
   └─ IDがpresym範囲内: presym_name_tableから取得
   └─ IDがpresym範囲外: 動的テーブルから取得
```

### フローチャート

```mermaid
flowchart TD
    A[シンボル検索要求] --> B{presymテーブル検索}
    B -->|見つかった| C[presym ID 返却]
    B -->|見つからない| D{動的テーブル検索}
    D -->|見つかった| E[既存ID 返却]
    D -->|見つからない| F[新規登録]
    F --> G[メモリプールから名前確保]
    G --> H[テーブルに追加]
    H --> I[新規ID 返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-16-01 | 一意性保証 | 同一文字列からは常に同一のシンボルIDが返される | シンボル生成時 |
| BR-16-02 | 不変性 | シンボルは生成後に変更不可 | 常時 |
| BR-16-03 | GC非対象 | シンボルはGCの対象にならない | 常時 |
| BR-16-04 | 長さ制限 | シンボル名はUINT16_MAX（65535）未満 | シンボル生成時 |
| BR-16-05 | new未定義 | Symbol.newは使用不可 | クラスメソッド呼び出し時 |
| BR-16-06 | プリコンパイル優先 | presymテーブルを先に検索し、動的テーブルは後 | シンボル検索時 |

### 計算ロジック

- **presym二分探索**: 長さテーブル(`presym_length_table`)でまず長さ比較、次にmemcmpで名前比較
- **LSBタギング**: ポインタの最下位ビットでリテラル（1）/非リテラル（0）を識別
- **チャンクサイズ**: MRB_SYM_POOL_CHUNK_SIZE = 4096バイト

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

該当なし（インメモリ操作のみ）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentError | シンボル名がUINT16_MAX以上 | 短い名前を使用する |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- プリコンパイルシンボルの検索: O(log n) の二分探索
- 動的シンボルの検索: テーブルサイズに依存
- シンボル比較: O(1)（整数比較）
- チャンクメモリプールにより小さなmalloc呼び出しを削減

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

- シンボルはGC対象外のため、大量の異なるシンボルの動的生成はメモリリークの原因となりうる

## 備考

- ISO 15.2.11に準拠
- mrb_sym型は整数（コンパクトな表現）
- presymは`include/mruby/presym/table.h`で自動生成される
- mrblib/symbol.rbでto_procメソッドが定義されている

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | symbol.c | `src/symbol.c` | sym_pool_chunk構造体、LSBタギング関数群 |

**読解のコツ**: シンボルの内部表現はmrb_sym型（整数）。1〜MRB_PRESYM_MAXはプリコンパイルシンボル、それ以降が動的シンボル。ポインタのLSBをリテラルフラグとして利用するため、ポインタは偶数アドレスにアラインされている必要がある。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | symbol.c | `src/symbol.c` | `mrb_init_symbol()`関数（1014行目）でクラス定義 |

**主要処理フロー**:
1. **1014-1023行目**: Symbolクラス定義、newメソッドundef、ROMメソッドテーブル初期化

#### Step 3: シンボル検索・生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | symbol.c | `src/symbol.c` | presym_find（21-40行目）、sym_pool_alloc（94-100行目） |

**主要処理フロー**:
- **21-40行目**: presym_find - プリコンパイルシンボルの二分探索
- **42-48行目**: presym_sym2name - presymの逆引き
- **52-75行目**: LSBタギング関数群（symtbl_get_ptr, symtbl_is_literal, symtbl_tag_literal）
- **77-83行目**: sym_validate_len - 長さ検証（UINT16_MAX未満）
- **88-92行目**: sym_pool_chunk構造体（チャンクベースメモリプール）
- **94-100行目**: sym_pool_alloc - チャンクからのメモリ確保

#### Step 4: Rubyレベルメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | symbol.rb | `mrblib/symbol.rb` | to_procメソッドの実装 |

**主要処理フロー**:
- **2-7行目**: `to_proc` - シンボルをProcに変換（`->(obj,*args,**opts,&block) { obj.__send__(mid, *args, **opts, &block) }`）

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

```
mrb_init_symbol()
    |
    +-- mrb_define_class_id(Symbol)
    +-- mrb_undef_class_method_id(new)
    +-- MRB_MT_INIT_ROM(symbol_rom_entries)

シンボル検索:
    mrb_intern / mrb_intern_str
        |
        +-- presym_find (二分探索)
        |       |
        |       +-- presym_length_table / presym_name_table
        |
        +-- 動的テーブル検索
                |
                +-- sym_pool_alloc (チャンクメモリプール)
                +-- symtbl_tag_literal (LSBタギング)
```

### データフロー図

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

文字列名             presym二分探索                     mrb_sym (整数ID)
             ---->   or 動的テーブル検索         ---->
                       |
                     見つからない場合:
                       sym_pool_alloc
                       テーブル登録

mrb_sym          presym_sym2name                    文字列名
(整数ID)   ---->  or 動的テーブル逆引き        ---->  (to_s結果)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| symbol.c | `src/symbol.c` | ソース（C） | Symbolクラスの主要実装（1024行） |
| symbol.rb | `mrblib/symbol.rb` | ソース（Ruby） | to_procメソッドの実装 |
| presym.h | `include/mruby/presym.h` | ヘッダ | プリコンパイルシンボル定義 |
| presym/table.h | `include/mruby/presym/table.h` | ヘッダ（自動生成） | presymテーブルデータ |
