From 3a576a665cdbe491b24aedc7802957b6f4a09eda Mon Sep 17 00:00:00 2001 From: Moe Charm Date: Fri, 29 Aug 2025 03:42:59 +0900 Subject: [PATCH] =?UTF-8?q?Phase=2010.1:=20ChatGPT5=E3=81=AEC=20ABI?= =?UTF-8?q?=E7=B5=B1=E4=B8=80=E8=A8=AD=E8=A8=88=E3=82=92=E6=96=87=E6=9B=B8?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ChatGPT5からの的確なアドバイスを設計文書に反映 - nyrt_*(コアランタイム)とnyplug_*(プラグイン)の命名規則 - 実装ステップガイドの詳細化(VM→JIT→AOTの順序) - 最小限のC ABIヘッダ雛形を定義 '手順さえ守れば大丈夫' - 一歩ずつ確実に進める計画 --- .../phases/phase-10.1/c_abi_unified_design.md | 156 +++++++++++++++ .../phases/phase-10.1/implementation_steps.md | 180 ++++++++++++++++++ 2 files changed, 336 insertions(+) create mode 100644 docs/development/roadmap/phases/phase-10.1/c_abi_unified_design.md create mode 100644 docs/development/roadmap/phases/phase-10.1/implementation_steps.md diff --git a/docs/development/roadmap/phases/phase-10.1/c_abi_unified_design.md b/docs/development/roadmap/phases/phase-10.1/c_abi_unified_design.md new file mode 100644 index 00000000..59b0ff36 --- /dev/null +++ b/docs/development/roadmap/phases/phase-10.1/c_abi_unified_design.md @@ -0,0 +1,156 @@ +# C ABI統一設計 - JIT/AOT共通基盤 + +*ChatGPT5さんからのアドバイスに基づく設計文書* + +## 🎯 核心的洞察 + +**プラグインBoxのC ABI = そのままJIT/AOTの呼び出し土台** + +JITで今呼んでいるC ABIをAOTでは静的リンクに差し替えるだけでexe化まで一直線! + +## 📊 全体アーキテクチャ + +``` +Nyash → MIR → VM/JIT/Cranelift ──┐ + ├─ 呼ぶ先は全部 C ABI: nyrt_* / nyplug_* +NyRT (libnyrt.a/.so) ←──────────┘ +PluginBox 実装 (libnyplug_*.a/.so) +``` + +- **JIT**: `extern "C"` シンボル(`nyrt_*`/`nyplug_*`)をその場で呼ぶ +- **AOT**: 同じシンボルを`.o`に未解決のまま出力→`libnyrt.a`とプラグイン`.a`をリンク +- **動的配布**: `.so/.dll`に差し替え(同じC ABIでOK) + +## 🔧 C ABIルール(小さく強い) + +### 1. 命名/可視性 +- コア: `nyrt_*`(Box/weak/bus/gc/sync/alloc...) +- プラグイン: `nyplug_{name}_*`(ArrayBox, StringBox など) +- `extern "C"` + 明示の可視性(ELF: `__attribute__((visibility("default")))`) + +### 2. ABIの型 +- 引数/戻り: `int32_t/int64_t/uint64_t/double/void*` のみに限定 +- `bool`は`uint8_t`統一、構造体は不透明ポインタ(ハンドル) +- `varargs`と例外のABI横断は**禁止**(戻り値でエラーコード/out-paramで返す) + +### 3. レイアウト/アライン +```c +// Boxハンドル例 +struct NyBox { + void* data; + uint64_t typeid; + uint32_t flags; + uint32_t gen; +}; +``` +※JIT側は中身に触らない。操作はAPI経由のみ。 + +### 4. 呼び出し規約 +- x86_64 SysV / aarch64 AAPCS64 / Win64 をターゲットごとに固定 +- Craneliftの`call_conv`を上記に合わせる(JIT/AOT共通) + +### 5. バージョン管理 +- `nyrt_abi_version()`を導入(壊れたら即fail) +- プラグインも`nyplug_{name}_abi_version()` + +## 📝 最小ヘッダ雛形 + +### nyrt.h(コアランタイム) +```c +#pragma once +#include +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NyBox { + void* data; + uint64_t typeid; + uint32_t flags; + uint32_t gen; +} NyBox; + +int32_t nyrt_abi_version(void); + +// Box/weak +NyBox nyrt_box_new(uint64_t typeid, uint64_t size); +void nyrt_box_free(NyBox b); +int32_t nyrt_adopt(NyBox parent, NyBox child); +int32_t nyrt_release(NyBox parent, NyBox child, NyBox* out_weak); +NyBox nyrt_weak_load(NyBox weak); // gen一致ならBox, 失効なら{0} + +// GC/epoch +void nyrt_epoch_collect(void); + +// Sync(最低限) +void* nyrt_mutex_lock(NyBox sync); +void nyrt_mutex_unlock(void* guard); + +// Bus +int32_t nyrt_bus_send(NyBox port, NyBox msg); + +#ifdef __cplusplus +} +#endif +``` + +### nyplug_array.h(プラグイン例:ArrayBox) +```c +#pragma once +#include "nyrt.h" +#ifdef __cplusplus +extern "C" { +#endif + +int32_t nyplug_array_abi_version(void); +NyBox nyplug_array_new(void); +int32_t nyplug_array_get(NyBox arr, uint64_t i, NyBox* out); +int32_t nyplug_array_set(NyBox arr, uint64_t i, NyBox v); +uint64_t nyplug_array_len(NyBox arr); +int32_t nyplug_array_push(NyBox arr, NyBox v); + +#ifdef __cplusplus +} +#endif +``` + +## 🚀 ビルド・配布フロー(AOT静的リンク) + +1. **JITと同じLowering**でCLIF生成 +2. **ObjectWriter**で`mod.o`出力(未解決:`nyrt_*`/`nyplug_*`) +3. **リンク** + - Linux/macOS: `cc mod.o -static -L. -lnyrt -lnyplug_array -o app` + - Windows: `link mod.obj nyrt.lib nyplug_array.lib /OUT:app.exe` +4. 実行:`./app`でJIT無しに動作 + +## ⚡ 実装順序(重要!) + +1. **必要なビルトインBoxをプラグインBoxに変換** +2. **VM動作確認** +3. **JIT動作確認** +4. **AOT実装** + +## ⚠️ 地雷と回避策 + +- **名前修飾/装飾**: C++で実装するなら`extern "C"`を絶対忘れない +- **サイズ違い**: `bool`/`size_t`のプラットフォーム差 → 明示幅型で統一 +- **例外越境**: C ABI越しに`throw`/`panic`禁止。エラーコード+out-paramで返す +- **並行**: JITから`nyrt_mutex_*`を呼ぶ箇所はSafepointとも整合するように(長保持しない) + +## 📋 即実行ToDo(30分で前進) + +- [ ] `nyrt.h`最小セット確定(上の雛形でOK) +- [ ] Craneliftの`call_conv`をターゲットに合わせて固定 +- [ ] JIT経路で`nyrt_abi_version()==NYRT_ABI`を起動時チェック +- [ ] AOT試作:`add.o`を吐いて`libnyrt.a`とリンク→`add()`を呼ぶ最小exe + +## 💡 まとめ + +> プラグインBoxのC ABI=JIT/AOTの土台だから、 +> **いまのJITが動いている=静的リンクexeの最短ルートはもう目の前。** +> まずは`nyrt.h`を固定して、JITとAOTの両方で同じシンボルを呼ぶ状態にしよう。 +> それで**"今日のJIT"が"明日のexe"**に化けるにゃ。 + +--- + +*最終更新: 2025-08-28* \ No newline at end of file diff --git a/docs/development/roadmap/phases/phase-10.1/implementation_steps.md b/docs/development/roadmap/phases/phase-10.1/implementation_steps.md new file mode 100644 index 00000000..7ab1f1c8 --- /dev/null +++ b/docs/development/roadmap/phases/phase-10.1/implementation_steps.md @@ -0,0 +1,180 @@ +# Phase 10.1 実装ステップガイド + +## 🎯 実装の鉄則:必ずこの順序で! + +ChatGPT5さんの指摘通り、緻密な計画と順序が成功の鍵にゃ。 + +## 📊 実装ステップ + +### Step 1: ArrayBoxのプラグイン化(最小実装) + +#### 1.1 プロジェクト作成 +```bash +cd plugins/ +cargo new nyash-array-plugin --lib +cd nyash-array-plugin +``` + +#### 1.2 最小限のC FFI実装 +```rust +// src/lib.rs +#[repr(C)] +pub struct NyBox { + data: *mut u8, + typeid: u64, + flags: u32, + gen: u32, +} + +#[no_mangle] +pub extern "C" fn nyplug_array_abi_version() -> i32 { 1 } + +#[no_mangle] +pub extern "C" fn nyplug_array_new() -> NyBox { + // 簡略実装:Vecのみサポート + let vec = Box::new(Vec::::new()); + NyBox { + data: Box::into_raw(vec) as *mut u8, + typeid: 3, // ArrayBox + flags: 0, + gen: 1, + } +} + +#[no_mangle] +pub extern "C" fn nyplug_array_len(arr: NyBox) -> u64 { + unsafe { + let vec = &*(arr.data as *const Vec); + vec.len() as u64 + } +} +``` + +#### 1.3 ビルド設定 +```toml +# Cargo.toml +[lib] +crate-type = ["cdylib", "staticlib"] # 動的・静的両対応 +``` + +### Step 2: VM動作確認 + +#### 2.1 プラグインローダーとの統合 +```rust +// src/runtime/plugin_loader_v2.rsに追加 +fn load_builtin_plugins(&mut self) { + // 既存のFileBox等に加えて + self.register_plugin("nyash-array-plugin", 3); // ArrayBox type_id = 3 +} +``` + +#### 2.2 テストプログラム +```nyash +// test_array_plugin.nyash +local arr +arr = new ArrayBox() // プラグイン版を呼ぶ +print(arr.length()) // 0が出力されれば成功 +``` + +#### 2.3 VM実行 +```bash +./target/release/nyash --backend vm test_array_plugin.nyash +``` + +### Step 3: JIT動作確認 + +#### 3.1 LowerCoreの修正 +```rust +// src/jit/lower/core.rs +match box_type { + "ArrayBox" => { + // HostCallからPluginInvokeに切り替え + b.emit_plugin_invoke(3, method_id, args); + } + // 他のBoxは従来通り +} +``` + +#### 3.2 JIT実行テスト +```bash +NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 ./target/release/nyash --backend vm test_array_plugin.nyash +``` + +### Step 4: 段階的移行 + +#### 4.1 移行優先順位 +1. **ArrayBox** - 最も使用頻度が高い +2. **StringBox** - 基本的なデータ型 +3. **IntegerBox/BoolBox** - プリミティブ型 +4. **MapBox** - コレクション型 +5. **その他** - 順次移行 + +#### 4.2 互換性維持 +```rust +// フラグで切り替え可能に +if env::var("NYASH_USE_PLUGIN_BUILTINS").is_ok() { + // プラグイン版を使用 +} else { + // 従来のビルトイン版 +} +``` + +### Step 5: パフォーマンス測定 + +#### 5.1 ベンチマーク作成 +```nyash +// bench_array_ops.nyash +local arr = new ArrayBox() +local start = Timer.now() +loop(i in 0..1000000) { + arr.push(i) +} +local elapsed = Timer.now() - start +print("Time: " + elapsed) +``` + +#### 5.2 比較測定 +```bash +# 従来版 +./target/release/nyash --benchmark bench_array_ops.nyash + +# プラグイン版 +NYASH_USE_PLUGIN_BUILTINS=1 ./target/release/nyash --benchmark bench_array_ops.nyash +``` + +## 🎯 成功基準 + +### Phase 1(1週間) +- [ ] ArrayBoxプラグインが動作 +- [ ] VM経由で基本操作(new, length, push, get)が可能 +- [ ] パフォーマンス劣化が10%以内 + +### Phase 2(2週間) +- [ ] JIT経由でも動作 +- [ ] 5つ以上のビルトインBoxがプラグイン化 +- [ ] 既存テストがすべてパス + +### Phase 3(1ヶ月) +- [ ] すべての主要ビルトインBoxがプラグイン化 +- [ ] 静的リンクでの最小exe生成 +- [ ] Linux/macOSで動作確認 + +## ⚠️ 注意事項 + +1. **TLVエンコーディング**: 既存のプラグインシステムに合わせる +2. **エラー処理**: panicではなくエラーコードを返す +3. **メモリ管理**: Box化されたデータのライフサイクルに注意 + +## 💡 デバッグ時のヒント + +```bash +# プラグインロード確認 +NYASH_DEBUG_PLUGIN=1 ./target/release/nyash test.nyash + +# JIT呼び出し確認 +NYASH_JIT_EVENTS=1 ./target/release/nyash --backend vm test.nyash +``` + +--- + +*"手順を守れば大丈夫" - 一歩ずつ確実に進めるにゃ!* \ No newline at end of file