Phase 12: 統一TypeBox ABI実装開始 - ChatGPT5による極小コアABI基盤構築
- TypeBox ABI雛形: メソッドスロット管理システム追加 - Type Registry: Array/Map/StringBoxの基本メソッド定義 - Host API: C ABI逆呼び出しシステム実装 - Phase 12ドキュメント整理: 設計文書統合・アーカイブ化 - MIR Builder: クリーンアップと分離実装完了 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -0,0 +1,87 @@
|
||||
# Nyash ABI戦略議論まとめ (2025-09-01)
|
||||
|
||||
## 📋 概要
|
||||
|
||||
Phase 12のプラグインシステム実装において、C ABIとNyash ABIの選択について、AI先生方と深い技術議論を行いました。
|
||||
|
||||
## 🗂️ ドキュメント一覧
|
||||
|
||||
1. **[gemini-abi-analysis.md](gemini-abi-analysis.md)**
|
||||
- Gemini先生の長期エコシステム視点
|
||||
- ABI安定性の重要性
|
||||
- 段階的進化戦略(C ABI → SDK → WASM)
|
||||
|
||||
2. **[codex-abi-implementation.md](codex-abi-implementation.md)**
|
||||
- Codex先生の実装最適化視点
|
||||
- C呼出規約×Nyash値表現の提案
|
||||
- VM/JIT最適化の具体策
|
||||
|
||||
3. **[deep-analysis-synthesis.md](deep-analysis-synthesis.md)**
|
||||
- なぜ正解が難しいのかの深い分析
|
||||
- 時間軸のジレンマ
|
||||
- 「正解がない」ことが答え
|
||||
|
||||
## 🎯 結論:BoxCall拡張による統合案
|
||||
|
||||
### 最終的な実装方針
|
||||
|
||||
```rust
|
||||
// MIRレベル:BoxCallをちょっと拡張
|
||||
MirInstruction::BoxCall {
|
||||
receiver: Value,
|
||||
method: String,
|
||||
args: Vec<Value>,
|
||||
abi_hint: Option<AbiType>, // ← これだけ追加
|
||||
}
|
||||
```
|
||||
|
||||
### 利点
|
||||
|
||||
1. **MIR命令数は15個のまま**(美しさ維持)
|
||||
2. **既存コードは変更不要**(後方互換)
|
||||
3. **プラグインごとにABI選択可能**(段階的移行)
|
||||
4. **Everything is Box哲学の体現**
|
||||
|
||||
### 実装計画
|
||||
|
||||
```yaml
|
||||
Week 1: 基盤整備
|
||||
- PluginABI enum定義
|
||||
- nyash.tomlのabi field追加
|
||||
- NyashValue構造体作成
|
||||
|
||||
Week 2: VM統合
|
||||
- プラグインローダー拡張
|
||||
- VM実行時のABI分岐
|
||||
- pack/unpack実装
|
||||
|
||||
Week 3: 検証
|
||||
- 比較ベンチマーク
|
||||
- ドキュメント作成
|
||||
- 方向性判断
|
||||
```
|
||||
|
||||
## 🔑 重要な洞察
|
||||
|
||||
1. **両ABI共存が現実的**
|
||||
- C ABI:既存資産・高速・安定
|
||||
- Nyash ABI:型安全・拡張性・将来性
|
||||
|
||||
2. **適応的戦略の採用**
|
||||
- 3ヶ月ごとに測定・評価
|
||||
- データに基づく進化
|
||||
|
||||
3. **箱理論による差し替え可能性**
|
||||
- 実装を箱に切り出す
|
||||
- いつでも戻せる安心感
|
||||
|
||||
## 📊 次のステップ
|
||||
|
||||
1. このREADMEを起点に実装開始
|
||||
2. 最小限のプロトタイプ作成
|
||||
3. 性能・開発体験の比較データ収集
|
||||
4. Phase 12本実装への反映
|
||||
|
||||
---
|
||||
|
||||
*「間に挟むだけ」が最も難しい設計判断だった。しかし、BoxCall拡張という自然な解決策にたどり着いた。*
|
||||
@ -0,0 +1,124 @@
|
||||
# Codex先生のNyash ABI実装戦略 (2025-09-01)
|
||||
|
||||
## 質問内容
|
||||
|
||||
Nyashプラグインシステムの ABI戦略について技術的相談です。
|
||||
|
||||
【背景】
|
||||
Phase 12でNyashスクリプトプラグインシステムを実装中です。現在、プラグインインターフェースの設計で重要な判断が必要です。
|
||||
|
||||
【現状】
|
||||
- 既存: C ABI(シンプル、高速、実績あり)
|
||||
- 提案: Nyash ABI(3×u64構造体、型情報付き、拡張性高い)
|
||||
|
||||
【トレードオフ】
|
||||
C ABI:
|
||||
- 利点: ゼロオーバーヘッド、既存資産活用、シンプル
|
||||
- 欠点: 型情報なし、拡張性限定、エラー処理が原始的
|
||||
|
||||
Nyash ABI:
|
||||
- 利点: 型安全、メタデータ活用、将来性(async等)
|
||||
- 欠点: pack/unpackのオーバーヘッド、新規学習コスト
|
||||
|
||||
【具体的な選択肢】
|
||||
1. Nyash ABIのみ(統一性重視)
|
||||
2. C ABI + Nyash ABI両方(実用性重視)
|
||||
3. その他の革新的アプローチ?
|
||||
|
||||
【質問】
|
||||
1. どちらの戦略が長期的に見て賢明でしょうか?
|
||||
2. 両方サポートする場合の複雑性は管理可能でしょうか?
|
||||
3. 他の言語での成功例・失敗例から学べることは?
|
||||
4. VM/JIT最適化の観点から、どちらが有利でしょうか?
|
||||
|
||||
実装の実践的観点から、C ABIとNyash ABIの選択について深く分析してください。特にVM/JIT最適化や実装の複雑性を考慮して。
|
||||
|
||||
## Codex先生の回答
|
||||
|
||||
**結論**
|
||||
- 長期的には「C呼出規約 × Nyash値表現(3×u64)」を中核に、C ABIとNyash ABIの両方をサポートする二層戦略が最も堅実。
|
||||
- まずは二者併存で運用し、JIT/VMでの最適化余地と実用性を確保しながら、将来的にNyash ABIを第一級に育てるのが現実的。
|
||||
|
||||
**推奨戦略**
|
||||
- 両対応(2)を採用。ただし"呼出規約はC、値表現はNyash"を共通土台にする。
|
||||
- 共通の値ABI: `#[repr(C)] struct NyValue { u64 tag; u64 payload; u64 aux; }`
|
||||
- C ABI関数でもNyValueを受け渡しできるため、型安全・メタデータ拡張の道を確保しつつ、Cの安定性・高速性を得る。
|
||||
- プラグイン初期化は「バージョン付き関数テーブル(vtable)+機能フラグ」の交渉型にする。
|
||||
- 例: `NyPluginInitV1(NyRtFnsV1* rt, NyPluginV1* out)` → `NyPluginV1 { u32 abi_mask; u32 size; NyFnDesc* fns; ... }`
|
||||
- `abi_mask`で `NY_ABI_C` と `NY_ABI_NYV1` の両方可否を示す。将来の `NY_ABI_NYV2` も追加可能。
|
||||
- エラーモデルは二段階:
|
||||
- 速経路: `NyStatus`(enum, small int)を戻す。失敗時は`NyValue`でエラーオブジェクトをout-param返却。
|
||||
- 詳細情報は`NyError`ヘルパ(`NyValue`として表現)に格納。FFI境界でpanic禁止・例外横断なし。
|
||||
- メモリ/所有権はハンドル/関数テーブル経由で統一(NyRTのalloc/free、string/slice作成API)。内部構造体への直接依存は不可。
|
||||
|
||||
**複雑性と管理**
|
||||
- 追加コストは主にローダとアダプタ(トランポリン)実装+テスト行列の増加。ただし次の工夫で管理可能:
|
||||
- 機能交渉を一本化(init関数とマニフェスト/nyash.tomlで表明)。ロード時に一度だけ決定。
|
||||
- 呼出アダプタをテンプレート化/JIT時に生成・キャッシュ(型配列→シグネチャ→thunkアドレス)。
|
||||
- 型表(`NyFnDesc`に引数/戻りの型ID配列、純関数/readonly/aliasing属性)を持ち、最適化と検証を兼用。
|
||||
- 見積り:ローダ+vtable+アダプタの骨格は数百行〜千行弱で収まり、以降は関数種別追加が足し算。
|
||||
|
||||
**他言語の事例からの学び**
|
||||
- 成功例
|
||||
- Node N-API: バージョン化された関数テーブルでABIを安定化。実装側の進化と互換の両立に有効。
|
||||
- Lua C API: C呼出規約+独自値表現で長期安定。ただしstackベースは学習コストあり。
|
||||
- 反省点
|
||||
- CPython C API: 内部構造体露出で進化の足枷に。HPyはハンドル化で再設計。
|
||||
- JNI: 汎用だが冗長・低速傾向。最適化しづらい。
|
||||
- 教訓
|
||||
- 内部レイアウト非公開(ハンドル/関数経由)・バージョン化vtable・拡張フラグが長期安定の鍵。
|
||||
- 値ABIは固定サイズ・レジスタ渡し最適化可能な形が吉(3×u64は合理的)。
|
||||
|
||||
**VM/JIT最適化の観点**
|
||||
- 呼出オーバーヘッド
|
||||
- 3×u64はSysV/Win64いずれもレジスタ渡しが効きやすく、C ABIと同等のコールコストに収束。
|
||||
- 本質的ボトルネックは間接呼出ミス予測と型検査。JITで型が既知ならチェックを埋め込み/削減可能。
|
||||
- 直呼 vs トランポリン
|
||||
- 署名が一致する場合は直接呼出(JITに外部シンボルとして登録)。
|
||||
- 型昇降/借用が必要な時のみthunkを噛ませる。JITでモノモーフィック化・デッドパス除去。
|
||||
- 最適化ヒント(Cranelift/LLVM)
|
||||
- 関数属性: `nounwind`, `readonly`/`readnone`, `nocapture`, `nonnull`, `cold`(エラーパス)
|
||||
- 戻り値はout-paramにしてtailcall最適化(`musttail`適用可否は要検証)。
|
||||
- シンボルはAOT時`dso_local`、JITは`CallConv::SystemV/WindowsFast`で3×i64に整合。
|
||||
- ホットループ対策
|
||||
- スカラー跨ぎは避け、スライス/バルクAPIを定義(例: vector add)。boundary跨ぎ回数を削減。
|
||||
- 将来は静的リンクモード(first-party plugins)でLTO許可→AOTでインライン・DCE可。
|
||||
|
||||
**Nyash ABIのみ vs 併存の比較**
|
||||
- Nyash ABIのみ(1)
|
||||
- 一貫性と将来性は高いが、既存C資産/ツール連携コストと立上げ摩擦が大きい。
|
||||
- 併存(2, 推奨)
|
||||
- 早期エコシステム拡大と最適化の両取り。複雑性はvtable+アダプタの設計で抑え込み可能。
|
||||
- その他(3)
|
||||
- N-API風ハンドル専一は安定するが、オーバーヘッド/冗長性が増える。Nyashのパフォーマンス志向には過剰。
|
||||
|
||||
**実装メモ(具体)**
|
||||
- 値ABI
|
||||
- `tag`: 上位ビットに種別・フラグ(own/borrow、small/heap、nullable等)
|
||||
- `payload`: ポインタor即値、`aux`: len/stride/arena_id等
|
||||
- `NySlice`: `tag=SLICE`で`payload=ptr`, `aux=len`。borrow時は生存期間制約、必要なら`nyrt_clone_slice`で所有権取得。
|
||||
- 初期化/交渉
|
||||
- `NyPluginInitV1(NyRtFnsV1*, NyPluginV1*) -> NyStatus`
|
||||
- `NyRtFnsV1`: alloc/free、string/slice/future、log、error造作API。
|
||||
- `NyPluginV1`: `abi_mask`, `size`, `features`, `fn_count`, `NyFnDesc*`.
|
||||
- エラー/非同期
|
||||
- `NyStatus` + `NyValue err_out`。非同期は `NyFuture*`を返却、`NyRtFnsV1`で`poll/wake`を橋渡し。
|
||||
- VMのスケジューラとWakerのブリッジはvtableで隠蔽(ABI非依存)。
|
||||
- 安定性
|
||||
- すべての公開構造体に`size`を先頭フィールドに持たせ将来拡張。未理解フィールドは無視。
|
||||
- ABIバージョンは数値+機能フラグで条件分岐(ビルド時にも`#[cfg(feature)]`で絞る)。
|
||||
|
||||
**質問への回答**
|
||||
- 1) 長期的に賢明か: 併存+共通値ABIが最善。Cの互換性とNyashの型安全/拡張性を両立。
|
||||
- 2) 複雑性は管理可能か: はい。vtableの一本化、JIT生成thunk、機能交渉で抑制できる。
|
||||
- 3) 学び: 内部構造体を外部に晒さない・ハンドル経由・バージョン化テーブル・豊富な属性メタデータ。CPythonの反省とN-APIの成功を取り込む。
|
||||
- 4) VM/JIT最適化: 3×u64のNyash値はレジスタ渡しでC ABIと同等に速く、型既知箇所はJITで直呼/チェック省略可能。最適化の自由度はNyash ABIの方が高い。
|
||||
|
||||
**次のアクション**
|
||||
- 値ABIと関数テーブル仕様を`crates/nyrt/include/nyrt.h`に最小ドラフト化(`NyValue`, `NyStatus`, `NyRtFnsV1`, `NyPluginV1`, `NyFnDesc`)。
|
||||
- ローダにinit/交渉実装(`nyash.toml`のabi種別・型情報読み込み→関数登録)。
|
||||
- JIT/VMに外部関数署名登録とthunk生成を追加(Cranelift/LLVM兼用)。
|
||||
- バルク演算プラグインのスモークを作成(C ABI版とNyash ABI版を比較ベンチ)。
|
||||
- ドキュメント化(`docs/plugins/abi.md`)とサンプル(`plugins/`、`apps/`)追加。
|
||||
|
||||
必要なら、ドラフトの`NyValue`と`NyPluginInitV1`の最小Cヘッダ案もすぐ出します。
|
||||
@ -0,0 +1,188 @@
|
||||
# Codex先生のBoxCall拡張分析 (2025-09-01)
|
||||
|
||||
## 質問内容
|
||||
|
||||
Nyash ABI実装の具体的アプローチについて技術相談です。
|
||||
|
||||
【背景】
|
||||
前回の議論で、C ABIとNyash ABIの両方をサポートする方向性が見えました。実装方法について新しいアイデアがあります。
|
||||
|
||||
【BoxCall拡張による統合案】
|
||||
MIR命令を増やさず、既存のBoxCallを自然に拡張する案です:
|
||||
|
||||
```rust
|
||||
// 現在のBoxCall
|
||||
MirInstruction::BoxCall {
|
||||
receiver: Value,
|
||||
method: String,
|
||||
args: Vec<Value>,
|
||||
}
|
||||
|
||||
// 提案:最小限の拡張
|
||||
MirInstruction::BoxCall {
|
||||
receiver: Value,
|
||||
method: String,
|
||||
args: Vec<Value>,
|
||||
abi_hint: Option<AbiType>, // 追加
|
||||
}
|
||||
```
|
||||
|
||||
【実装の流れ】
|
||||
1. MIRビルダー:プラグインBoxならABIヒント付与
|
||||
2. VM実行時:receiver.type_idから適切なABI選択
|
||||
3. プラグインローダー:nyash.tomlでABI指定可能
|
||||
|
||||
【この案の利点】
|
||||
- MIR命令数は15個維持(Everything is Box哲学)
|
||||
- 既存コード無変更(後方互換)
|
||||
- プラグインごとに段階的移行可能
|
||||
- JITでABI別最適化も可能
|
||||
|
||||
【質問】
|
||||
1. このBoxCall拡張案は設計として健全でしょうか?
|
||||
2. abi_hintは本当に必要?VM実行時の型判定で十分?
|
||||
3. 将来的な拡張(WASM等)にも対応できる設計か?
|
||||
4. パフォーマンス影響をどう評価すべきか?
|
||||
|
||||
実装の観点から、MIR層でのabi_hint追加とVM層でのABI判定について深く分析してください。特に既存実装への影響を最小化する方法を考慮して。
|
||||
|
||||
## Codex先生の回答
|
||||
|
||||
### コードベース分析
|
||||
|
||||
まず、現在のMIR/VM実装を確認:
|
||||
|
||||
```rust
|
||||
// 現在のMirInstruction::BoxCall定義
|
||||
BoxCall {
|
||||
dst: Option<ValueId>,
|
||||
box_val: ValueId,
|
||||
method: String,
|
||||
method_id: Option<u16>, // Universal method用
|
||||
args: Vec<ValueId>,
|
||||
effects: EffectMask,
|
||||
}
|
||||
```
|
||||
|
||||
プラグインローダーはすでにnyash.tomlから型情報を読み込んでおり、VM実行時に利用可能。
|
||||
|
||||
### 核心的な洞察
|
||||
|
||||
**abi_hintは実は不要かもしれない!**
|
||||
|
||||
理由:
|
||||
1. VM実行時にreceiver.type_idから型情報を取得可能
|
||||
2. プラグインローダーが既にABI情報を保持している
|
||||
3. MIR層を変更せずに済む(15命令維持)
|
||||
|
||||
### 実装提案
|
||||
|
||||
#### Option A: 最小限実装(MIR無変更)
|
||||
|
||||
```rust
|
||||
// VM層での実装
|
||||
fn execute_boxcall(&mut self, dst: Option<ValueId>, box_val: ValueId, method: &str, args: &[ValueId]) -> Result<ControlFlow, VMError> {
|
||||
let receiver = self.get_value(box_val)?;
|
||||
let type_id = receiver.get_type_id();
|
||||
|
||||
// プラグインローダーから型情報取得
|
||||
if let Some(plugin_info) = self.runtime.get_plugin_info(type_id) {
|
||||
match plugin_info.abi.as_str() {
|
||||
"c" => self.call_c_abi_plugin(plugin_info, method, args),
|
||||
"nyash" => self.call_nyash_abi_plugin(plugin_info, method, args),
|
||||
_ => self.call_c_abi_plugin(plugin_info, method, args), // fallback
|
||||
}
|
||||
} else {
|
||||
// ビルトインBox処理(既存のまま)
|
||||
self.execute_builtin_method(receiver, method, args)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Option B: 将来の拡張性を考慮
|
||||
|
||||
```rust
|
||||
// MIRに汎用メタデータ追加(ABIに限定しない)
|
||||
MirInstruction::BoxCall {
|
||||
receiver: Value,
|
||||
method: String,
|
||||
args: Vec<Value>,
|
||||
metadata: Option<u32>, // 汎用的な最適化ヒント
|
||||
}
|
||||
```
|
||||
|
||||
### JIT/AOT最適化の観点
|
||||
|
||||
```rust
|
||||
// JIT時の特化
|
||||
match type_info.abi {
|
||||
Some("c") => {
|
||||
// 直接call命令生成
|
||||
builder.emit_direct_call(symbol, args);
|
||||
}
|
||||
Some("nyash") => {
|
||||
// NyashValue pack/unpackを含めてインライン化
|
||||
let packed = builder.emit_pack_nyash_values(args);
|
||||
builder.emit_call_with_abi(symbol, packed);
|
||||
}
|
||||
_ => {
|
||||
// 汎用パス(VM呼び出し)
|
||||
builder.emit_vm_boxcall(receiver, method, args);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### パフォーマンス評価方法
|
||||
|
||||
```rust
|
||||
// ベンチマーク設計
|
||||
fn benchmark_abi_comparison() {
|
||||
// 1. 高頻度呼び出し(math operations)
|
||||
measure_time("C ABI", || {
|
||||
for _ in 0..1_000_000 {
|
||||
math_add_c_abi(1.0, 2.0);
|
||||
}
|
||||
});
|
||||
|
||||
measure_time("Nyash ABI", || {
|
||||
for _ in 0..1_000_000 {
|
||||
math_add_nyash_abi(pack(1.0), pack(2.0));
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 複雑な型(string operations)
|
||||
// 3. プラグイン初期化コスト
|
||||
}
|
||||
```
|
||||
|
||||
### 結論と推奨事項
|
||||
|
||||
1. **abi_hintは不要** - VM実行時の型判定で十分
|
||||
2. **MIR層は無変更** - 15命令の美しさ維持
|
||||
3. **将来拡張は型システム経由** - WASMもプラグイン型として追加
|
||||
4. **段階的実装**:
|
||||
- Week 1: nyash.toml拡張 + VM分岐
|
||||
- Week 2: ベンチマーク + 最適化
|
||||
- Week 3: JIT特化(必要なら)
|
||||
|
||||
### 実装の具体的ステップ
|
||||
|
||||
```yaml
|
||||
Step 1: nyash.toml拡張
|
||||
- LibraryDefinition に abi: Option<String> 追加
|
||||
- デフォルトは "c"
|
||||
|
||||
Step 2: プラグインローダー
|
||||
- PluginInfo 構造体に abi フィールド追加
|
||||
- ロード時に保存
|
||||
|
||||
Step 3: VM execute_boxcall
|
||||
- 型判定でABI分岐
|
||||
- call_c_abi / call_nyash_abi メソッド追加
|
||||
|
||||
Step 4: テスト
|
||||
- 同一機能の C/Nyash 両実装
|
||||
- 性能比較測定
|
||||
```
|
||||
|
||||
この最小限アプローチなら、既存コードへの影響を最小化しつつ、将来の拡張性も確保できます。
|
||||
@ -0,0 +1,164 @@
|
||||
# Nyash ABI戦略の深い分析 - なぜ正解が難しいのか (2025-09-01)
|
||||
|
||||
## 🤔 両先生の回答から見えた根本的な難しさ
|
||||
|
||||
### 1. 時間軸のジレンマ
|
||||
|
||||
**Gemini先生の視点**(長期エコシステム):
|
||||
- 10年後も動くプラグインを作りたい
|
||||
- 破壊的変更は絶対避けたい
|
||||
- 開発者の信頼が最重要
|
||||
|
||||
**Codex先生の視点**(現実的最適化):
|
||||
- 今すぐ高速に動かしたい
|
||||
- JIT/VMの最適化余地を残したい
|
||||
- 実装の複雑性を抑えたい
|
||||
|
||||
→ **この2つは本質的に矛盾する!**
|
||||
|
||||
### 2. 抽象化レベルの選択
|
||||
|
||||
```
|
||||
高レベル抽象化(Gemini案)
|
||||
↑
|
||||
SDK層
|
||||
↑
|
||||
C ABI(安定境界)
|
||||
|
||||
vs
|
||||
|
||||
低レベル統合(Codex案)
|
||||
↓
|
||||
共通値表現(3×u64)
|
||||
↓
|
||||
C呼出規約で統一
|
||||
```
|
||||
|
||||
どちらが正解? **状況による!**
|
||||
|
||||
### 3. 隠れた複雑性の罠
|
||||
|
||||
**表面的には単純に見える選択**:
|
||||
- C ABI only → シンプル!
|
||||
- Nyash ABI only → 統一的!
|
||||
- 両方サポート → 柔軟!
|
||||
|
||||
**実際の複雑さ**:
|
||||
- C ABI only → 型情報なし、拡張困難
|
||||
- Nyash ABI only → 既存資産切り捨て
|
||||
- 両方サポート → **複雑性が2倍...ではなく4倍!**
|
||||
|
||||
### 4. なぜ複雑性が爆発するのか
|
||||
|
||||
```
|
||||
組み合わせ爆発:
|
||||
- 2つのABI ×
|
||||
- 3つのバックエンド(Interpreter/VM/JIT) ×
|
||||
- N個のプラグイン型 ×
|
||||
- M個の最適化レベル
|
||||
= 指数関数的複雑性
|
||||
```
|
||||
|
||||
## 🎯 深い洞察:本当の問題は何か
|
||||
|
||||
### 技術的正解 vs ビジネス的正解
|
||||
|
||||
**技術的に美しい解**:
|
||||
- Nyash ABI一本化
|
||||
- 型安全、拡張可能、統一的
|
||||
|
||||
**ビジネス的に賢い解**:
|
||||
- C ABI + 段階的移行
|
||||
- 既存資産活用、リスク分散
|
||||
|
||||
→ **どちらも「正解」であり「不正解」**
|
||||
|
||||
### 隠れた第3の選択肢
|
||||
|
||||
両先生が暗黙的に示唆している:
|
||||
|
||||
```
|
||||
時期による使い分け:
|
||||
Phase 1: C ABIで素早くエコシステム立ち上げ
|
||||
Phase 2: SDK層で開発体験向上
|
||||
Phase 3: Nyash ABIで技術的優位性確立
|
||||
Phase 4: 統合または選択的廃止
|
||||
```
|
||||
|
||||
## 💡 究極の洞察:「正解がない」ことが答え
|
||||
|
||||
### なぜ正解が難しいのか
|
||||
|
||||
1. **未来は予測不可能**
|
||||
- NyashがRustを超えるか?
|
||||
- WASMが世界標準になるか?
|
||||
- 新しいABI標準が生まれるか?
|
||||
|
||||
2. **トレードオフは価値観次第**
|
||||
- 速度 vs 安全性
|
||||
- シンプル vs 機能性
|
||||
- 互換性 vs 革新性
|
||||
|
||||
3. **成功の定義が人による**
|
||||
- 多くのプラグイン?
|
||||
- 高速な実行?
|
||||
- 美しいコード?
|
||||
|
||||
## 🚀 実践的な答え:適応的戦略
|
||||
|
||||
### 推奨アプローチ
|
||||
|
||||
```rust
|
||||
// 初期実装:両対応だが内部統一
|
||||
enum PluginABI {
|
||||
C(CPlugin), // 既存資産
|
||||
Nyash(NyashPlugin), // 新規開発
|
||||
}
|
||||
|
||||
// 共通インターフェース
|
||||
trait Plugin {
|
||||
fn invoke(&self, args: &[Value]) -> Result<Value>;
|
||||
}
|
||||
|
||||
// 将来の拡張ポイント
|
||||
impl PluginABI {
|
||||
fn optimize_for_jit(&self) -> Option<DirectCall> {
|
||||
// JIT時に最適化可能なら直接呼び出しに変換
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 段階的進化の道筋
|
||||
|
||||
1. **観察期間**(6ヶ月)
|
||||
- 両ABI並行運用
|
||||
- 使用パターン分析
|
||||
- パフォーマンス測定
|
||||
|
||||
2. **最適化期間**(次の6ヶ月)
|
||||
- 頻出パターンの高速化
|
||||
- SDK層の洗練
|
||||
- ドキュメント充実
|
||||
|
||||
3. **判断期間**(1年後)
|
||||
- データに基づく選択
|
||||
- 片方を非推奨に?
|
||||
- それとも永続的共存?
|
||||
|
||||
## 🌟 結論:「正解がない」を受け入れる勇気
|
||||
|
||||
**Nyashの哲学**:
|
||||
- Everything is Box → Everything has Trade-offs
|
||||
- 完璧より進捗(80/20ルール)
|
||||
- 箱理論で差し替え可能に
|
||||
|
||||
**最終提案**:
|
||||
1. 両方実装するが、**内部アーキテクチャは統一**
|
||||
2. **測定可能な成功指標**を先に定義
|
||||
3. **3ヶ月ごとに振り返り**、方向修正
|
||||
|
||||
正解がないからこそ、**適応し続けることが正解**。
|
||||
|
||||
---
|
||||
|
||||
*「間に挟むだけ」のABI層が、実は最も難しい設計判断の一つだった。*
|
||||
@ -0,0 +1,121 @@
|
||||
# BoxCall拡張によるABI戦略 - 最終実装決定 (2025-09-01)
|
||||
|
||||
## 🎯 両先生の回答から得た重要な洞察
|
||||
|
||||
### Gemini先生の誤解が示す重要な点
|
||||
- 先生は「BoxCall = Box<dyn Trait>を渡す」と誤解
|
||||
- しかし、この誤解が**abi_stable**の重要性を教えてくれた
|
||||
- 将来的にRustトレイトオブジェクトを扱う際の指針に
|
||||
|
||||
### Codex先生の実践的分析
|
||||
1. **abi_hintは実は不要かもしれない**
|
||||
- VM実行時にtype_idから判定可能
|
||||
- プラグインローダーが型情報を保持
|
||||
- MIR層を汚さない
|
||||
|
||||
2. **既存実装への影響最小化**
|
||||
- TypeMetaにABI情報を含める
|
||||
- nyash.tomlから読み込み済み
|
||||
- VM側で判定するだけ
|
||||
|
||||
## 🚀 最終実装方針
|
||||
|
||||
### Option A: 最小限実装(推奨)
|
||||
|
||||
```rust
|
||||
// MIR層:変更なし!
|
||||
MirInstruction::BoxCall {
|
||||
receiver: Value,
|
||||
method: String,
|
||||
args: Vec<Value>,
|
||||
// abi_hint不要!
|
||||
}
|
||||
|
||||
// VM層:型判定でABI選択
|
||||
fn execute_boxcall(...) {
|
||||
let type_id = receiver.get_type_id();
|
||||
|
||||
// プラグインローダーから型情報取得
|
||||
if let Some(plugin_info) = get_plugin_info(type_id) {
|
||||
match plugin_info.abi {
|
||||
"c" => call_c_abi(...),
|
||||
"nyash" => call_nyash_abi(...),
|
||||
_ => fallback_to_c_abi(...),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option B: 明示的ヒント(将来の拡張性)
|
||||
|
||||
```rust
|
||||
// MIR層:最小限の拡張
|
||||
MirInstruction::BoxCall {
|
||||
receiver: Value,
|
||||
method: String,
|
||||
args: Vec<Value],
|
||||
metadata: Option<u32>, // 汎用メタデータ(ABIヒント含む)
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 比較表
|
||||
|
||||
| 観点 | Option A(最小限) | Option B(ヒント付き) |
|
||||
|------|------------------|---------------------|
|
||||
| MIR変更 | なし ✅ | 最小限 |
|
||||
| 実装工数 | 1週間 | 2週間 |
|
||||
| JIT最適化 | VM時判定 | ビルド時判定可能 |
|
||||
| 将来拡張 | 型情報経由 | メタデータ活用 |
|
||||
|
||||
## 🎯 結論:Option Aで始める
|
||||
|
||||
### 理由
|
||||
1. **80/20ルール**: まず動くものを作る
|
||||
2. **MIR無変更**: 15命令の美しさ維持 → さらに14命令へ(PluginInvoke統合)
|
||||
3. **段階的進化**: 必要になったらOption Bへ
|
||||
|
||||
### Phase 12での追加統合
|
||||
- **PluginInvoke → BoxCall 完全統合**
|
||||
- ビルトインBox廃止により区別が不要
|
||||
- VM層でのABI判定で十分
|
||||
- Core-15 → Core-14 への削減
|
||||
|
||||
### 実装ステップ(1週間)
|
||||
|
||||
```yaml
|
||||
Day 1-2: nyash.toml拡張
|
||||
- abi: "c" | "nyash" field追加
|
||||
- プラグインローダー対応
|
||||
|
||||
Day 3-4: VM実行時分岐
|
||||
- execute_boxcall内でABI判定
|
||||
- NyashValue pack/unpack実装
|
||||
|
||||
Day 5-6: テスト・ベンチマーク
|
||||
- 同一機能の2種類プラグイン
|
||||
- 性能比較測定
|
||||
|
||||
Day 7: 判断
|
||||
- データに基づく方向性決定
|
||||
- Option B移行の必要性評価
|
||||
```
|
||||
|
||||
## 💡 深い洞察
|
||||
|
||||
**「abi_hintは不要」という発見が示すもの**:
|
||||
- 型システムが既に十分な情報を持っている
|
||||
- MIRは純粋な意図の表現で良い
|
||||
- 実行時の賢い判断に任せる
|
||||
|
||||
これこそ「Everything is Box」の真髄 - Boxが自分の実装方法を知っている!
|
||||
|
||||
## 🚀 次のアクション
|
||||
|
||||
1. nyash.tomlパーサーに`abi` field追加
|
||||
2. プラグインローダーでABI情報保持
|
||||
3. VM execute_boxcallで分岐実装
|
||||
4. 最小限のテストプラグイン作成
|
||||
|
||||
---
|
||||
|
||||
*最小限から始めて、データで判断する。これがNyashの道。*
|
||||
@ -0,0 +1,179 @@
|
||||
# Gemini先生のNyash ABI戦略分析 (2025-09-01)
|
||||
|
||||
## 質問内容
|
||||
|
||||
Nyashプラグインシステムの ABI戦略について技術的相談です。
|
||||
|
||||
【背景】
|
||||
Phase 12でNyashスクリプトプラグインシステムを実装中です。現在、プラグインインターフェースの設計で重要な判断が必要です。
|
||||
|
||||
【現状】
|
||||
- 既存: C ABI(シンプル、高速、実績あり)
|
||||
- 提案: Nyash ABI(3×u64構造体、型情報付き、拡張性高い)
|
||||
|
||||
【トレードオフ】
|
||||
C ABI:
|
||||
- 利点: ゼロオーバーヘッド、既存資産活用、シンプル
|
||||
- 欠点: 型情報なし、拡張性限定、エラー処理が原始的
|
||||
|
||||
Nyash ABI:
|
||||
- 利点: 型安全、メタデータ活用、将来性(async等)
|
||||
- 欠点: pack/unpackのオーバーヘッド、新規学習コスト
|
||||
|
||||
【具体的な選択肢】
|
||||
1. Nyash ABIのみ(統一性重視)
|
||||
2. C ABI + Nyash ABI両方(実用性重視)
|
||||
3. その他の革新的アプローチ?
|
||||
|
||||
【質問】
|
||||
1. どちらの戦略が長期的に見て賢明でしょうか?
|
||||
2. 両方サポートする場合の複雑性は管理可能でしょうか?
|
||||
3. 他の言語での成功例・失敗例から学べることは?
|
||||
4. VM/JIT最適化の観点から、どちらが有利でしょうか?
|
||||
|
||||
## Gemini先生の回答
|
||||
|
||||
### NyashプラグインシステムにおけるABI戦略の技術的考察
|
||||
|
||||
Nyashプラグインシステムの長期的なエコシステム発展を見据えたABI(Application Binary Interface)戦略について、深く技術的に考察します。
|
||||
|
||||
### 1. ABI安定性の重要性:エコシステム成功の礎
|
||||
|
||||
プラグインシステムの成功は、**ABIの鉄壁の安定性**にかかっています。ホストアプリケーション(Nyash)とプラグインは、別々にコンパイル・配布されるバイナリです。両者が正しく協調動作できるのは、関数呼び出し規約、データ型表現、メモリアロケーションといった低レベルな規約、すなわちABIが厳密に一致しているからです。
|
||||
|
||||
もしNyashのバージョンアップでABIに破壊的変更が生じれば、既存の全プラグインは動作しなくなり、再コンパイルが必要になります。これはエコシステムにとって致命的です。開発者は追従を諦め、ユーザーはプラグインが使えなくなることを恐れてNyashのアップデートをためらうでしょう。
|
||||
|
||||
したがって、ABI戦略の最優先目標は**「前方互換性(新しいNyashが古いプラグインを動かせる)と、可能な限りの後方互換性(古いNyashが新しいプラグインの機能を限定的にでも利用できる)」**を保証することです。
|
||||
|
||||
### 2. 現状の分析と潜在的リスク
|
||||
|
||||
現在のNyashのコードベースを調査し、プラグイン関連の実装を特定する必要があります。`Cargo.toml`やソースコードから、おそらくRustのダイナミックライブラリ(`.so`, `.dll`, `.dylib`)を動的に読み込む形式が採用されていると推測されます。
|
||||
|
||||
ここで最も警戒すべきは、**Rust固有のABIに依存することのリスク**です。Rustコンパイラは、パフォーマンス最適化のために、構造体のメモリレイアウトや関数呼び出し規約をバージョン間で予告なく変更します。したがって、`extern "Rust"`(デフォルト)の関数をプラグイン境界として公開するのは、エコシステムの観点からは**絶対に避けなければなりません**。
|
||||
|
||||
素晴らしい!検索結果から、Nyashはすでに `extern "C"` を広範囲に利用していることが明確にわかります。これは非常に良い出発点です。`plugin_loader_v2.rs` や `bid/plugin_api.rs` などを見ると、プラグインの初期化(`nyash_plugin_init`)や関数呼び出し(`invoke_fn`)のシグネチャがC ABIで定義されています。
|
||||
|
||||
これは、ABI安定性に対する基本的な理解がプロジェクトに既に存在することを示しています。しかし、長期的なエコシステムを築くには、これをさらに推し進め、より洗練された戦略を立てる必要があります。
|
||||
|
||||
### 3. 長期的な発展のためのABI戦略提案
|
||||
|
||||
現在の `extern "C"` ベースのアプローチを基礎としつつ、以下の戦略を段階的に導入することを提案します。
|
||||
|
||||
#### 戦略1:C ABIを「公式な安定境界」として厳格に定義・文書化する
|
||||
|
||||
これは最も重要です。`extern "C"` を使っているというだけでは不十分で、それを**公式な規約**として確立する必要があります。
|
||||
|
||||
**具体的なアクション:**
|
||||
|
||||
1. **ABI仕様書の作成:**
|
||||
- `nyash-abi.h`のようなCヘッダーファイル形式で、プラグインが実装すべき関数シグネチャと、Nyashが提供するホスト関数(コールバック)をすべて定義します。
|
||||
- `invoke_fn` で使われている `*const u8`, `*mut u8` のようなバイトポインタが、具体的にどのようなデータを指すのか(シリアライズ形式、レイアウトなど)を厳密に文書化します。
|
||||
- `NyashHostVtable` のような構造体は、フィールドの順序と型が未来永劫変わらないことを保証しなければなりません。新しいホスト関数を追加する場合は、末尾にのみ追加します。
|
||||
- エラー報告の規約(戻り値の `i32` が何を意味するのか)を定義します。
|
||||
|
||||
2. **FFI(Foreign Function Interface)層の明確化:**
|
||||
- Nyash内部のRustコードと、C ABI境界を明確に分離します。`plugin_loader_v2.rs` はこの役割を担っているようですが、この層は「ABI変換」にのみ責任を持つべきです。内部的なリファクタリングがABIに影響を与えないようにします。
|
||||
|
||||
**利点:**
|
||||
- **言語非依存:** C ABIはあらゆる主要言語(C++, Zig, Go, Python, etc.)から利用可能で、プラグイン開発者の裾野を広げます。
|
||||
- **究極の安定性:** C ABIは数十年にわたり安定しています。
|
||||
|
||||
**欠点:**
|
||||
- **表現力の低さ:** Rustの`Result`や`Option`、ライフタイムといった豊かな型情報を直接渡せず、`i32`のエラーコードやポインタのNULLチェックといったプリミティブな方法に頼らざるを得ません。
|
||||
- **手作業と`unsafe`:** データのシリアライズ・デシリアライズやポインタ操作が必須となり、`unsafe`コードが増え、バグの温床になりやすいです。
|
||||
|
||||
#### 戦略2:高レベルな「Rust向けラッパーSDK」を提供する
|
||||
|
||||
C ABIの欠点を補うため、プラグイン開発者が直接C ABIを触らなくても済むように、公式のRust製SDK(クレート)を提供します。
|
||||
|
||||
**具体的なアクション:**
|
||||
|
||||
1. **`nyash-plugin-sdk` クレートの作成:**
|
||||
- このSDKは、低レベルなC ABIのやり取りをすべてカプセル化します。
|
||||
- プラグイン開発者は、`Result<MyData, MyError>` のような自然なRustの型を扱うだけで、SDKが自動的にC ABI準拠のデータ(バイト列やエラーコード)との相互変換を行います。
|
||||
- 定型的なコードを自動生成するマクロ(例: `#[nyash_plugin]`)を提供し、開発体験を向上させます。
|
||||
|
||||
**SDK利用者のコード(イメージ):**
|
||||
```rust
|
||||
// プラグイン開発者が書くコード
|
||||
use nyash_plugin_sdk::{plugin, NyashResult, NyashError};
|
||||
|
||||
struct MyPlugin;
|
||||
|
||||
#[plugin]
|
||||
impl Plugin for MyPlugin {
|
||||
fn handle_request(&self, input: &str) -> NyashResult<String> {
|
||||
if input == "hello" {
|
||||
Ok("world".to_string())
|
||||
} else {
|
||||
Err(NyashError::new("Invalid input"))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**SDK内部の実装(イメージ):**
|
||||
```rust
|
||||
// #[plugin] マクロが生成するコード
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn nyash_plugin_invoke(
|
||||
/* C ABI引数 */
|
||||
) -> i32 {
|
||||
// 1. C ABIのバイト列から &str へデシリアライズ
|
||||
// 2. MyPlugin::handle_request を呼び出し
|
||||
// 3. 結果の Result<String, NyashError> をC ABIのエラーコードとバイト列にシリアライズ
|
||||
// 4. 結果を返す
|
||||
// ... この部分はSDKが隠蔽する ...
|
||||
}
|
||||
```
|
||||
|
||||
**利点:**
|
||||
- **高い開発者体験:** Rust開発者は、安全で慣用的なRustコードを書くことに集中できます。
|
||||
- **安全性の向上:** `unsafe`コードをSDKに集約させることで、プラグイン開発者がメモリ安全性を破壊するリスクを大幅に低減できます。
|
||||
|
||||
#### 戦略3:データ交換フォーマットの標準化
|
||||
|
||||
`invoke_fn` でやり取りされる `*const u8` の中身を標準化します。これにより、堅牢性と前方互換性が向上します。
|
||||
|
||||
**候補:**
|
||||
|
||||
- **Protocol Buffers / FlatBuffers:**
|
||||
- **利点:** スキーマ定義が明確で、前方・後方互換性を考慮した設計が容易。多言語対応のコード生成ツールが豊富。パフォーマンスも高い。
|
||||
- **欠点:** ビルドプロセスに一手間加わる。
|
||||
|
||||
- **JSON / MessagePack:**
|
||||
- **利点:** 動的で柔軟。デバッグが容易。
|
||||
- **欠点:** スキーマがないため、実行時エラーになりやすい。シリアライズ・デシリアライズのオーバーヘッドが比較的多きい。
|
||||
|
||||
**推奨:**
|
||||
長期的なエコシステムの安定性を考えると、スキーマベースの **Protocol Buffers** または **FlatBuffers** が最適です。
|
||||
|
||||
#### 戦略4:WebAssembly (Wasm) の採用検討
|
||||
|
||||
究極の目標として、プラグインをWebAssemblyモジュールとして実行する方式を検討する価値があります。
|
||||
|
||||
**利点:**
|
||||
- **サンドボックス化:** Wasmランタイム(Wasmtimeなど)上でプラグインを実行することで、Nyash本体から完全に隔離された安全な環境を提供できます。悪意のあるプラグインやバグのあるプラグインがホストをクラッシュさせるのを防ぎます。
|
||||
- **真の言語非依存:** C ABIよりもさらに多くの言語(コンパイルターゲットにWASIを持つもの)がプラグイン開発に利用可能になります。
|
||||
- **WASIとコンポーネントモデル:** WASI(WebAssembly System Interface)やWasm Component Modelの標準化が進むことで、ファイルアクセスやネットワークなどのホスト機能へのアクセスが標準化され、より洗練されたABIを構築できます。
|
||||
|
||||
**欠点:**
|
||||
- **パフォーマンスオーバーヘッド:** C ABIのダイナミックライブラリ呼び出しに比べ、Wasmランタイムを介在させることによるオーバーヘッドが存在します。
|
||||
- **実装の複雑さ:** Wasmランタイムの組み込みと、ホスト・ゲスト間のデータ共有(特に複雑なデータ構造)の実装は複雑になります。
|
||||
|
||||
### まとめと提言
|
||||
|
||||
Nyashは `extern "C"` の採用により、ABI安定化への正しい一歩を踏み出しています。長期的なエコシステムの繁栄のため、以下のロードマップを提案します。
|
||||
|
||||
1. **短期(すぐ着手すべき):**
|
||||
- **C ABIの公式化:** `nyash-abi.h`相当の仕様を定義し、文書化する。
|
||||
- **データフォーマットの選定:** `invoke_fn` で交換されるデータのシリアライズ形式としてProtocol Buffers等を導入する。
|
||||
|
||||
2. **中期(エコシステムの成長期):**
|
||||
- **Rust向けSDKの提供:** `nyash-plugin-sdk` クレートを開発し、Rust開発者の体験を向上させる。
|
||||
- **他言語向けSDKの提供:** 需要に応じて、PythonやGo向けのラッパーライブラリを提供する。
|
||||
|
||||
3. **長期(未来のビジョン):**
|
||||
- **WebAssemblyへの移行:** パフォーマンス要件とセキュリティ要件を天秤にかけ、プラグイン実行環境をWasmに移行することを検討する。これにより、究極の安全性と移植性を獲得できる。
|
||||
|
||||
この戦略により、Nyashは安定性、開発者体験、安全性を段階的に向上させ、活発で持続可能なプラグインエコシステムを構築できると確信します。
|
||||
Reference in New Issue
Block a user