# 機能設計書 54-ILライター

## 概要

本ドキュメントは、F#コンパイラにおける.NETアセンブリ（PE/CLI形式）のバイナリ書き込み機能について記述する。

### 本機能の処理概要

ILモジュール定義（ILModuleDef）を.NETアセンブリファイル（.dll/.exe）としてバイナリ形式で出力するライター機能を提供する。

**業務上の目的・背景**：F#コンパイラは内部表現（ILModuleDef）をCLI/PE形式のバイナリファイルに変換して出力する必要がある。本機能はIL抽象構文をECMA-335準拠のPE形式にシリアライズし、実行可能なアセンブリを生成する。

**機能の利用シーン**：
- F#コンパイラによるDLL/EXE生成
- F# Interactiveでの動的コード生成
- Fable等のトランスパイラでのIL出力

**主要な処理内容**：
1. メタデータテーブルの構築（TypeDef, MethodDef等）
2. 文字列ヒープ/BLOBヒープ/GUIDヒープの構築
3. ILコードのアセンブル（命令のバイト列化）
4. PEヘッダーの生成
5. セクションテーブルの構築
6. CLIヘッダーの生成
7. リソースの埋め込み
8. 強い名前の署名準備

**関連システム・外部連携**：
- 強い名前署名（ilsign.fs）
- PDB生成（ilwritepdb.fs）
- リソース埋め込み

**権限による制御**：ファイルシステム書き込み権限

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | ビルド出力 | 参照画面 | コンパイル結果の確認 |

## 機能種別

データ変換 / バイナリ出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| inputModule | ILModuleDef | Yes | 出力するILモジュール定義 | - |
| options | ILBinaryWriterOptions | Yes | 書き込みオプション | - |
| normalizeAssemblyRefs | ILAssemblyRef -> ILAssemblyRef | Yes | アセンブリ参照正規化関数 | - |

### ILBinaryWriterOptions

| フィールド | 型 | 説明 |
|-----------|-----|------|
| outfile | string | 出力ファイルパス |
| pdbfile | string option | PDBファイルパス |
| portablePDB | bool | ポータブルPDB出力 |
| embeddedPDB | bool | 埋め込みPDB |
| embedAllSource | bool | 全ソース埋め込み |
| embedSourceList | string list | 埋め込むソースリスト |
| sourceLink | string | SourceLinkファイル |
| checksumAlgorithm | HashAlgorithm | チェックサムアルゴリズム |
| signer | ILStrongNameSigner option | 署名者 |
| emitTailcalls | bool | tailcall命令出力 |
| deterministic | bool | 決定論的ビルド |
| pathMap | PathMap | パスマッピング |

### 入力データソース

- ILModuleDef（コンパイラ内部表現）
- リソースファイル
- 署名キー

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| - | .dll/.exe | PE/CLI形式バイナリファイル |
| - | .pdb | デバッグシンボルファイル（オプション） |

### 出力先

- ファイルシステム（指定パス）
- メモリバッファ（WriteILBinaryInMemory）

## 処理フロー

### 処理シーケンス

```
1. 環境（cenv）の初期化
   └─ メタデータテーブル用配列の準備
   └─ ヒープ（String, Blob, GUID）の初期化

2. モジュール情報の書き込み
   └─ Module行の生成
   └─ アセンブリ情報の書き込み

3. 型定義の書き込み
   └─ TypeDef行の生成
   └─ ネストされた型の処理
   └─ フィールド/メソッド/プロパティ/イベント

4. メソッド本体の書き込み
   └─ ILコードのアセンブル
   └─ 例外ハンドラテーブル
   └─ ローカル変数署名

5. カスタム属性の書き込み
   └─ CustomAttribute行の生成
   └─ BLOB形式での属性データ

6. リソースの書き込み
   └─ マネージドリソース
   └─ アンマネージドリソース

7. メタデータの最終化
   └─ テーブルのソート
   └─ ヒープのシリアライズ
   └─ メタデータルートの構築

8. PE構造の書き込み
   └─ DOSヘッダー
   └─ PEヘッダー
   └─ セクションテーブル
   └─ CLIヘッダー

9. ファイル出力
   └─ 全セクションの書き込み
   └─ 署名（オプション）
```

### フローチャート

