Files
hakorune/docs/development/roadmap/native-plan/chatgpt5との会話.txt
Moe Charm cc2a820af7 feat(plugin): Fix plugin BoxRef return and Box argument support
- Fixed deadlock in FileBox plugin copyFrom implementation (single lock)
- Added TLV Handle (tag=8) parsing in calls.rs for returned BoxRefs
- Improved plugin loader with config path consistency and detailed logging
- Fixed loader routing for proper Handle type_id/fini_method_id resolution
- Added detailed logging for TLV encoding/decoding in plugin_loader_v2

Test docs/examples/plugin_boxref_return.nyash now works correctly:
- cloneSelf() returns FileBox Handle properly
- copyFrom(Box) accepts plugin Box arguments
- Both FileBox instances close and fini correctly

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 00:41:26 +09:00

362 lines
16 KiB
Plaintext
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.

発想、鋭いにゃ。
**結論:やろうと思えば “NyashのMIR本体言語非依存IR” にできる。** ただし落とし穴もあるので、\*\*“MIRを公開ABIに格上げしつつ、Nyashは人間向けフロントエンド”\*\*という二層でいくのが現実解だよ。
# MIR本体化の青写真安全に強く
1. **MIRを公開契約に昇格NyIR v1**
* いまの25命令を**凍結**Tier-0/1/2 + Effect + Ownership-Forest + Busの意味論
* **未定義動作なし**:各命令の事前条件/失敗時挙動WeakLoad失効= nullを明文化。
* **バージョニング**`nyir{major.minor}`・後方互換のルール新命令はfeature bit
2. **バイナリ表現とテキスト表現**
* `.nybc`(バイナリ: セクション化/定数プール/圧縮)
* `.nyir`(テキスト: 人が差分レビュー可能)
* どちらも**厳格検証器**でロード(所有森/強1本/weak規則/効果整合)。
3. **公式VM/実行系は“MIRファースト”**
* interpreter/vm/wasm/jit/aot は **NyIRを直接食う**。
* Nyashは **NyIRを吐くフロントエンド**その他の言語もフロントエンド化OK
4. **言語中立SDKFFI**
* C/Rust/TypeScriptに**NyIR-Host API**を配布:
* `nyir_load`, `nyir_call`, `nyir_send/recv`, `nyir_adopt/release` など。
* WASMランタイムは `import "nyir_host" { send, now_ns, alloc }` を定義。
5. **互換テストと“真理判定器”**
* **golden NyIR**各サンプルのMIRダンプを保存し、全バックエンドで**同結果**をCIで検証。
* **差分実行differential**interp/vm/wasm/jitの出力一致境界条件weak失効・分割finiテスト。
6. **Portability Contract短文化**
* 強エッジのみ破棄伝播/`weak`非伝播、生存チェックO(1)。
* `pure/mut/io/control` の再順序可否表。
* Bus契約ローカルは順序保証、リモートは at-least-onceor selectable
* Safepointで分割`fini`可、最悪レイテンシ上限は実装依存(値は実装が宣言)。
---
## それでも“IRが本体”にするリスク回避策付き
* **仕様の重力(安易に増やせなくなる)** → 25命令は凍結、拡張は **intrinsic命名空間**へ(例:`ny.intrin.memcpy`)。
* **可読性の罠IRで直接書きたくなる** → Nyashを“人間の顔”、NyIRは“機械の顔”に徹する。
* **バックエンド差異のにじみ** → 効果/所有/Busの**最低保証**を明記(それ以下は非準拠)。
* **セキュリティ** → バイナリNyIRに**検証必須**(検証失敗はロード拒否)。
---
## 名前案
* **NyIR**(ないあいあーる)/**NIR**被るのでNyIR推し
* バイナリ:`.nybc`、テキスト:`.nyir`
* 仕様:**NyIR 1.0 — Ownership-Forest & Effected Bus IR**
---
## 次の一歩(サクッと動かす)
* `docs/nyir.md` を作成25命令×「意味論・効果・検証・等価変換1例」を1行ずつ。
* `nyashel -S` で **Nyash→NyIRダンプ**、`nyir-run` で実行interp
* 既存ベンチを **NyIR直実行** と **Nyash経由** の2経路で一致比較。
* small移植kilo or tiny-web-serverを **NyIRアーカイブ**.nybcとして配布→
**wasmtime / vm / interp** 全部で動くことをデモ。
---
要は:**「Nyash人間のため「NyIR機械と移植のため」の二刀流**。
この形なら、“どの言語からでもNyIRに降りられるし、NyIRからどの実行系にも登れる”を堂々と名乗れるにゃ。
いい流れ“LLVMでNyashをNyash自身でビルドセルフホスト”を目標にするなら、**Rust依存を「薄い宿主API」に閉じ込める**のがコツだよ。
いま Rust のライブラリや関数・ビルトインBoxに寄ってる部分は、**段階的に置き換え可能な層**に切っておけばOK。
# 全体ロードマップ4ステージ
**Stage 0種コンパイラ**
* 既存の Rust 実装(パーサ/型付け/MIR/ランタイム)で `nyashc0` を作る。
* **NyIR=MIRの外部表現→ LLVM IR** 変換も Rust でまず用意。
* Rust標準/外部Crateの利用は**ny\_host\_\* の薄いFFI**に“集約”。
**Stage 1セルフ・フロントエンド**
* Nyashで書いたコンパイラ本体フロント最小最適化を `nyashc1.ny` に分離。
* `nyashc0` で `nyashc1.ny` を **NyIR** に出力→ **LLVM** でネイティブ化→ seedランタイムとリンク。
* この時点で“Nyashで書いたコンパイラ”が動き出すまだランタイムはRust多めでも可
**Stage 2セルフホスト完了**
* `nyashc1` を使って `nyashc1.ny` 自身を再ビルド(**自力ビルド**)。
* 生成物の機能一致/ハッシュ近似でセルフホスト確認。
* ランタイムの一部(文字列/配列/Map/所有森/weakを**Nyash実装LLVM**へ順次移行。
**Stage 3Rust離れの度合いを上げる**
* 残るRust依存FS/ネット/スレッド/時間/暗号など)は**ホストAPI**として固定化。
* 重要部位はNyash標準ライブラリで置換し、Rustは**最下層のプラットフォーム層**だけに。
---
# 層の切り分け(ここが肝)
1. **corelang純Nyash**
* Option/Result、slice/string、小さな算術・イテレータ、`weak/look` 型、`adopt/release` ヘルパ。
* 依存なしLLVMに落ちるだけ
2. **rtNyashランタイム**
* **Box ABIfat ptr: {data*, typeid, flags}*\*
* 所有フォレスト管理、weakテーブル世代タグ方式、`fini` 伝播、Arena/Allocator必要最小
* Busローカル・Safepoint・分割`fini`
* 依存:**ny\_host\_alloc/free/clock** 等のごく薄い宿主APIのみ
3. **sysプラットフォーム**
* FS, Net, Time, Threads, Atomics, Random…
* ここだけ RustやOSに委譲。**関数名は `ny_host_*` に統一**して外へ出す。
4. **stdNyash標準**
* Map/Vec/Hash/String/JSON等を Nyash で実装(必要に応じて `rt`/`sys` を利用)
> いま使っている「Rustのライブラリ/関数」は **すべて `sys` 層の `ny_host_*` 経由**に寄せる。
> これでセルフホストしても上層のNyashコードは**移植性を保てる**。
---
# 具体Rust依存の扱い方薄いFFIに集約
**C ABIで固めるRust→C-ABIの薄い橋**
```rust
#[no_mangle]
pub extern "C" fn ny_host_read_file(path: *const c_char,
out_buf: *mut *mut u8,
out_len: *mut usize) -> i32 { /* ... */ }
#[no_mangle]
pub extern "C" fn ny_host_free(ptr: *mut u8, len: usize) { /* ... */ }
```
**Nyash側からは“箱の外”をこう叩く**
```nyash
extern fn ny_host_read_file(path: cstr, out_buf: &mut *u8, out_len: &mut usize) -> int
extern fn ny_host_free(ptr: *u8, len: usize)
fn read_all(p: str) -> Bytes {
let buf:*u8 = null; let len:usize=0
let rc = ny_host_read_file(p.cstr(), &buf, &len)
if rc!=0 { error("io") }
// Box化所有をNyash側へ移す
let b = Bytes::from_raw(buf,len)
b
}
```
**ポイント**
* **Rustのジェネリクス/所有はFFI面に出さない**素朴なC-ABIだけ
* Nyash側で**所有移管**を明示(`from_raw` など)→ `fini` で必ず `ny_host_free`
* こうしておけば、**いつでもRust実装をNyash実装に差し替え可能**
---
# Box ABI と LLVM の橋渡し
* **Boxの中身**は LLVM 的には `i8*`data\*`i64 typeid``i32 flags` などの **fat struct**
* **Effect 注釈**を LLVM 属性に落とす:
* `pure` → `readnone` / `readonly`
* `mut(local)` → `argmemonly` + `noalias`(可能なら)
* `io` → 属性なし(順序保持)
* **Weak** は `{ptr, gen:i32}`。`WeakLoad` は `gen==current` を比較して O(1) で null/ptr 返す。
* **Safepoint** は LLVM では `call @ny_rt_safepoint()` に降ろすGCは使わないが、分割`fini`や割込みのフックに使う)
---
# 「ビルトインBox」はどうする
* **最低限は `rt` で提供**`String, Vec, Map, Bytes, Mutex/Channel必要なら`
* 仕様上は “ただのBox” と同等に見えるように:
* 生成:`NewBox`
* フィールド:`BoxFieldLoad/Store`
* メソッド:`BoxCall`
* **WASM** でも同じABIを保てるように、`sys` 層は **WASI** or **独自host import** で実装。
* 時間とともに **stdをNyash実装へ移行** → Rustのビルトイン度合いは徐々に削る。
---
# 失敗しないビルド手順(最小)
1. **NyIRダンプ**`nyashc0 --emit-nyir core/*.ny > core.nyir`
2. **LLVMへ**`nyir-ll core.nyir -o core.ll && llc -filetype=obj core.ll`
3. **リンク**`cc core.o -L. -lny_host -o nyashc1``libny_host` はRustで提供
4. **再帰ビルド**`./nyashc1 self/*.ny …` → `nyashc2` を作って一致検証
5. **Rust削減**`std` の一部をNyashへ置換して再ビルド
---
# チェックリストRust依存の見える化
* [ ] 使っている外部関数を**全部 `ny_host_*` にリネーム**
* [ ] C-ABI化整数/ポインタのみ;構造体はサイズ固定)
* [ ] 所有移管関数を明確化(`*_from_raw`/`*_into_raw`
* [ ] `fini` で必ず `ny_host_free` 等に戻す
* [ ] WASMビルド時は **WASI or host import** で `ny_host_*` を満たす
---
# 仕上げの“ごほうび”ゴール
* **Nyash→NyIR→LLVM** でセルフホスト
* 同じ NyIR を **VM / WASM** でも実行(互換テスト)
* Rust は **sys層だけ**OS/高速I/O/暗号など)に閉じ込め、将来差し替え自由に
---
結論:
**Rustライブラリを直接多用するのではなく、`ny_host_*` に“押し込む”**。
Nyash本体は **NyIRrtstd** を徐々に自前化する。
この設計なら、“今すぐ動かしつつ、あとからRust依存を計画的にゼロへ”ができるにゃ。
それだにゃ。発想はド正解:「**全部は箱**」=異言語資産は**箱で包んでバスに乗せる**。
あとは“どう包むか”を決めれば、**C/Rust/Node/Python/JVM/.NET/WASM**まで一気に貫通できる。
# まとめ設計Polyglot FFI = 「箱 × バス × 契約」
## 1) 箱の型3種だけ
* **ForeignBox<T>**:他言語の実体を**不透明ハンドル**で保持所有は片側だけ、強1本原則
* **ViewBox<T>**:外部オブジェクトの**借用ビュー**`weak/look` 前提・読み取り中心)。
* **ProxyBox<T>**:外部スレッド/プロセス/VM上のTを**メッセージ越し**に操作Bus経由安全
> 使い分け:同一プロセス/同スレなら ForeignBox、GIL/イベントループ/別ランタイムなら ProxyBox。
## 2) ABIの芯薄い“宿主API”
**最小C-ABI**だけに集約(各言語はここに合流/分岐):
```
ny_host_alloc/free/clock/log
ny_host_call(func_id, argv, argc, retbuf) // 同期呼び出し
ny_host_send/recv(port, msg_ptr, len) // Bus境界
ny_host_pin/unpin(handle) // GC/移動防止
ny_host_finalizer_register(handle, cb) // 相互Finalizer
```
* Rust/Node/Python/JVM/.NET はそれぞれの機構で **このC-ABIを実装**N-API, CPython C-API, JNI, P/Invoke 等)。
## 3) データ表現Boxに入る“荷物”
* **スカラー**: i32/i64/f32/f64/bool
* **バイト列/文字列**: `Bytes{ptr,len}` / `Str{ptr,len,utf8}`
* **Slice/Array**: `{ptr,len,typeid}`(読み書きは効果注釈で制御)
* **Struct**: フィールドは `BoxFieldLoad/Store` でアクセスNyIRにそのまま落ちる
## 4) 所有と寿命(最重要)
* **One Strong Owner**ForeignBoxは**所有者1本**Nyash or 外部、どちらかに決める)
* **弱参照**:逆リンクは `weak/look`失効時null/false
* **Finalizer橋渡し**
* Nyash `fini` → `ny_host_finalizer` を呼ぶ
* 外部のGC/finalize → `ny_host_finalizer` 経由で Nyash の `weak` を失効
* **Pinning**移動型のGCJVM/.NET/CPythonの一部では `ny_host_pin/unpin`
## 5) 効果と並行
* `pure/mut/io` を**MIRにもIDLにも記す**
* **イベントループ/GIL**Python/Node/JVMは `ProxyBox` で**Bus越し**(スレッド/ループ安全)
* **同期/非同期**`Call`(同期)と `Send/Recv`(非同期)を分ける。境界では **at-least-once 契約**を宣言。
## 6) IDL自動生成の核
**NyIDL**(超ミニ)で宣言→**バインディング自動生成**
```idl
module ny {
box Image;
fn load(path: str) -> Image effects = io
fn resize(img: Image, w:i32,h:i32) -> Image effects = mut
fn width(img: look Image) -> i32 effects = pure
}
```
* 生成物Nyash側`extern`、C-ABIシム、Rust/Node/Python/JVMのstub、`ForeignBox/ProxyBox`薄ラッパ。
---
# 代表ターゲット別メモ
* **C/Rust**最短。C-ABI直でOK。Rustは `#[no_mangle] extern "C"`。所有はNyash↔Rustのどちらかに寄せる二重所有禁止
* **Python**GILあり → `ProxyBox` 推奨。CPython C-APIで `PyObject*` を **ForeignBox**に入れ、操作はBus経由でワーカーに委譲。
* **NodeN-API**:イベントループを壊さないよう `ProxyBox`postMessage/uv\_queue\_work。短い同期関数は `ForeignBox`でも可。
* **JVM/.NET**JNI/P-Invoke。**Pin** が要る。`SafeHandle`/`PhantomReference`でFinalizer橋を作る。
* **WASM**`ny_host_*` を **import**。データはリニアメモリへ `Bytes`/`Str` で搬送。
---
# 最小サンプル(イメージ)
**1) Rustの画像ライブラリを包む**
```rust
#[no_mangle] extern "C" fn ny_img_load(path:*const c_char) -> *mut Image { ... }
#[no_mangle] extern "C" fn ny_img_resize(img:*mut Image, w:i32, h:i32) -> *mut Image { ... }
#[no_mangle] extern "C" fn ny_img_free(img:*mut Image) { ... }
```
**2) NyIDL → 自動生成Nyash側**
```nyash
extern fn ny_img_load(path: str) -> ForeignBox<Image> effects io
extern fn ny_img_resize(img: ForeignBox<Image>, w:int,h:int) -> ForeignBox<Image> effects mut
extern fn ny_img_free(img: ForeignBox<Image>) effects io
static box Image {
init { ForeignBox<Image> h }
fini { ny_img_free(h) } // ★ 所有はNyash側強1
fn resize(w:int,h:int) -> Image { Image{ ny_img_resize(h,w,h) } }
}
```
**3) 使う側**
```nyash
let img = Image.load("cat.png")
let small = img.resize(320, 200) // 所有/解放はBox/finiに任せる
```
---
# チェックリスト(安全に増やすための型紙)
* [ ] **どちらが強所有か**を最初に決めた強1・弱は逆
* [ ] 例外/エラーは**戻り値に正規化**?(他言語の例外は境界で捕捉)
* [ ] **Pin/Finalizer** 必要なターゲットJVM/.NET/Python
* [ ] `pure/mut/io` は宣言した?(最適化/バス選択の鍵)
* [ ] 境界を跨ぐなら **ProxyBox + Bus** にした?(スレッド/GIL/loop安全
---
# これで得られるもの
* **インスタント多言語資産**既存ライブラリを“箱に詰めて”即Nyashで使える
* **寿命の一貫性****強1weak/lookfini**で、外部資源も**確定的に回収**
* **配布の柔軟性**WASM/VM/ネイティブのどれでも同じIDLから出荷
---
“全部、箱に閉じ込める”を**設計として正式化**すれば、実装は機械的になる。
やるならまず **NyIDLの最小仕様****C-ABIの`ny_host_*`** を1ファイルに切ろう。
そこさえ決まれば、**あらゆる言語→Nyash** と **Nyash→あらゆる実行系** が綺麗に繋がるにゃ。