Major Interpreter Refactoring: - Split core.rs (373 lines removed) into focused modules - Split expressions/calls.rs (460 lines removed) into cleaner structure - Added new modules: calls.rs, errors.rs, eval.rs, methods_dispatch.rs, state.rs - Improved separation of concerns across interpreter components P2PBox Enhancements: - Added on_once() for one-time event handlers - Added off() for handler deregistration - Implemented handler flags with AtomicBool for thread-safe management - Added loopback testing cache (last_from, last_intent_name) - Improved Arc-based state sharing for transport and handlers Plugin Loader Unification (In Progress): - Created plugin_loader_unified.rs skeleton - Created plugin_ffi_common.rs for shared FFI utilities - Migration plan documented (2400 lines → 1100 lines target) MIR & VM Improvements: - Enhanced modularized MIR builder structure - Added BoxCall dispatch improvements - Better separation in builder modules Documentation Updates: - Added Phase 9.79a unified box dispatch plan - Created plugin loader migration plan - Updated CURRENT_TASK.md with latest progress All tests passing (180 tests) - ready for next phase of refactoring 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
786 lines
26 KiB
Markdown
786 lines
26 KiB
Markdown
# Nyash統一Box設計の深い分析と今後の方向性
|
||
Status: Research
|
||
Created: 2025-08-25
|
||
Priority: High
|
||
Related: Everything is Box哲学の実装レベルでの完全実現
|
||
|
||
## 現状の統一Box設計
|
||
|
||
### 3種類のBoxの存在
|
||
1. **ビルトインBox** - Rustで実装(StringBox, IntegerBox, ConsoleBox等)
|
||
2. **プラグインBox** - 動的ライブラリで提供(FileBox等の置き換え可能)
|
||
3. **ユーザー定義Box** - Nyashコードで定義(box Person等)
|
||
|
||
### 現在の統一アーキテクチャ
|
||
```
|
||
UnifiedBoxRegistry(統一レジストリ)
|
||
├── BuiltinBoxFactory(優先度1)
|
||
├── UserDefinedBoxFactory(優先度2)
|
||
└── PluginBoxFactory(優先度3)
|
||
```
|
||
|
||
### 統一の美しさ
|
||
|
||
1. **透過的な置き換え**
|
||
- 同じ名前のBoxをプラグインで上書き可能
|
||
- 実行時の動的切り替えも可能
|
||
|
||
2. **統一インターフェース**
|
||
```rust
|
||
pub trait BoxFactory: Send + Sync {
|
||
fn create_box(&self, name: &str, args: &[Box<dyn NyashBox>]) -> Result<Box<dyn NyashBox>, RuntimeError>;
|
||
fn box_types(&self) -> Vec<&str>;
|
||
fn supports_birth(&self) -> bool;
|
||
}
|
||
```
|
||
|
||
3. **優先順位システム**
|
||
- ビルトイン > ユーザー定義 > プラグイン
|
||
- 予約語保護(StringBox等は上書き不可)
|
||
|
||
## InstanceBoxによる完全統一
|
||
|
||
### 統一実装の核心
|
||
```rust
|
||
pub struct InstanceBox {
|
||
pub class_name: String, // "StringBox", "Person"等
|
||
pub inner_content: Option<Box<dyn NyashBox>>, // 内包Box(統一!)
|
||
pub fields_ng: Arc<Mutex<HashMap<String, NyashValue>>>,
|
||
pub methods: Arc<HashMap<String, ASTNode>>,
|
||
}
|
||
```
|
||
|
||
### 3つの形態を統一的に扱う
|
||
```rust
|
||
// ビルトイン
|
||
InstanceBox::from_any_box("StringBox", Box::new(StringBox::new("hello")))
|
||
|
||
// プラグイン
|
||
InstanceBox::from_any_box("FileBox", plugin_loader.create_box("FileBox"))
|
||
|
||
// ユーザー定義
|
||
InstanceBox::from_declaration("Person", vec!["name", "age"], methods)
|
||
```
|
||
|
||
## 基本メソッドの統一提案
|
||
|
||
### 問題点
|
||
- `toString()` → `to_string_box()` (Rustの命名規則で異なる)
|
||
- `type()` → `type_name()` (微妙に異なる)
|
||
- 各Boxで個別実装されていて統一感がない
|
||
|
||
### 解決案:NyashBoxトレイトにデフォルト実装
|
||
```rust
|
||
pub trait NyashBox: BoxCore + Debug {
|
||
// Nyash標準メソッド(デフォルト実装)
|
||
fn toString(&self) -> Box<dyn NyashBox> {
|
||
Box::new(StringBox::new(&self.to_string_box().value))
|
||
}
|
||
|
||
fn type(&self) -> Box<dyn NyashBox> {
|
||
Box::new(StringBox::new(self.type_name()))
|
||
}
|
||
|
||
fn equals(&self, other: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
|
||
Box::new(BoolBox::new(self.equals_internal(other.as_ref())))
|
||
}
|
||
|
||
fn clone(&self) -> Box<dyn NyashBox> {
|
||
self.clone_box()
|
||
}
|
||
}
|
||
```
|
||
|
||
### VMでの統一的な呼び出し
|
||
```rust
|
||
pub(super) fn call_box_method(&self, box_value: Box<dyn NyashBox>, method: &str, args: Vec<Box<dyn NyashBox>>) -> Result<Box<dyn NyashBox>, VMError> {
|
||
// 基本メソッドは全Boxで使える!
|
||
match method {
|
||
"toString" => Ok(box_value.toString()),
|
||
"type" => Ok(box_value.type()),
|
||
"equals" => Ok(box_value.equals(args[0].clone_or_share())),
|
||
"clone" => Ok(box_value.clone()),
|
||
_ => self.call_specific_method(box_value, method, args)
|
||
}
|
||
}
|
||
```
|
||
|
||
## Gemini先生からの提案(部分)
|
||
|
||
### 1. NyashValue Enumの導入
|
||
```rust
|
||
pub enum NyashValue {
|
||
// 即値(スタック上)
|
||
Void,
|
||
Bool(bool),
|
||
Integer(i64),
|
||
Float(f64),
|
||
|
||
// ヒープ上の不変値
|
||
String(Arc<String>),
|
||
|
||
// 複雑なオブジェクト
|
||
Object(Arc<NyashObject>),
|
||
}
|
||
```
|
||
|
||
**メリット**:
|
||
- 小さな値のヒープアロケーション回避
|
||
- パターンマッチによる高速ディスパッチ
|
||
- 型安全性の向上
|
||
|
||
### 2. トレイトの階層化
|
||
```rust
|
||
// 基本トレイト
|
||
pub trait NyashBox: Send + Sync + Debug {
|
||
fn to_string(&self) -> String;
|
||
fn type_name(&self) -> &'static str;
|
||
fn equals(&self, other: &dyn NyashBox) -> bool;
|
||
}
|
||
|
||
// 拡張トレイト
|
||
pub trait Comparable: NyashBox {
|
||
fn compare(&self, other: &dyn NyashBox) -> Option<Ordering>;
|
||
}
|
||
|
||
pub trait Arithmetic: NyashBox {
|
||
fn add(&self, other: &dyn NyashBox) -> Result<Box<dyn NyashBox>, String>;
|
||
}
|
||
```
|
||
|
||
### 3. メタプログラミング機能
|
||
```rust
|
||
pub trait BoxMetadata {
|
||
fn on_method_missing(&self, name: &str, args: &[NyashValue]) -> Option<NyashValue>;
|
||
fn on_field_access(&self, name: &str) -> Option<NyashValue>;
|
||
}
|
||
```
|
||
|
||
## 統一継承の実現
|
||
|
||
### ~~現在の課題~~ → 2025-08-25更新:すべて実装済み!
|
||
- ~~ビルトインBoxの継承ができない~~ → ✅ 実装済み!
|
||
- ~~プラグインBoxの継承も未実装~~ → ✅ 実装済み!
|
||
|
||
### 理想的な統一継承(すでに実現!)
|
||
```nyash
|
||
// すべて可能になった!
|
||
box MyString from StringBox { } // ビルトイン継承 ✅
|
||
box MyFile from FileBox { } // プラグイン継承 ✅
|
||
box Employee from Person { } // ユーザー定義継承 ✅
|
||
|
||
// 多重デリゲーションも可能!
|
||
box MultiChild from StringBox, IntegerBox { } // ✅
|
||
```
|
||
|
||
### 実際のコード例(動作確認済み)
|
||
```nyash
|
||
box EnhancedString from StringBox {
|
||
init { prefix, suffix }
|
||
|
||
birth(text) {
|
||
from StringBox.birth(text) // 透過的にpackに変換される
|
||
me.prefix = "【"
|
||
me.suffix = "】"
|
||
}
|
||
|
||
enhanced() {
|
||
return me.prefix + me.toString() + me.suffix + "✨"
|
||
}
|
||
}
|
||
```
|
||
|
||
## さらなる美化への道
|
||
|
||
### 1. パイプライン演算子
|
||
```nyash
|
||
// 現在
|
||
local result = str.substring(0, 5).toUpperCase().trim()
|
||
|
||
// パイプライン版
|
||
local result = str
|
||
|> substring(0, 5)
|
||
|> toUpperCase()
|
||
|> trim()
|
||
```
|
||
|
||
### 2. Box階層の整理
|
||
```
|
||
NyashBox (trait)
|
||
├── ValueBox (数値・文字列・真偽値)
|
||
│ ├── IntegerBox
|
||
│ ├── StringBox
|
||
│ └── BoolBox
|
||
├── ContainerBox (コレクション)
|
||
│ ├── ArrayBox
|
||
│ └── MapBox
|
||
├── IOBox (入出力)
|
||
│ ├── ConsoleBox
|
||
│ └── FileBox
|
||
└── ConcurrentBox (並行処理)
|
||
├── FutureBox
|
||
└── ChannelBox
|
||
```
|
||
|
||
### 3. エフェクトシステムの美化
|
||
```rust
|
||
impl ArrayBox {
|
||
#[effect(Pure)]
|
||
fn length(&self) -> IntegerBox { }
|
||
|
||
#[effect(State)]
|
||
fn push(&mut self, item: Box<dyn NyashBox>) { }
|
||
}
|
||
```
|
||
|
||
## 実装優先順位(80/20ルール)
|
||
|
||
### 今すぐやるべき(80%)
|
||
1. 基本メソッド(toString, type, equals, clone)の統一実装
|
||
2. VMでの統一的なメソッドディスパッチ
|
||
3. InstanceBoxのinner_content活用の徹底
|
||
|
||
### 後でじっくり(20%)
|
||
1. NyashValue enum導入によるパフォーマンス最適化
|
||
2. トレイト階層化による整理
|
||
3. パイプライン演算子の実装
|
||
4. メタプログラミング機能
|
||
5. 完全な統一継承システム
|
||
|
||
## まとめ
|
||
|
||
現在のNyashの統一Box設計は、すでに相当美しく実装されている。特に:
|
||
|
||
1. **UnifiedBoxRegistry**による透過的な管理
|
||
2. **優先順位システム**による明確な解決
|
||
3. **InstanceBox**による統一的な扱い
|
||
|
||
これらは「Everything is Box」哲学を実装レベルで体現している。
|
||
|
||
ユーザー定義Boxをビルトイン/プラグインBoxと完全に同じレベルで扱うことは、強引ではなく、むしろ設計として自然で美しい。この統一により、言語の一貫性と拡張性が大幅に向上する。
|
||
|
||
今後は、基本メソッドの統一実装から始めて、段階的により洗練された設計へと進化させていくのが良いだろう。
|
||
|
||
## 🚀 MIR/VM統一実装計画(2025-08-25追記)
|
||
|
||
### 📍 現状の課題
|
||
VMとMIRで、Box型によって異なる処理をしている:
|
||
|
||
```rust
|
||
// VMでの現状:InstanceBoxだけ特別扱い
|
||
if let Some(inst) = arc_box.as_any().downcast_ref::<InstanceBox>() {
|
||
// ユーザー定義Box → 関数呼び出しに変換
|
||
let func_name = format!("{}.{}/{}", inst.class_name, method, args.len());
|
||
} else {
|
||
// ビルトイン/プラグイン → 直接メソッド呼び出し
|
||
self.call_box_method(cloned_box, method, nyash_args)?
|
||
}
|
||
```
|
||
|
||
### 🎯 統一実装の提案
|
||
|
||
#### 1. 統一メソッドディスパッチインターフェース
|
||
```rust
|
||
pub trait UnifiedBox: NyashBox {
|
||
fn dispatch_method(&self, method: &str, args: Vec<Box<dyn NyashBox>>)
|
||
-> Result<Box<dyn NyashBox>, String> {
|
||
// デフォルト実装:既存のメソッド呼び出しを使用
|
||
self.call_method(method, args)
|
||
}
|
||
}
|
||
|
||
// InstanceBoxでのオーバーライド
|
||
impl UnifiedBox for InstanceBox {
|
||
fn dispatch_method(&self, method: &str, args: Vec<Box<dyn NyashBox>>)
|
||
-> Result<Box<dyn NyashBox>, String> {
|
||
// MIR関数へのリダイレクト
|
||
let func_name = format!("{}.{}/{}", self.class_name, method, args.len());
|
||
// VM経由で関数呼び出し
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. VMの簡素化
|
||
```rust
|
||
// 統一後:すべて同じ処理パス
|
||
let result = match &recv {
|
||
VMValue::BoxRef(arc_box) => {
|
||
arc_box.dispatch_method(method, nyash_args)?
|
||
}
|
||
_ => {
|
||
recv.to_nyash_box().dispatch_method(method, nyash_args)?
|
||
}
|
||
};
|
||
```
|
||
|
||
#### 3. MIRレベルでの統一
|
||
- `BoxCall`命令ですべてのBox型を統一的に処理
|
||
- 型による分岐や特殊処理を削除
|
||
- コンパイル時の最適化は維持
|
||
|
||
### 💎 期待される効果
|
||
|
||
1. **コードの簡素化**
|
||
- VM内の条件分岐削除で30%以上のコード削減
|
||
- 新Box型追加時の変更箇所が最小限に
|
||
|
||
2. **保守性の向上**
|
||
- Box型の実装詳細がVMから隠蔽される
|
||
- テストが書きやすくなる
|
||
|
||
3. **パフォーマンス**
|
||
- 統一的な最適化(メソッドキャッシュ等)が可能
|
||
- 仮想関数テーブルによる高速化の可能性
|
||
|
||
4. **美しさ**
|
||
- 「Everything is Box」が実装レベルでも完全に実現
|
||
- シンプルで理解しやすいコード
|
||
|
||
### 📅 実装ロードマップ
|
||
|
||
1. **Phase 1**: UnifiedBoxトレイトの導入(後方互換性を保ちながら)
|
||
2. **Phase 2**: VMでの統一ディスパッチ実装
|
||
3. **Phase 3**: MIRビルダーの簡素化
|
||
4. **Phase 4**: 旧実装の削除とクリーンアップ
|
||
|
||
### 🌟 最終的なビジョン
|
||
|
||
すべてのBox(ビルトイン、プラグイン、ユーザー定義)が完全に統一された世界:
|
||
- 同じインターフェース
|
||
- 同じ実行パス
|
||
- 同じ最適化機会
|
||
|
||
これこそが「Everything is Box」の究極の実現!
|
||
|
||
## 🔌 プラグインローダーv2との統合
|
||
|
||
### 現在のプラグインシステムとの関係
|
||
- プラグインローダーv2がすでに統一的なインターフェースを提供
|
||
- `extern_call`経由での統一的なアクセス
|
||
- UnifiedBoxトレイトとの相性は良好
|
||
|
||
### 統合のメリット
|
||
- プラグインBoxも`dispatch_method()`で統一処理
|
||
- ホットリロード時も透過的に動作
|
||
- FFI境界を意識しない実装
|
||
|
||
## 📊 パフォーマンス測定計画
|
||
|
||
### 現在のベースライン
|
||
- インタープリター基準で13.5倍高速化達成(VM実装)
|
||
- BoxCall命令の実行時間が全体の約30%
|
||
|
||
### 統一実装後の予測
|
||
- 条件分岐削減で5-10%の高速化期待
|
||
- メソッドキャッシュで追加20%改善の可能性
|
||
- 測定方法:`--benchmark --iterations 1000`で検証
|
||
|
||
## 🔄 移行時の互換性戦略
|
||
|
||
### 段階的移行計画
|
||
1. **Phase 1**: UnifiedBoxトレイトを追加(既存APIは維持)
|
||
2. **Phase 2**: 警告付きで旧API使用を通知
|
||
3. **Phase 3**: 内部実装を統一版に切り替え
|
||
4. **Phase 4**: 旧APIをdeprecated化
|
||
5. **Phase 5**: 完全削除(6ヶ月後)
|
||
|
||
### テスト戦略
|
||
- 既存の全E2Eテストが通ることを保証
|
||
- パフォーマンスリグレッションテスト追加
|
||
- プラグイン互換性テストスイート
|
||
|
||
## ⚡ JITコンパイラとの統合(Phase 9準備)
|
||
|
||
### 統一メソッドディスパッチの利点
|
||
- JITが最適化しやすい単純な呼び出しパターン
|
||
- インライン展開の機会増加
|
||
- 型情報を活用した特殊化
|
||
|
||
### 仮想関数テーブル(vtable)戦略
|
||
```rust
|
||
struct BoxVTable {
|
||
methods: HashMap<String, fn(&dyn NyashBox, Vec<Box<dyn NyashBox>>) -> Result<Box<dyn NyashBox>, String>>,
|
||
}
|
||
```
|
||
- 起動時に事前計算
|
||
- JITコンパイル時に直接参照
|
||
- キャッシュフレンドリーな配置
|
||
|
||
## 🔧 具体的な実装タスク(TODO)
|
||
|
||
### Phase 1: 基礎実装(1週間)
|
||
- [ ] UnifiedBoxトレイトの定義(src/box_trait.rs)
|
||
- [ ] StringBox, IntegerBox等への実装
|
||
- [ ] InstanceBoxへのdispatch_method実装
|
||
- [ ] 単体テストの作成
|
||
|
||
### Phase 2: VM統合(2週間)
|
||
- [ ] execute_boxcall()の簡素化
|
||
- [ ] InstanceBox特別扱いコードの削除
|
||
- [ ] VMValueとの統合
|
||
- [ ] E2Eテスト全パス確認
|
||
- [ ] ベンチマーク実行と比較
|
||
|
||
### Phase 3: 最適化(1週間)
|
||
- [ ] メソッドキャッシュ実装
|
||
- [ ] 頻出メソッドの特殊化
|
||
- [ ] vtable事前計算
|
||
- [ ] JIT統合準備
|
||
|
||
### Phase 4: クリーンアップ(3日)
|
||
- [ ] 旧実装コードの削除
|
||
- [ ] ドキュメント更新
|
||
- [ ] CHANGELOG記載
|
||
- [ ] マイグレーションガイド作成
|
||
|
||
### 検証項目
|
||
- [ ] 全Box型でtoString/type/equals/cloneが動作
|
||
- [ ] プラグインBoxの透過的な動作
|
||
- [ ] パフォーマンス改善の確認
|
||
- [ ] メモリ使用量の変化なし
|
||
|
||
## 🚀 究極の統一:ビルトインBox完全プラグイン化構想
|
||
|
||
### 現状の二重実装問題
|
||
- **plugin_loader.rs** (1217行) - ビルトインBoxの動的ライブラリ化
|
||
- **plugin_loader_v2.rs** (906行) - プラグインBoxシステム
|
||
- 合計2000行以上の重複!
|
||
|
||
### 完全プラグイン化の提案
|
||
|
||
#### すべてをプラグインに統一
|
||
```rust
|
||
// 現在
|
||
ビルトインFileBox → 静的リンク
|
||
プラグインFileBox → 動的ロード(.so)
|
||
|
||
// 統一後
|
||
すべてのBox → プラグイン(.so)として実装
|
||
```
|
||
|
||
#### コアBoxの自動ロード戦略
|
||
```rust
|
||
const CORE_BOXES: &[&str] = &[
|
||
"libnyash_string_box.so", // StringBox(必須)
|
||
"libnyash_integer_box.so", // IntegerBox(必須)
|
||
"libnyash_bool_box.so", // BoolBox(必須)
|
||
"libnyash_console_box.so", // ConsoleBox(print用)
|
||
];
|
||
|
||
// 起動時に自動ロード
|
||
fn init_core_boxes() {
|
||
for plugin in CORE_BOXES {
|
||
plugin_loader.load_required(plugin)
|
||
.expect("Core box loading failed");
|
||
}
|
||
}
|
||
```
|
||
|
||
### メリット
|
||
1. **コード削減**: plugin_loader.rs (1217行) を完全削除
|
||
2. **統一性**: Everything is Boxの究極の実現
|
||
3. **柔軟性**: StringBoxすら置き換え可能
|
||
4. **ビルド高速化**: 本体が軽量に
|
||
5. **配布の柔軟性**: 必要なBoxだけ選択可能
|
||
|
||
### 考慮事項
|
||
|
||
#### パフォーマンス
|
||
- FFI境界のオーバーヘッドは**ナノ秒レベル**
|
||
- 実用上の影響なし
|
||
|
||
#### デバッグの課題と対策
|
||
```rust
|
||
// 課題:エラー時のスタックトレース
|
||
thread 'main' panicked at 'FFI boundary: 0x7f8b2c001234'
|
||
|
||
// 対策1:プラグイン側でのロギング
|
||
#[no_mangle]
|
||
pub extern "C" fn box_method_toString() {
|
||
eprintln!("[StringBox::toString] called from {:?}", std::thread::current().id());
|
||
}
|
||
|
||
// 対策2:デバッグシンボル保持
|
||
cargo build --features debug-symbols
|
||
|
||
// 対策3:プラグイン単体テストの充実
|
||
#[test]
|
||
fn test_string_box_methods() { /* ... */ }
|
||
```
|
||
|
||
### 実装ロードマップ
|
||
1. **Phase A**: コアBoxのプラグイン化
|
||
- StringBox, IntegerBox, BoolBox, ConsoleBox
|
||
2. **Phase B**: 起動時自動ロード機構
|
||
3. **Phase C**: plugin_loader.rs削除
|
||
4. **Phase D**: ドキュメント・テスト整備
|
||
|
||
### 設定ファイル案
|
||
```toml
|
||
# ~/.nyash/config.toml
|
||
[plugins]
|
||
core_path = "./plugins/core/"
|
||
search_paths = ["./plugins", "/usr/lib/nyash/plugins"]
|
||
|
||
[core_boxes]
|
||
required = ["string", "integer", "bool", "console"]
|
||
optional = ["file", "math", "time"]
|
||
```
|
||
|
||
これにより、「Everything is Box」哲学が実装レベルでも完全に実現される!
|
||
|
||
## 🔍 統一デバッグインフラストラクチャ(2025-08-26追記)
|
||
|
||
### 📍 MIRレベルでの統一デバッグ実現
|
||
|
||
今までの議論で、MIRレベルでのデバッグ実装が最も理想的であることが判明しました。
|
||
Gemini先生とCodex先生の両方が同じ結論に達しました:**設計案2+3のハイブリッド**が最適解です。
|
||
|
||
#### 核心設計:メタデータ分離+プロファイリングAPI
|
||
|
||
```rust
|
||
// MIR本体はクリーンに保つ
|
||
pub struct MIRModule {
|
||
pub functions: HashMap<String, MIRFunction>,
|
||
pub constants: Vec<Constant>,
|
||
pub debug_info: Option<MIRDebugInfo>, // デバッグ時のみ生成
|
||
}
|
||
|
||
// 静的情報(設計案2)
|
||
pub struct MIRDebugInfo {
|
||
// ID→名前のマッピング(文字列を避けてIDベース)
|
||
pub type_table: HashMap<u16, BoxTypeDescriptor>, // TypeId → Box型情報
|
||
pub method_table: HashMap<u32, MethodInfo>, // MethodId → メソッド情報
|
||
pub site_table: HashMap<u32, SiteInfo>, // SiteId → 位置情報
|
||
pub source_map: HashMap<usize, SourceLocation>, // PC → ソース位置
|
||
}
|
||
|
||
// 動的収集(設計案3)
|
||
pub trait MIRProfiler: Send + Sync {
|
||
fn on_alloc(&mut self, type_id: u16, site_id: u32, obj_id: u64, size: usize);
|
||
fn on_free(&mut self, obj_id: u64);
|
||
fn on_method_enter(&mut self, method_id: u32, site_id: u32, instance_id: u64);
|
||
fn on_method_exit(&mut self, method_id: u32, site_id: u32, result: &VMValue);
|
||
fn on_field_access(&mut self, obj_id: u64, field_id: u16, is_write: bool);
|
||
}
|
||
```
|
||
|
||
#### なぜこの設計が美しいのか?
|
||
|
||
1. **MIRの純粋性を保つ** - デバッグ命令でIRを汚染しない
|
||
2. **ゼロオーバーヘッド** - 本番ビルドではdebug_info = None
|
||
3. **全バックエンド統一** - VM/JIT/AOT/WASMで同じプロファイラAPI
|
||
4. **業界標準に準拠** - LLVM、JVM、.NETと同じアプローチ
|
||
|
||
### 🧠 DeepInspectorBox - 統一デバッグ体験
|
||
|
||
#### Everything is Boxの哲学をデバッグでも実現
|
||
|
||
```nyash
|
||
// グローバルシングルトン - すべてを見通す眼
|
||
static box DeepInspectorBox {
|
||
init {
|
||
enabled, // デバッグON/OFF
|
||
boxCreations, // すべてのBox生成履歴
|
||
methodCalls, // すべてのメソッド呼び出し
|
||
fieldAccess, // フィールドアクセス履歴
|
||
memorySnapshots, // メモリスナップショット
|
||
referenceGraph, // 参照グラフ(リーク検出用)
|
||
performanceMetrics // パフォーマンス統計
|
||
}
|
||
|
||
// === Box ライフサイクル完全追跡 ===
|
||
trackBoxLifecycle(boxType) {
|
||
// 特定のBox型の生成から破棄まで完全追跡
|
||
return me.boxCreations.filter(b => b.type == boxType)
|
||
}
|
||
|
||
// === メモリリーク検出(深い実装) ===
|
||
detectLeaks() {
|
||
// 参照グラフの構築
|
||
local graph = me.buildReferenceGraph()
|
||
|
||
// 循環参照の検出
|
||
local cycles = graph.findCycles()
|
||
|
||
// 到達不可能なBoxの検出
|
||
local unreachable = graph.findUnreachableFrom(me.getRootBoxes())
|
||
|
||
// weak参照の考慮
|
||
local suspicious = me.findSuspiciousWeakReferences()
|
||
|
||
return LeakReport {
|
||
cycles: cycles,
|
||
unreachable: unreachable,
|
||
suspicious: suspicious,
|
||
totalLeakedBytes: me.calculateLeakedMemory()
|
||
}
|
||
}
|
||
|
||
// === P2P非同期フロー可視化 ===
|
||
traceAsyncFlow(startEvent) {
|
||
// P2Pメッセージの送信から受信、ハンドラー実行までの完全追跡
|
||
local flow = []
|
||
|
||
// 送信イベント
|
||
flow.push(startEvent)
|
||
|
||
// Transport経由の転送
|
||
local transportEvents = me.findTransportEvents(startEvent.messageId)
|
||
flow.extend(transportEvents)
|
||
|
||
// MethodBox.invoke()の実行
|
||
local handlerExecution = me.findHandlerExecution(startEvent.to, startEvent.intent)
|
||
flow.push(handlerExecution)
|
||
|
||
return AsyncFlowTrace {
|
||
events: flow,
|
||
totalTime: flow.last().time - flow.first().time,
|
||
visualization: me.generateFlowDiagram(flow)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 🔬 メモリリーク検出の深い仕組み
|
||
|
||
#### 参照グラフベースの完全検出
|
||
|
||
```rust
|
||
impl DeepInspectorBox {
|
||
/// 参照グラフの構築(UnifiedBox設計と統合)
|
||
fn build_reference_graph(&self) -> ReferenceGraph {
|
||
let mut graph = ReferenceGraph::new();
|
||
|
||
// すべてのBoxを走査(ビルトイン/プラグイン/ユーザー定義を統一的に)
|
||
for (obj_id, box_info) in &self.live_boxes {
|
||
match box_info.content {
|
||
// InstanceBoxのフィールド参照
|
||
BoxContent::Instance(fields) => {
|
||
for (field_name, field_value) in fields {
|
||
if let Some(target_id) = field_value.get_box_id() {
|
||
graph.add_edge(*obj_id, target_id, EdgeType::Field(field_name));
|
||
}
|
||
}
|
||
}
|
||
|
||
// MethodBoxのインスタンス参照
|
||
BoxContent::Method { instance_id, .. } => {
|
||
graph.add_edge(*obj_id, instance_id, EdgeType::MethodInstance);
|
||
}
|
||
|
||
// P2PBoxのハンドラー参照
|
||
BoxContent::P2P { handlers, .. } => {
|
||
for (intent, handler_id) in handlers {
|
||
graph.add_edge(*obj_id, handler_id, EdgeType::Handler(intent));
|
||
}
|
||
}
|
||
|
||
// ArrayBox/MapBoxの要素参照
|
||
BoxContent::Container(elements) => {
|
||
for (index, element_id) in elements.iter().enumerate() {
|
||
graph.add_edge(*obj_id, element_id, EdgeType::Element(index));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
graph
|
||
}
|
||
|
||
/// 高度なリーク検出アルゴリズム
|
||
fn detect_leak_patterns(&self, graph: &ReferenceGraph) -> Vec<LeakPattern> {
|
||
let mut patterns = vec![];
|
||
|
||
// Pattern 1: 単純な循環参照
|
||
let cycles = graph.tarjan_scc();
|
||
for cycle in cycles {
|
||
if cycle.len() > 1 {
|
||
patterns.push(LeakPattern::CircularReference(cycle));
|
||
}
|
||
}
|
||
|
||
// Pattern 2: イベントハンドラーリーク(P2P特有)
|
||
for (node_id, node_info) in &self.p2p_nodes {
|
||
for (intent, handler) in &node_info.handlers {
|
||
if let Some(method_box) = handler.as_method_box() {
|
||
let instance_id = method_box.get_instance_id();
|
||
if !self.is_box_alive(instance_id) {
|
||
patterns.push(LeakPattern::DanglingHandler {
|
||
node: node_id.clone(),
|
||
intent: intent.clone(),
|
||
dead_instance: instance_id,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Pattern 3: 巨大オブジェクトグラフ
|
||
let subgraphs = graph.find_connected_components();
|
||
for subgraph in subgraphs {
|
||
let total_size = subgraph.iter()
|
||
.map(|id| self.get_box_size(*id))
|
||
.sum::<usize>();
|
||
|
||
if total_size > SUSPICIOUS_GRAPH_SIZE {
|
||
patterns.push(LeakPattern::LargeObjectGraph {
|
||
root: subgraph[0],
|
||
size: total_size,
|
||
object_count: subgraph.len(),
|
||
});
|
||
}
|
||
}
|
||
|
||
patterns
|
||
}
|
||
}
|
||
```
|
||
|
||
### 🚀 実装ロードマップ(2025年後半)
|
||
|
||
#### Phase 1: MIRデバッグ基盤(2週間)
|
||
- [ ] MIRDebugInfo構造の実装
|
||
- [ ] MIRProfilerトレイトの定義
|
||
- [ ] MIRビルダーでのデバッグ情報生成
|
||
|
||
#### Phase 2: VMプロファイラー統合(1週間)
|
||
- [ ] VMでのMIRProfiler実装
|
||
- [ ] DeepInspectorBoxのVM連携
|
||
- [ ] 基本的なメモリリーク検出
|
||
|
||
#### Phase 3: 非同期フロー可視化(1週間)
|
||
- [ ] P2Pメッセージトレース
|
||
- [ ] MethodBox実行追跡
|
||
- [ ] タイミング図の生成
|
||
|
||
#### Phase 4: WASM対応(2週間)
|
||
- [ ] nyash_debugインポートの実装
|
||
- [ ] カスタムセクションへのデバッグ情報埋め込み
|
||
- [ ] ブラウザ開発ツール連携
|
||
|
||
#### Phase 5: パフォーマンス最適化(1週間)
|
||
- [ ] ロックフリーリングバッファ
|
||
- [ ] サンプリングモード
|
||
- [ ] 増分参照グラフ更新
|
||
|
||
### 💎 統一の美しさ
|
||
|
||
この設計により、以下が実現されます:
|
||
|
||
1. **完全な可視性** - Boxの生成から破棄、メソッド呼び出し、フィールドアクセスまですべて追跡
|
||
2. **メモリ安全性の保証** - リークパターンの自動検出と可視化
|
||
3. **非同期フローの理解** - P2Pメッセージングの複雑な流れを完全に把握
|
||
4. **統一された体験** - VM/JIT/AOT/WASMすべてで同じデバッグ機能
|
||
5. **Nyashらしさ** - DeepInspectorBox自体もBoxとして実装
|
||
|
||
「Everything is Box」の哲学は、デバッグインフラストラクチャにおいても完全に実現されることになります。
|
||
|
||
### 🔮 将来の拡張可能性
|
||
|
||
- **AI支援デバッグ** - パターン認識によるバグの自動検出
|
||
- **時間遡行デバッグ** - 実行履歴の巻き戻しと再実行
|
||
- **分散トレーシング** - 複数ノード間のP2P通信の可視化
|
||
- **パフォーマンスAI** - ボトルネックの自動最適化提案
|
||
|
||
これらすべてが、統一されたMIRデバッグ基盤の上に構築可能です。 |