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

200 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 11.5a: Write Barrier除去によるGC最適化
## 🎯 目標
JITコンパイル時にescape analysisを行い、不要なwrite barrierを除去してGC性能を大幅に向上させる。
## 📊 現状の問題
### 現在のVM実装
```rust
// すべての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基盤
```rust
// 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解析
```rust
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統合
```rust
// 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: 最適化レベル設定
```rust
// 環境変数で制御
NYASH_JIT_ESCAPE_ANALYSIS=1 # escape analysis有効化
NYASH_JIT_BARRIER_OPT=1 # barrier最適化有効化
NYASH_JIT_BARRIER_STATS=1 # 統計出力
```
## 📈 期待される効果
### ベンチマーク例
```nyash
// 大量のローカル変数操作
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統計
```json
{
"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. 性能測定
```bash
# 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%改善
- [ ] ドキュメント更新