Files
hakorune/docs/private/roadmap/phases/phase-20.23/README.md

501 lines
15 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 20.23 — Arc/RefCell in Hakoruneメモリ所有権管理
**期間**: 2-3週間
**ステータス**: 計画更新20.21 RCテーブル導入と整合
**前提条件**: Phase 20.21Manual Memory Management完了
---
## 🎯 Executive Summary
**Critical Strategic Decision**: Arc/RefCell を **C ではなく Hakorune** で実装する。
### 理由Why Hakorune, Not C
| 観点 | C実装 | Hakorune実装 |
|------|-------|-------------|
| **開発期間** | 2-3ヶ月 | **2-3週間** ⚡ |
| **複雑性** | ❌ 高(低レベル並行制御) | ✅ 低(ポリシー記述) |
| **リスク** | ❌ 高(メモリ安全性) | ✅ 低(境界明確) |
| **保守性** | ❌ C コード保守 | ✅ Hakorune コード保守 |
| **テスト容易性** | ⚠️ 中 | ✅ 高(スクリプトレベル) |
### 実装パターンGcBox を踏襲)
**既存の成功事例**: `lang/src/runtime/gc/gc_box.hako`
```hakorune
// Policy plane (Hakorune) - ポリシー・ロジック層
static box GcBox {
stats() {
return call("env.gc.stats/0") // Data plane呼び出し
}
collect() {
call("env.gc.collect/0") // Data plane呼び出し
}
}
// Data plane (C/Rust) - 実際のメモリ操作
// Rust: fn hako_gc_stats() -> String { /* 実メモリ走査 */ }
// Rust: fn hako_gc_collect() { /* 実GC実行 */ }
```
**このパターンを Arc/RefCell に適用**:
- **Policy plane**: ArcBox/RefCellBox (Hakorune) - retain/release ロジック
- **Data plane**: Phase 20.21 の `hako_alloc/hako_free` (C) - 実メモリ操作
### Time Savings時間短縮効果
```
Before (C implementation plan):
Phase 20.23: Arc/RefCell (C) 2-3 months ❌
After (Hakorune implementation):
Phase 20.23: Arc/RefCell (Hako) 2-3 weeks ✅
Savings: ~2.5 months = 10-11 weeks ⚡
```
---
## 🏗️ アーキテクチャ設計
### Policy-Data Plane 分離(現状の足場)
```
┌─────────────────────────────────────────────────┐
│ Policy Plane (Hakorune) │
│ │
│ ┌────────────┐ ┌──────────────┐ │
│ │ ArcBox │ │ RefCellBox │ │
│ │ │ │ │ │
│ │ - retain() │ │ - borrow() │ │
│ │ - release()│ │ - borrow_mut │ │
│ │ - clone() │ │ - try_borrow │ │
│ └──────┬─────┘ └──────┬───────┘ │
│ │ │ │
└────────┼────────────────┼────────────────────────┘
│ │
│ call("env.arc.retain/1", ptr)
│ call("env.arc.release/1", ptr)
│ call("env.refcell.borrow/1", ptr)
▼ ▼
┌─────────────────────────────────────────────────┐
│ Data Plane (C - Phase 20.21 既存API) │
│ │
│ void* hako_alloc(size_t size) │
│ void hako_free(void* ptr) │
│ │
│ // Atomic operations (C11 標準) │
│ atomic_fetch_add(&ref_count, 1) │
│ atomic_fetch_sub(&ref_count, 1) │
└─────────────────────────────────────────────────┘
```
### ArcBox API 設計Hakorune Layer
```hakorune
// lang/src/runtime/memory/arc_box.hako
static box ArcBox {
// Opaque handle to C memory
ptr: IntegerBox // 64-bit pointer/handle
ref_count: IntegerBox // Local cache (optional)
// Constructor: Allocate and initialize ref_count=1
birth(data_ptr) {
me.ptr = data_ptr
me.ref_count = 1
call("env.arc.init/2", me.ptr, 1) // C side初期化
}
// Increment ref count (atomic)
retain() {
local new_count = call("env.arc.retain/1", me.ptr)
me.ref_count = new_count
return new_count
}
// Decrement ref count, free if 0 (atomic)
release() {
local new_count = call("env.arc.release/1", me.ptr)
me.ref_count = new_count
if (new_count == 0) {
call("env.arc.free/1", me.ptr) // C側でhako_free呼び出し
me.ptr = 0 // Dangling pointer防止
}
return new_count
}
// Clone (increment ref_count and return new ArcBox)
clone() {
me.retain()
local new_arc = new ArcBox()
new_arc.ptr = me.ptr
new_arc.ref_count = me.ref_count
return new_arc
}
// Get raw pointer (unsafe, for C interop)
as_ptr() {
return me.ptr
}
}
```
### RefCellBox API 設計Hakorune Layer
```hakorune
// lang/src/runtime/memory/refcell_box.hako
static box RefCellBox {
ptr: IntegerBox // Opaque handle
borrow_state: IntegerBox // 0=free, >0=shared, -1=mutable
birth(data_ptr) {
me.ptr = data_ptr
me.borrow_state = 0 // Initially free
call("env.refcell.init/2", me.ptr, 0)
}
// Shared borrow (multiple readers allowed)
borrow() {
local state = call("env.refcell.try_borrow/1", me.ptr)
if (state < 0) {
// Already mutably borrowed - panic
call("env.panic/1", "RefCellBox: already mutably borrowed")
}
me.borrow_state = state + 1 // Increment reader count
return me.ptr // Return borrowed reference
}
// Mutable borrow (exclusive)
borrow_mut() {
local state = call("env.refcell.try_borrow_mut/1", me.ptr)
if (state != 0) {
// Already borrowed - panic
call("env.panic/1", "RefCellBox: already borrowed")
}
me.borrow_state = -1 // Mark as mutably borrowed
return me.ptr
}
// Release borrow (caller must specify type)
release_borrow(is_mutable) {
if (is_mutable == 1) {
call("env.refcell.release_mut/1", me.ptr)
me.borrow_state = 0
} else {
call("env.refcell.release_shared/1", me.ptr)
me.borrow_state = me.borrow_state - 1
}
}
// Try operations (non-panicking)
try_borrow() {
local state = call("env.refcell.try_borrow/1", me.ptr)
if (state < 0) {
return null // Failed
}
me.borrow_state = state + 1
return me.ptr // Success
}
try_borrow_mut() {
local state = call("env.refcell.try_borrow_mut/1", me.ptr)
if (state != 0) {
return null // Failed
}
me.borrow_state = -1
return me.ptr // Success
}
}
```
---
## 🔧 C Side Minimal APIData Plane
Phase 20.21 既存APIに以下を追加100行程度:
(補足)現状、`include/hako_mem.h``src/abi/c/mem_libc.c` は RC テーブルへ委譲済み:
- `src/abi/c/handle_registry.{h,c}` — ハンドルの参照カウントをC11 atomicで管理
- `hako_retain/hako_release` は未知/二重解放で FailFast安定メッセージ
この上に Arc/RefCell の dataplane API を薄く足す。
```c
// lang/src/runtime/memory/arc.c (NEW, ~50 lines)
#include <stdatomic.h>
#include <stdint.h>
#include "hakmem.h" // Phase 20.21
// Arc metadata (prepended to allocation)
typedef struct {
atomic_uint_fast64_t ref_count;
size_t size;
} ArcHeader;
// Initialize Arc (called from ArcBox.birth)
void hako_arc_init(void* ptr, uint64_t initial_count) {
ArcHeader* hdr = (ArcHeader*)ptr;
atomic_init(&hdr->ref_count, initial_count);
}
// Atomic retain (returns new count)
uint64_t hako_arc_retain(void* ptr) {
ArcHeader* hdr = (ArcHeader*)ptr;
return atomic_fetch_add(&hdr->ref_count, 1) + 1;
}
// Atomic release (returns new count)
uint64_t hako_arc_release(void* ptr) {
ArcHeader* hdr = (ArcHeader*)ptr;
uint64_t old = atomic_fetch_sub(&hdr->ref_count, 1);
return old - 1; // New count
}
// Free Arc (called when ref_count=0)
void hako_arc_free(void* ptr) {
hako_free(ptr); // Phase 20.21 API
}
```
```c
// lang/src/runtime/memory/refcell.c (NEW, ~50 lines)
#include <stdatomic.h>
// RefCell metadata
typedef struct {
atomic_int_fast32_t borrow_state; // 0=free, >0=shared, -1=mutable
} RefCellHeader;
void hako_refcell_init(void* ptr, int32_t initial_state) {
RefCellHeader* hdr = (RefCellHeader*)ptr;
atomic_init(&hdr->borrow_state, initial_state);
}
// Try shared borrow (returns current state or -1 if failed)
int32_t hako_refcell_try_borrow(void* ptr) {
RefCellHeader* hdr = (RefCellHeader*)ptr;
int32_t state = atomic_load(&hdr->borrow_state);
if (state < 0) return -1; // Already mutably borrowed
atomic_fetch_add(&hdr->borrow_state, 1);
return state + 1;
}
// Try mutable borrow
int32_t hako_refcell_try_borrow_mut(void* ptr) {
RefCellHeader* hdr = (RefCellHeader*)ptr;
int32_t expected = 0;
if (atomic_compare_exchange_strong(&hdr->borrow_state, &expected, -1)) {
return 0; // Success
}
return expected; // Failed (return current state)
}
// Release shared borrow
void hako_refcell_release_shared(void* ptr) {
RefCellHeader* hdr = (RefCellHeader*)ptr;
atomic_fetch_sub(&hdr->borrow_state, 1);
}
// Release mutable borrow
void hako_refcell_release_mut(void* ptr) {
RefCellHeader* hdr = (RefCellHeader*)ptr;
atomic_store(&hdr->borrow_state, 0);
}
```
**Total C code added**: ~100 linesPhase 20.21 の 5%
---
## 📋 Week-by-Week Implementation Plan
### Week 1: ArcBox ImplementationRCテーブル上に実装
**Day 1-2: C Data Plane**
- [ ] `arc.c/arc.h` 実装50行
- [ ] Atomic operations テストretain/release
- [ ] Memory leak テストvalgrind
**Day 3-4: Hakorune Policy Plane**
- [ ] `lang/src/runtime/memory/arc_box.hako` 実装
- [ ] `birth/retain/release/clone` メソッド
- [ ] `call("env.arc.*")` extern binding
**Day 5: Integration Testing**
- [ ] スモークテスト追加(`tools/smokes/v2/suites/memory/arc_*.sh`
- [ ] Multi-threaded stress test4 threads, 10000 ops
- [ ] Memory leak verificationvalgrind clean
### Week 2: RefCellBox Implementation
**Day 1-2: C Data Plane**
- [ ] `refcell.c/refcell.h` 実装50行
- [ ] Borrow state transitions テスト
- [ ] Panic case validationdouble mut borrow
**Day 3-4: Hakorune Policy Plane**
- [ ] `lang/src/runtime/memory/refcell_box.hako` 実装
- [ ] `borrow/borrow_mut/release_borrow` メソッド
- [ ] `try_borrow/try_borrow_mut` 実装
**Day 5: Integration Testing**
- [ ] Borrow check テストpanic cases
- [ ] Nested borrow テスト
- [ ] Shared + mutable conflict テスト
### Week 3: Integration & Documentation
**Day 1-2: Integration with Box System**
- [ ] StringBox + Arc 統合テスト
- [ ] ArrayBox + RefCell 統合テスト
- [ ] MapBox + Arc/RefCell 統合テスト
**Day 3: Performance Benchmarking**
- [ ] Arc clone overheadvs Rust `Arc::clone`
- [ ] RefCell borrow overheadvs Rust `RefCell::borrow`
- [ ] Multi-threaded throughput
**Day 4-5: Documentation**
- [ ] API documentationArcBox/RefCellBox
- [ ] Migration guideRust Arc/RefCell → Hakorune
- [ ] Best practiceswhen to use Arc vs RefCell
- [ ] Failure modes & error handling
---
## ✅ 受け入れ基準Acceptance Criteria
### Functional Requirements
- [ ] **ArcBox**: retain/release/clone 正常動作
- [ ] **RefCellBox**: borrow/borrow_mut 正常動作
- [ ] **Panic cases**: 不正なborrow操作で適切にpanic
- [ ] **Memory safety**: valgrind cleanleak なし)
- [ ] **Thread safety**: 4 threads concurrent access で破損なし
### Performance Requirements
- [ ] **Arc clone**: < 50ns per operationmimalloc程度
- [ ] **RefCell borrow**: < 10ns per operationほぼゼロコスト
- [ ] **Overhead**: Rust Arc/RefCell 2倍以内
### Testing Requirements
- [ ] **Unit tests**: 20+ testsC layer + Hakorune layer
- [ ] **Integration tests**: 10+ Box system 統合テスト
- [ ] **Smoke tests**: `tools/smokes/v2/profiles/quick/` 追加
- [ ] **Stress tests**: 10000 ops, 4 threads, no crashes
### Documentation Requirements
- [ ] **API docs**: ArcBox/RefCellBox 完全仕様
- [ ] **Implementation docs**: Policy-Data plane 設計図
- [ ] **Migration guide**: Rust Hakorune 移行手順
- [ ] **Troubleshooting**: よくあるエラーと対処法
---
## 🚨 リスク分析と軽減策
### Risk Matrix
| リスク | 確率 | 影響 | 軽減策 |
|--------|------|------|--------|
| **Atomic operations バグ** | | | C11 標準 atomic 使用既存実装参照 |
| **Memory leak** | | | valgrind 継続検証ref_count audit |
| **Race condition** | | | TSanThread Sanitizer使用 |
| **Borrow check 不完全** | | | Rust RefCell テストケース移植 |
| **Performance 劣化** | | | Benchmark driven development |
### Mitigation Strategies
1. **Continuous Testing**: 毎日 valgrind + TSan 実行
2. **Reference Implementation**: Rust std::sync::Arc/RefCell をリファレンス
3. **Incremental Integration**: Week 1 Arc 完成後Week 2 RefCell
4. **Early Performance Validation**: Week 1 overhead 確認問題なければ継続
5. **Rollback Plan**: Phase 20.21 API は変更なしいつでも Arc/RefCell 削除可能
---
## 📊 Timeline Comparison再掲
### Before (C Implementation - Original Plan)
```
Phase 20.23: Arc/RefCell (C) 2-3 months ❌
├─ Week 1-4: Arc implementation (C)
├─ Week 5-8: RefCell implementation (C)
└─ Week 9-12: Integration & testing
Risk: HIGH ❌
Complexity: HIGH ❌
```
### After (Hakorune Implementation - This Plan)
```
Phase 20.23: Arc/RefCell (Hako) 2-3 weeks ✅
├─ Week 1: ArcBox (Hakorune + 50 lines C)
├─ Week 2: RefCellBox (Hakorune + 50 lines C)
└─ Week 3: Integration & docs
Risk: LOW ✅
Complexity: LOW ✅
```
**Savings**: ~2.5 months (10-11 weeks)
---
## 🔗 関連ドキュメント
- **Phase 20.21**: [Manual Memory Management](../phase-20.21/README.md) - C API 基盤
- **Phase 20.22**: [String/Array C-ABI](../phase-20.22/README.md) - Box system 連携
- **Phase 20.24**: [Parser削除](../phase-20.24/README.md) - 次のフェーズ
- **GcBox Pattern**: `lang/src/runtime/gc/gc_box.hako` - 実装パターン参照
---
## 💡 Key Insightsまとめ
### Why This Approach Works
1. **Policy-Data Separation**: Hakorune はロジックC は実メモリ操作
2. **Minimal C Code**: 100行のみ追加Phase 20.21 5%
3. **Proven Pattern**: GcBox で既に検証済み
4. **Low Risk**: Hakorune レイヤーなので変更容易
5. **Fast Development**: スクリプトレベル実装は C より 10倍速い
### Strategic Advantage
**User の洞察**: "Arc/RefCell はHakoruneスクリプトで実装するやつじゃない"
**完全に正しい!**
これにより:
- **2.5ヶ月の時間短縮**
- **リスク大幅削減**C バグ vs Hakorune バグ
- **保守性向上**Hakorune コードは読みやすい
- **テスト容易性向上**スクリプトレベルでテスト
---
**ステータス**: 未開始
**開始可能条件**: Phase 20.21 完了
**期間**: 2-3週間
**次フェーズ**: Phase 20.24Parser削除