```mermaid
flowchart TD
    A[開始: WriteILBinaryFile] --> B[cenv初期化]
    B --> C[モジュール情報書き込み]
    C --> D[型定義書き込み]
    D --> E[メソッド本体書き込み]
    E --> F[カスタム属性書き込み]
    F --> G[リソース書き込み]
    G --> H[メタデータ最終化]
    H --> I[PE構造書き込み]
    I --> J{署名必要?}
    J -->|Yes| K[署名処理]
    J -->|No| L[ファイル出力]
    K --> L
    L --> M[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-54-01 | 型メソッド上限 | 1型あたりのメソッド数は0xfff0が上限 | 常時 |
| BR-54-02 | 圧縮整数 | 0-0x7F:1バイト、0x80-0x3FFF:2バイト、その他:4バイト | メタデータエンコーディング |
| BR-54-03 | 決定論的ビルド | deterministic=trueの場合、タイムスタンプは内容ハッシュから生成 | deterministic=true |
| BR-54-04 | セクションアライメント | コード/データセクションは0x200バイト境界 | 常時 |

### 計算ロジック

**圧縮整数エンコーディング（Z32）**:
- n <= 0x7F: 1バイト（そのまま）
- n <= 0x3FFF: 2バイト（0x80 | 上位7ビット, 下位8ビット）
- その他: 4バイト（0xC0 | 上位6ビット, 次8ビット, 次8ビット, 下位8ビット）

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| FSComp.SR.tooManyMethodsPerType | エラー | 型あたりのメソッド数超過 | 型を分割 |
| fixup sanity check failed | 内部エラー | フィックスアップ位置不正 | バグ報告 |
| - | IOException | ファイル書き込み失敗 | パス/権限確認 |

### リトライ仕様

本機能にリトライ機構はない。

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

該当なし（ファイルは最終段階で一括書き込み）

## パフォーマンス要件

- メタデータテーブルは重複排除（ハッシュによる高速検索）
- 文字列/BLOBヒープも重複排除
- 大規模アセンブリ対応（テーブルサイズに応じた2/4バイトインデックス）

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

- 署名キーの安全な取り扱い
- 出力パスのバリデーション

## 備考

- maximumMethodsPerDotNetType = 0xfff0（ECMA仕様と異なる経験的値）
- ユニコードマーカーの判定ロジックはC#実装に準拠

---

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

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

### 推奨読解順序

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

まず、書き込み用のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | RowElement型（220-224行目）でテーブル行要素を理解 |
| 1-2 | ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | RowElementTags（156-218行目）でタグ種別を理解 |

**読解のコツ**: RowElementは(tag, value)のペアで、tagがデータ種別（UShort/Blob/String等）、valueがインデックスまたは値を表す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | WriteILBinaryFile関数（4617行目）がファイル出力のエントリーポイント |
| 2-2 | ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | WriteILBinaryInMemory関数（4621行目）がメモリ出力のエントリーポイント |

#### Step 3: バイナリ書き込みプリミティブを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | b0/b1/b2/b3関数（27-30行目）でリトルエンディアン変換 |
| 3-2 | ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | ByteBuffer.EmitZ32（73-83行目）で圧縮整数エンコーディング |
| 3-3 | ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | align関数（51行目）でアライメント計算 |

#### Step 4: フィックスアップ機構を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | checkFixup32/applyFixup32関数（140-150行目）で後処理パッチを理解 |

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

```
WriteILBinaryFile / WriteILBinaryInMemory
    │
    ├─ cenv (書き込み環境) の初期化
    │
    ├─ GenModule (モジュール情報生成)
    │      └─ GenModuleRef
    │      └─ GenAssemblyRef
    │
    ├─ GenTypeDefs (型定義生成)
    │      ├─ GenTypeDef
    │      ├─ GenFieldDef
    │      ├─ GenMethodDef
    │      │      └─ GenMethodBody (ILコードアセンブル)
    │      ├─ GenPropertyDef
    │      └─ GenEventDef
    │
    ├─ GenCustomAttrs (カスタム属性生成)
    │
    ├─ GenResources (リソース生成)
    │
    ├─ BuildMetadata (メタデータ構築)
    │      ├─ EmitTablesAndHeaps
    │      └─ BuildMetadataRoot
    │
    └─ WritePE (PE構造書き込み)
           ├─ WriteDOSHeader
           ├─ WritePEHeader
           ├─ WriteSectionHeaders
           └─ WriteSections
                  └─ signer.SignStream (オプション)
```

### データフロー図

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

ILModuleDef           ──▶  cenv初期化                ──▶  cenv (書き込み環境)
       │
       ▼
ILTypeDef[]           ──▶  GenTypeDefs              ──▶  TypeDefテーブル行
       │
       ▼
ILMethodDef[]         ──▶  GenMethodDef             ──▶  MethodDefテーブル行
       │
       ▼
ILCode                ──▶  GenMethodBody            ──▶  ILバイトコード
       │
       ▼
テーブル/ヒープ       ──▶  BuildMetadata            ──▶  メタデータバイト列
       │
       ▼
メタデータ + コード   ──▶  WritePE                  ──▶  PE/CLIバイナリ
       │
       ▼
PE/CLIバイナリ        ──▶  SignStream (オプション)  ──▶  署名済みアセンブリ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | ソース | ILバイナリライターの中核実装 |
| il.fs | `src/Compiler/AbstractIL/il.fs` | ソース | IL抽象構文（入力データ構造） |
| BinaryConstants.fs | `src/Compiler/AbstractIL/BinaryConstants.fs` | ソース | PE/CLIバイナリ定数 |
| ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | ソース | 強い名前署名 |
| ilwritepdb.fs | `src/Compiler/AbstractIL/ilwritepdb.fs` | ソース | PDBファイル生成 |
