Files
hakorune/docs/development/roadmap/phases/phase-11.5/11.5a-WRITE-BARRIER-REMOVAL.md

5.2 KiB
Raw Blame History

Phase 11.5a: Write Barrier除去によるGC最適化

🎯 目標

JITコンパイル時にescape analysisを行い、不要なwrite barrierを除去してGC性能を大幅に向上させる。

📊 現状の問題

現在のVM実装

// すべてのrefset操作でbarrierが呼ばれる
pub fn execute_ref_set(&mut self, reference: ValueId, field: &str, value: ValueId) 
    -> Result<ControlFlow, VMError> {
    // ... 値の設定 ...
    
    // 常にwrite barrierが実行される
    gc_write_barrier_site(&self.runtime, "RefSet");
    Ok(ControlFlow::Continue)
}

オーバーヘッド

  • 単純な代入でも毎回barrier呼び出し
  • Stack上のローカル変数でも不要にbarrier
  • ループ内での大量のbarrier呼び出し

🚀 実装計画

Step 1: Escape Analysis基盤

// mir/escape_analysis.rs
pub struct EscapeAnalysis {
    // allocation site追跡
    allocations: HashMap<ValueId, AllocInfo>,
    // escape状態
    escapes: HashSet<ValueId>,
    // 解析結果キャッシュ
    cache: HashMap<FunctionId, EscapeInfo>,
}

#[derive(Debug)]
struct AllocInfo {
    location: BasicBlockId,
    kind: AllocKind,
    size: Option<usize>,
}

enum AllocKind {
    NewBox,      // new StringBox()
    ArrayNew,    // []
    RefNew,      // ユーザー定義Box
}

Step 2: MIR解析

impl EscapeAnalysis {
    /// 関数内でのescape解析
    pub fn analyze_function(&mut self, func: &MirFunction) -> EscapeInfo {
        // 1. allocation site収集
        for (bb_id, bb) in &func.basic_blocks {
            for inst in &bb.instructions {
                match inst {
                    MirInstruction::NewBox { dst, .. } |
                    MirInstruction::ArrayNew { dst, .. } |
                    MirInstruction::RefNew { dst, .. } => {
                        self.allocations.insert(*dst, AllocInfo {
                            location: bb_id,
                            kind: self.classify_alloc(inst),
                            size: self.estimate_size(inst),
                        });
                    }
                    _ => {}
                }
            }
        }
        
        // 2. escape point検出
        self.find_escape_points(func);
        
        // 3. 結果集計
        EscapeInfo {
            non_escaping: self.collect_non_escaping(),
            barrier_sites: self.collect_barrier_sites(),
        }
    }
    
    fn find_escape_points(&mut self, func: &MirFunction) {
        // return文でのescape
        // 関数引数としてのescape
        // グローバル変数へのescape
        // プラグイン呼び出しでのescape
    }
}

Step 3: JIT統合

// jit/lower/builder.rs
impl<'a> LoweringBuilder<'a> {
    fn emit_ref_set(&mut self, reference: Value, field: &str, value: Value) {
        // escape解析結果を確認
        let needs_barrier = self.escape_info
            .map(|info| info.needs_barrier(reference))
            .unwrap_or(true); // 解析なしなら保守的にbarrier
            
        if needs_barrier {
            // barrierあり
            self.emit_gc_barrier(BarrierKind::Write);
        } else {
            // barrier除去
            if self.config.trace_opt {
                eprintln!("[JIT] barrier removed at {:?}", self.current_location());
            }
        }
        
        // 実際のstore操作
        self.emit_store(reference, field, value);
    }
}

Step 4: 最適化レベル設定

// 環境変数で制御
NYASH_JIT_ESCAPE_ANALYSIS=1  # escape analysis有効化
NYASH_JIT_BARRIER_OPT=1      # barrier最適化有効化
NYASH_JIT_BARRIER_STATS=1    # 統計出力

📈 期待される効果

ベンチマーク例

// 大量のローカル変数操作
function processData(n) {
    local sum = 0
    local temp = new MapBox()
    
    loop(i < n) {
        temp.set(i, i * 2)  // escape analysisでbarrier除去
        sum = sum + temp.get(i)
        i = i + 1
    }
    
    return sum
}

性能改善予測

  • ローカル変数操作: 90%以上のbarrier除去
  • ループ内操作: 80%以上の高速化
  • 全体的なGCオーバーヘッド: 50%削減

🔍 検証方法

1. Barrier統計

{
  "total_barriers": 10000,
  "removed_barriers": 8500,
  "removal_rate": 0.85,
  "sites": {
    "RefSet": { "total": 5000, "removed": 4800 },
    "ArraySet": { "total": 3000, "removed": 2500 },
    "MapSet": { "total": 2000, "removed": 1200 }
  }
}

2. 性能測定

# barrier最適化なし
NYASH_JIT_ESCAPE_ANALYSIS=0 ./target/release/nyash --benchmark

# barrier最適化あり
NYASH_JIT_ESCAPE_ANALYSIS=1 ./target/release/nyash --benchmark

🚧 実装上の注意点

  1. 保守的な解析

    • 不明な場合は必ずbarrierを残す
    • プラグイン境界では常にbarrier
  2. デバッグ性

    • 除去したbarrierサイトを記録
    • GCエラー時の診断情報
  3. 段階的実装

    • まずローカル変数のみ
    • 次にループ不変式
    • 最後に関数間解析

🎉 完了基準

  • Escape analysis基本実装
  • MIR解析パス追加
  • JIT統合
  • ベンチマーク50%改善
  • ドキュメント更新