selfhost(pyvm): MiniVmPrints – prefer JSON route early-return (ok==1) to avoid fallback loops; keep default behavior unchanged elsewhere
This commit is contained in:
@ -1,10 +1,10 @@
|
||||
# Nyash ABI Minimal Core and Evolution Strategy
|
||||
|
||||
目的
|
||||
- 極小コアのみABI凍結し、将来拡張は交渉+予約+フォールバックで吸収する。
|
||||
- 極小コアのABIを長期安定化(仕様固定)し、将来拡張は交渉+予約+フォールバックで吸収する。
|
||||
- VM/JIT/プラグインを同じ枠組み(TypeBox + vtable + NyrtValue)に統一する。
|
||||
|
||||
最小コア(凍結対象)
|
||||
最小コア(安定化対象)
|
||||
- NyrtValue: 16B固定 `#[repr(C)]`(`tag:u32 | reserved:u32 | payload:u64`)
|
||||
- InstanceHeader: 先頭に `vtbl:*const NyVTable, refcnt:u32, flags:u32`(実体は不透明)
|
||||
- NyMethodFn: `fn(ctx:*mut VmCtx, recv:*mut InstanceHeader, args:*const NyrtValue, argc:u32, out:*mut NyrtValue) -> NyStatus`
|
||||
@ -66,4 +66,3 @@ typedef struct NyVEntry { NyMethodSig sig; NyMethodFn fn_ptr; } NyVEntry;
|
||||
- [ ] `execute_boxcall`: vtable直行→PIC→汎用の三段整備(STRICTガード)。
|
||||
- [ ] TypeRegistry: Array/Map/String の "get/set/len" を登録→vtable優先呼び出し。
|
||||
- [ ] ABIコンプライアンステストと同一実行テストの設計をdocsに反映。
|
||||
|
||||
|
||||
@ -1,94 +0,0 @@
|
||||
# NyRT C ABI v0 (JIT/AOT/Plugin 共通)
|
||||
|
||||
- 命名規則:
|
||||
- コア: `nyrt_*`
|
||||
- プラグイン: `nyplug_{name}_*`
|
||||
- 呼出規約: x86_64 SysV / aarch64 AAPCS64 / Win64(Cranelift `call_conv` と一致)
|
||||
- 型: `i32/i64/u64/double/void*` に限定。`bool` は `u8`。構造体は不透明ハンドル。
|
||||
- 互換性: `nyrt_abi_version()` / `nyplug_{name}_abi_version()`(v0=1)で fail-fast。
|
||||
|
||||
## 最小ヘッダ例(コア: nyrt.h)
|
||||
```c
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#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 基本
|
||||
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);
|
||||
|
||||
// GC/Safepoint
|
||||
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)
|
||||
```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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
## AOT(静的リンク)の流れ
|
||||
- CLIF から `.o` を出力(未解決: `nyrt_*` / `nyplug_*`)。
|
||||
- リンク(Linux/macOS の例):
|
||||
```bash
|
||||
# 1) NyRT静的ライブラリをビルド
|
||||
(cd crates/nyrt && cargo build --release)
|
||||
|
||||
# 2) プラグイン静的ライブラリ(必要なもの)をビルド
|
||||
(cd plugins/nyash-array-plugin && cargo build --release)
|
||||
(cd plugins/nyash-string-plugin && cargo build --release)
|
||||
(cd plugins/nyash-integer-plugin && cargo build --release)
|
||||
|
||||
# 3) ObjectModuleで生成した app.o を NyRT + plugins と静的リンク
|
||||
cc app.o \
|
||||
-L crates/nyrt/target/release \
|
||||
-L plugins/nyash-array-plugin/target/release \
|
||||
-L plugins/nyash-string-plugin/target/release \
|
||||
-L plugins/nyash-integer-plugin/target/release \
|
||||
-static -Wl,--whole-archive -lnyrt -Wl,--no-whole-archive \
|
||||
-lnyash_array_plugin -lnyash_string_plugin -lnyash_integer_plugin \
|
||||
-o app
|
||||
```
|
||||
- 実行: `./app`
|
||||
|
||||
補足(Phase 10.2 暫定→10.2b)
|
||||
- `.o` には暫定シム `nyash_plugin_invoke3_i64` が未解決として現れますが、`crates/nyrt` の `libnyrt.a` がこれを実装します。
|
||||
- 将来的に `nyrt_*` 命名へ整理予定(後方互換シムは残す)。
|
||||
|
||||
## 注意
|
||||
- 例外/パニックの越境は不可(戻り値/エラーコードで返す)。
|
||||
- C++ 側は必ず `extern "C"`、ELF は `visibility("default")`。
|
||||
- ABI 破壊変更は `*_v1` などの別シンボルで導入(v0は凍結)。
|
||||
@ -1,109 +0,0 @@
|
||||
# Nyash VM 実行基盤ガイド
|
||||
|
||||
最終更新: 2025-08-21(Phase 9.78 系対応)
|
||||
|
||||
本書は Nyash の VM バックエンド(MIR 実行機構)と、その周辺の実装・拡張ポイントをまとめた開発者向けドキュメントです。
|
||||
|
||||
## 全体像
|
||||
- 入力: `MirModule`(`mir::MirCompiler` が AST から生成)
|
||||
- 実行: `backend::vm::VM`
|
||||
- `execute_module` → `execute_function` → 命令列を逐次 `execute_instruction`
|
||||
- ランタイム DI: `NyashRuntime`
|
||||
- `box_registry`(統一 BoxFactory 経由の生成)
|
||||
- `box_declarations`(ユーザー定義 Box の宣言)
|
||||
- ライフサイクル: `ScopeTracker` により関数入退出で `fini()` を呼ぶ
|
||||
|
||||
## 主要ファイル
|
||||
- `src/backend/vm.rs` … VM 本体(命令ディスパッチ、Call/BoxCall、NewBox ほか)
|
||||
- `src/mir/*` … MIR 命令定義・Builder・Function/Module 管理
|
||||
- `src/runtime/nyash_runtime.rs` … ランタイムコンテナ(DI 受け皿)
|
||||
- `src/box_factory/*` … Builtin/User/Plugin の各 Factory 実装
|
||||
- `src/runtime/plugin_loader_v2.rs` … BID-FFI v2 ローダ(ExternCall/Plugin 呼び出し)
|
||||
|
||||
関連ドキュメント
|
||||
- 動的プラグインの流れ: [dynamic-plugin-flow.md](./dynamic-plugin-flow.md)
|
||||
- 命令セットダイエット: [mir-26-instruction-diet.md](./mir-26-instruction-diet.md)
|
||||
- MIR→VMマッピング: [mir-to-vm-mapping.md](./mir-to-vm-mapping.md)
|
||||
|
||||
## 実行フロー(概略)
|
||||
1) Nyash コード → Parser → AST → `MirCompiler` で `MirModule` を生成
|
||||
2) `VM::with_runtime(runtime)` で実行(`execute_module`)
|
||||
3) 命令ごとに処理:
|
||||
- `Const/Load/Store/BinOp/...` など基本命令
|
||||
- `NewBox`: 統一レジストリ経由で Box 生成
|
||||
- `Call`: `"{Box}.{method}/{N}"` の関数名で MIR 関数呼び出し
|
||||
- `BoxCall`: Box の種類で分岐(ユーザー定義/ビルトイン/プラグイン)
|
||||
- `ExternCall`: `env.console`/`env.canvas` 等をローダへ委譲
|
||||
|
||||
## Box 生成と種別
|
||||
- 生成パス(`NewBox`)は `NyashRuntime::box_registry` が担当
|
||||
- Builtin: `BuiltinBoxFactory` が直接生成
|
||||
- User-defined: `UserDefinedBoxFactory` → `InstanceBox`
|
||||
- Plugin: プラグイン設定(`nyash.toml`)に従い BID-FFI で `PluginBoxV2`
|
||||
- **動的解決の詳細**: [dynamic-plugin-flow.md](./dynamic-plugin-flow.md) を参照
|
||||
|
||||
## birth/メソッドの関数化(MIR)
|
||||
- Lowering ポリシー: AST の `new` は `NewBox` に続けて `BoxCall("birth")` を自動挿入
|
||||
- Box 宣言の `birth/N` と通常メソッド `method/N` は `"{Box}.{name}/{N}"` の MIR 関数に関数化
|
||||
- 命名例: `Person.birth/1`, `Person.greet/0`
|
||||
- 引数: `me` が `%0`、ユーザー引数が `%1..N`(`me` は `MirType::Box(BoxName)`)
|
||||
- 戻り値型: 明示の `return <expr>` があれば `Unknown`、なければ `Void`(軽量推定)
|
||||
- `VM` の呼び出し
|
||||
- `Call` 命令: 関数名(`Const(String)`)を解決 → `call_function_by_name`
|
||||
- `BoxCall` 命令: 下記の種類分岐に委譲
|
||||
|
||||
## BoxCall の種類分岐
|
||||
- ユーザー定義 Box(`InstanceBox`)
|
||||
- `BoxCall("birth")`: `"{Box}.birth/{argc}"` を `Call` 等価で実行
|
||||
- 通常メソッド: `"{Box}.{method}/{argc}"` を `Call` 等価で実行
|
||||
- プラグイン Box(`PluginBoxV2`)
|
||||
- `PluginLoaderV2::invoke_instance_method(box_type, method, instance_id, args)` を呼び出し
|
||||
- 引数/戻り値は最小 TLV でやり取り(タグ: 1=Int64, 2=String, 3=Bool)
|
||||
- 戻り値なしは `void` 扱い
|
||||
- ビルトイン Box
|
||||
- 現状は VM 内の簡易ディスパッチ(`String/Integer/Array/Math` を中心にサポート)
|
||||
- 将来はビルトインも MIR 関数へ寄せる計画
|
||||
|
||||
## ExternCall(ホスト機能)
|
||||
- `env.console.log`, `env.canvas.*` などを `PluginLoaderV2::extern_call` に委譲
|
||||
- いまは最小実装(ログ出力・スタブ)。将来は BID-FFI 由来の外部機能にも接続予定
|
||||
|
||||
## ライフサイクル管理(ScopeTracker)
|
||||
- `VM` は関数入退出で `push_scope()/pop_scope()` を実行
|
||||
- 退出時に登録 Box を `fini()`(`InstanceBox`/`PluginBoxV2`)
|
||||
- Interpreter でも同思想で `restore_local_vars()` にて `fini()` 呼び出し
|
||||
|
||||
## ランタイム DI(依存注入)
|
||||
- `NyashRuntime`
|
||||
- `box_declarations`: AST から収集(Box 宣言)
|
||||
- `box_registry`: Builtin/User/Plugin の順で探索・生成
|
||||
- Runner(CLI 実行)
|
||||
- AST パース後、Box 宣言を `runtime.box_declarations` へ登録
|
||||
- `UserDefinedBoxFactory` をレジストリに注入 → VM を `with_runtime(runtime)` で起動
|
||||
|
||||
## 最適化
|
||||
- 置換: `new X(...).m(...)` → 直接 `Call("X.m/N", me+args)` に最適化
|
||||
- 拡張余地: 変数へ束縛してからの `.m()` も静的に決まる範囲で `Call` 化可能
|
||||
- 戻り値型: 軽量推定。将来は `MirType` 推論/注釈の強化
|
||||
|
||||
## 制約と今後
|
||||
- ビルトインのメソッドはまだ簡易ディスパッチ(MIR 関数化は未)
|
||||
- プラグインの TLV は最小型(Int/String/Bool)のみ。拡張予定
|
||||
- 例外(throw/catch)は簡易扱い(将来の unwind/handler 連携は別設計)
|
||||
|
||||
## テスト
|
||||
- 単体/E2E(抜粋): `src/backend/vm.rs` の `#[cfg(test)]`
|
||||
- `test_vm_user_box_birth_and_method` … `new Person("Alice").greet()` → "Hello, Alice"
|
||||
- `test_vm_user_box_var_then_method` … 変数に束縛→メソッド→戻り値(11)
|
||||
- `test_vm_extern_console_log` … ExternCall の void 確認
|
||||
- 実行例
|
||||
- `cargo test -j32`(plugins 機能や環境依存に注意)
|
||||
|
||||
## 実行(参考)
|
||||
- VMルート実行(Runner 経由)
|
||||
- `nyash --backend vm your_file.nyash`
|
||||
- WASM(ブラウザ)
|
||||
- plugins は無効。ExternCall はスタブ。MIR 関数はそのまま再利用される設計
|
||||
|
||||
---
|
||||
開発ポリシー: 小さく安全に最適化 → MIR/VM の共有ロジックを増やす → Extern/Plugin を段階統合 → WASM/LLVM/JIT へ横展開。
|
||||
@ -1,108 +0,0 @@
|
||||
# Nyash 設計図(アーキテクチャ概要)
|
||||
|
||||
最終更新: 2025-08-21(Phase 9.78b〜3 反映)
|
||||
|
||||
本書はNyashの実装設計を、バックエンド共通で理解できる単一ドキュメントとしてまとめたもの。言語コア、MIR、インタープリター/VM統合、ランタイム/プラグイン、ビルドと配布の観点を俯瞰する。
|
||||
|
||||
## レイヤー構成
|
||||
|
||||
- 構文/AST: `tokenizer`, `parser`, `ast`
|
||||
- モデル層: `core::model`(BoxDeclaration等の純粋データ)
|
||||
- ランタイム層: `runtime`(UnifiedBoxRegistry, PluginLoader, NyashRuntime)
|
||||
- 実行戦略層: `interpreter`(AST実行)/ `mir`+`backend::vm`(MIR実行)/ 将来 `wasm`/`llvm`
|
||||
- 付帯基盤: `box_factory`, `instance_v2`, `scope_tracker`, `boxes/*`, `stdlib`
|
||||
|
||||
## コア概念
|
||||
|
||||
- Everything is Box: すべての値はBox(ビルトイン、ユーザー定義、プラグイン)
|
||||
- 統一コンストラクタ: `birth(args)`(packはビルトイン継承内部用に透過化)
|
||||
- 明示デリゲーション: `box Child from Parent` と `from Parent.method()`
|
||||
- 厳密変数宣言/スコープ安全: `local`, `outbox`、スコープ退出時の`fini`一元化
|
||||
|
||||
## モデル層(core::model)
|
||||
|
||||
- `BoxDeclaration` を `interpreter` から分離し `core::model` に移動
|
||||
- name, fields, methods, constructors(birth/N), extends, implements, type_parameters
|
||||
- 実行戦略非依存の純粋データ
|
||||
|
||||
## ランタイム層(runtime)
|
||||
|
||||
- `NyashRuntime`
|
||||
- `box_registry: UnifiedBoxRegistry`(ビルトイン/ユーザー定義/プラグインを順序付き検索)
|
||||
- `box_declarations: RwLock<HashMap<String, BoxDeclaration>>`
|
||||
- BuilderでDI(`with_factory`)可能。Interpreter/VMから共有・注入できる
|
||||
- `UnifiedBoxRegistry`
|
||||
- `Arc<dyn BoxFactory>` の列で優先解決(builtin > user > plugin)
|
||||
- `create_box(name, args)` の統一エントリ
|
||||
- `BoxFactory`
|
||||
- builtin: 全ビルトインBoxの生成
|
||||
- user_defined: `BoxDeclaration`に基づき`InstanceBox`生成(birthは実行戦略側で)
|
||||
- plugin: BID-FFI準拠のプラグインBox(将来のExternCall/MIR接続)
|
||||
|
||||
## 実行戦略(Interpreter / VM)
|
||||
|
||||
- Interpreter(AST実行)
|
||||
- `SharedState` は段階的に分解し、宣言等を `NyashRuntime` に寄せ替え
|
||||
- 生成は統一レジストリへ委譲、コンストラクタ実行は`birth/N`のASTを実行
|
||||
|
||||
- VM (MIR実行)
|
||||
- `VM::with_runtime(runtime)` でDI、`NewBox`は`runtime.box_registry.create_box`へ
|
||||
- `ScopeTracker`でスコープ退出時に`fini`(InstanceBox/PluginBox)
|
||||
- birth/メソッドのMIR関数化(Phase 2/3):
|
||||
- Builderが `new` を `NewBox` + `BoxCall("birth")` に展開
|
||||
- Box宣言の `birth/N` と通常メソッド(`method/N`)を `"{Box}.{name}/{N}"` のMIR関数へ関数化
|
||||
- VMの`BoxCall`は `InstanceBox` なら該当MIR関数へディスパッチ(me + 引数)
|
||||
|
||||
## MIR(中間表現)
|
||||
|
||||
- 目的: バックエンド共通の最適化/実行基盤(VM/LLVM/WASM/JIT)
|
||||
- Builder
|
||||
- AST→MIR lowering。`ASTNode::New`→`NewBox`(+ `BoxCall("birth")`)
|
||||
- `ASTNode::BoxDeclaration` の `constructors` / `methods` をMIR関数化
|
||||
- if/loop/try-catch/phi等の基本構造を提供
|
||||
- VM
|
||||
- Stackベースの簡易実装→順次強化中
|
||||
- `call_function_by_name` による関数呼び出しフレームの最小実装
|
||||
|
||||
## インスタンス表現(InstanceBox)
|
||||
|
||||
- 統一フィールド`fields_ng: HashMap<String, NyashValue>`
|
||||
- メソッドASTを保持(ユーザー定義時)
|
||||
- `fini()`による簡易解放(将来、リソースBoxは明示やRAII連携)
|
||||
|
||||
## ライフサイクル統一(fini)
|
||||
|
||||
- Interpreter: スコープ復帰時に`InstanceBox.fini()`等を呼ぶ
|
||||
- VM: `ScopeTracker`で関数入退出時に登録Boxを`fini`
|
||||
|
||||
## プラグイン(BID-FFI)
|
||||
|
||||
- v2ローダ(`runtime::plugin_loader_v2`)とテスター完備
|
||||
- 目標: MIRの`ExternCall`→ローダに接続し、VM/LLVM/WASMで共通パス
|
||||
|
||||
## Runner/ビルド
|
||||
|
||||
- VMモード:
|
||||
1) ASTパース
|
||||
2) ランタイムにBox宣言収集 + UserDefinedBoxFactory登録
|
||||
3) MIRコンパイル
|
||||
4) VMを`with_runtime`で起動し実行
|
||||
|
||||
## 進行中フェーズと方針
|
||||
|
||||
- Phase 9.78b: Interpreter/VMのモデル・ランタイム共有(完了)
|
||||
- Phase 2/3(実質): birth/メソッドのMIR関数化とVMディスパッチ(実装済・基本動作)
|
||||
- 次:
|
||||
- BoxCall→Callへの段階的置換(型決定済みのとき)
|
||||
- ExternCallの実装(VM→プラグイン)
|
||||
- WASM/LLVMバックエンドへMIR関数の共有
|
||||
|
||||
## 参考ファイル
|
||||
|
||||
- `src/core/model.rs`(BoxDeclaration)
|
||||
- `src/runtime/nyash_runtime.rs`(NyashRuntime)
|
||||
- `src/box_factory/*`(builtin/user_defined/plugin)
|
||||
- `src/mir/*`(builder/instruction/function/etc.)
|
||||
- `src/backend/vm.rs`(VM実行)
|
||||
- `src/interpreter/*`(AST実行)
|
||||
|
||||
@ -1,118 +0,0 @@
|
||||
# Dynamic Plugin Flow (VM × Registry × PluginLoader v2)
|
||||
|
||||
最終更新: 2025-08-23
|
||||
|
||||
目的
|
||||
- Nyash 実行時に、MIR→VM→Registry→Plugin の呼び出しがどう流れるかを図解・手順で把握する。
|
||||
- TLVエンコード、ResultBoxの扱い、Handleのライフサイクル、nyash.tomlとの連携を1枚で理解する。
|
||||
|
||||
## ハイレベル流れ(シーケンス)
|
||||
|
||||
```
|
||||
Nyash Source ──▶ MIR (Builder)
|
||||
│ (BoxCall/NewBox/…)
|
||||
▼
|
||||
VM Executor
|
||||
│ (BoxCall dispatch)
|
||||
├─ InstanceBox → Lowered MIR 関数呼び出し
|
||||
├─ BuiltinBox → VM内ディスパッチ
|
||||
└─ PluginBoxV2 → PluginLoader v2
|
||||
│ (nyash.toml を参照)
|
||||
▼
|
||||
Invoke (TLV)
|
||||
│
|
||||
▼
|
||||
Plugin (lib*.so)
|
||||
│ (戻り値をTLVで返却)
|
||||
▼
|
||||
Loader でデコード
|
||||
│ (returns_result/Handle/型)
|
||||
▼
|
||||
NyashBox (ResultBox/PluginBoxV2/基本型)
|
||||
│
|
||||
▼
|
||||
VM に復帰
|
||||
```
|
||||
|
||||
## 主要構成要素
|
||||
- MIR: `MirInstruction::{BoxCall, NewBox, …}` で外部呼び出し箇所を明示。
|
||||
- VM: `src/backend/vm.rs`
|
||||
- InstanceBoxは `{Class}.{method}/{argc}` のLowered関数へ呼び出し
|
||||
- BuiltinはVM内の簡易ディスパッチ
|
||||
- PluginBoxV2は Loader v2 へ委譲
|
||||
- Registry/Runtime: `NyashRuntime` + `box_registry` + `plugin_loader_v2`
|
||||
- `nyash.toml` の `libraries.*` を読み込み、Box名→ライブラリ名、type_id、method_id等を集約
|
||||
|
||||
## NewBox(生成)
|
||||
1) MIRの `NewBox { box_type, args }`
|
||||
2) VM: `runtime.box_registry` に `box_type` を問い合わせ
|
||||
3) PluginBoxの場合、Loader v2が `birth(method_id=0)` を TLV で呼び出し
|
||||
4) Pluginは `type_id` と新規 `instance_id` を返却 → Loader は `PluginBoxV2` を構築
|
||||
5) VMは `ScopeTracker` に登録(スコープ終了で `fini` を呼ぶ)
|
||||
|
||||
## BoxCall(メソッド呼び出し)
|
||||
- InstanceBox: Lowered関数 `{Class}.{method}/{argc}` を MIR/VM内で実行
|
||||
- Builtin: VM内の `call_box_method` で対応(StringBox.length 等)
|
||||
- PluginBoxV2: Loader v2 の `invoke_instance_method` で TLV を組み立てて呼び出し
|
||||
|
||||
## TLV(Type-Length-Value)
|
||||
- ヘッダ: `u16 ver=1`, `u16 argc`
|
||||
- 各引数: `u8 tag`, `u8 reserved`, `u16 size`, `payload`
|
||||
- 主な tag:
|
||||
- 2 = i32 (size=4)
|
||||
- 6 = string, 7 = bytes
|
||||
- 8 = Handle(BoxRef) → payload = `u32 type_id || u32 instance_id`
|
||||
- 9 = void (size=0)
|
||||
|
||||
## 戻り値のマッピング(重要)
|
||||
- `returns_result=false`
|
||||
- tag=8 → PluginBoxV2(Handle)
|
||||
- tag=2 → IntegerBox、tag=6/7 → StringBox、tag=9 → void
|
||||
- `returns_result=true`(ResultBoxで包む)
|
||||
- tag=8/2 → `Result.Ok(value)`
|
||||
- tag=6/7 → `Result.Err(ErrorBox(message))`(Netプラグインなどがエラー文字列を返却)
|
||||
- tag=9 → `Result.Ok(void)`
|
||||
|
||||
補足
|
||||
- VM内で ResultBox の `isOk/getValue/getError` をディスパッチ済み
|
||||
- `toString()` フォールバックにより任意の Box を安全に文字列化可能
|
||||
|
||||
## Handle(BoxRef)のライフサイクル
|
||||
- Loaderは `(type_id, instance_id)` を `PluginBoxV2` としてラップ
|
||||
- `share_box()` は同一インスタンス共有、`clone_box()` はプラグインの birth を呼ぶ(設計意図による)
|
||||
- `fini` は `ScopeTracker` または Drop で保証(プラグインの `fini_method_id` を参照)
|
||||
|
||||
## 具体例(HttpClientBox.get)
|
||||
1) Nyash: `r = cli.get(url)`
|
||||
2) MIR: `BoxCall`(returns_result=true)
|
||||
3) VM→Loader: TLV(url = tag=6)
|
||||
4) Loader→Plugin: `invoke(type_id=HttpClient, method_id=get)`
|
||||
5) Plugin:
|
||||
- 接続成功: `Handle(HttpResponse)` を返す → Loaderは `Result.Ok(PluginBoxV2)`
|
||||
- 接続失敗: `String("connect failed …")` を返す → Loaderは `Result.Err(ErrorBox)`
|
||||
6) Nyash: `if r.isOk() { resp = r.getValue() … } else { print(r.getError().toString()) }`
|
||||
|
||||
## nyash.toml 連携
|
||||
- 例: `libraries."libnyash_net_plugin.so".HttpClientBox.methods.get = { method_id = 1, args=["url"], returns_result = true }`
|
||||
- Loaderは `method_id` と `returns_result` を参照し、TLVと戻り値のラップ方針を決定
|
||||
- 型宣言(args/kind)により、引数のTLVタグ検証を実施(不一致は InvalidArgs)
|
||||
|
||||
## デバッグTips
|
||||
- `NYASH_DEBUG_PLUGIN=1`: VM→Plugin の TLV ヘッダと先頭64バイトをプレビュー
|
||||
- `NYASH_NET_LOG=1 NYASH_NET_LOG_FILE=net_plugin.log`: Netプラグイン内部ログ
|
||||
- `--dump-mir --mir-verbose`: if/phi/return などのMIRを確認
|
||||
- `--vm-stats --vm-stats-json`: 命令使用のJSONを取得(hot pathの裏取りに)
|
||||
|
||||
## 将来の整合・改善
|
||||
- nyash.toml に ok側の戻り型(例: `ok_returns = "HttpResponseBox"`)を追加 → Loader判定の厳密化
|
||||
- Verifier強化: use-before-def across merge の検出(phi誤用を早期に発見)
|
||||
- BoxCall fast-path の最適化(hot path最優先)
|
||||
|
||||
関連
|
||||
- `docs/reference/plugin-system/net-plugin.md`
|
||||
- `docs/reference/architecture/mir-to-vm-mapping.md`
|
||||
- `docs/reference/architecture/mir-26-instruction-diet.md`
|
||||
|
||||
See also
|
||||
- `docs/examples/http_result_patterns.md` - HTTPのResult挙動(unreachable/404/500)のE2E例
|
||||
- `docs/VM_README.md` - VM統計とプラグイン周りの既知制約
|
||||
@ -1,527 +0,0 @@
|
||||
# Nyash実行バックエンド完全ガイド(推奨4経路 + 任意 JIT)
|
||||
|
||||
Nyashプログラミング言語は、**Everything is Box**哲学を維持しながら、推奨4経路(Interpreter / VM / Cranelift AOT / LLVM AOT)を中心に運用します。任意で Cranelift JIT ランタイムを有効化できます。
|
||||
|
||||
## 🚀 実行方式一覧
|
||||
|
||||
| 実行方式 | 用途 | 特徴 | パフォーマンス |
|
||||
|---------|------|------|---------------|
|
||||
| **インタープリター** | 開発・デバッグ | 直接AST実行、詳細ログ | 低速・高機能 |
|
||||
| **VM** | 本番・高速実行 | MIR→VM実行 | 中速・最適化 |
|
||||
| **WASM** | Web・サンドボックス | MIR→WASM変換 | 高速・移植性 |
|
||||
| **Cranelift AOT** | ネイティブEXE | CLIF→オブジェクト→リンク | 高速・軽量 |
|
||||
| **LLVM AOT** | ネイティブEXE | LLVM18/inkwell | 高速・高最適化 |
|
||||
|
||||
## 📋 CLIオプション
|
||||
|
||||
### 基本実行(インタープリター)
|
||||
```bash
|
||||
# デフォルト:インタープリター実行
|
||||
nyash program.nyash
|
||||
|
||||
# デバッグ燃料制限付き
|
||||
nyash --debug-fuel 50000 program.nyash
|
||||
|
||||
# 無制限デバッグ燃料
|
||||
nyash --debug-fuel unlimited program.nyash
|
||||
```
|
||||
|
||||
### VM実行
|
||||
```bash
|
||||
# VM実行(高速)
|
||||
nyash --backend vm program.nyash
|
||||
```
|
||||
|
||||
### MIR操作
|
||||
```bash
|
||||
# MIR表示(中間表現確認)
|
||||
nyash --dump-mir program.nyash
|
||||
|
||||
# MIR検証
|
||||
nyash --verify program.nyash
|
||||
|
||||
# 詳細MIR情報
|
||||
nyash --mir-verbose --dump-mir program.nyash
|
||||
```
|
||||
|
||||
### WASM生成・実行
|
||||
```bash
|
||||
# WASMコンパイル(WAT出力)
|
||||
nyash --compile-wasm program.nyash
|
||||
|
||||
# ファイル出力
|
||||
nyash --compile-wasm program.nyash -o output.wat
|
||||
|
||||
# ブラウザで実行可能なWASMを生成
|
||||
nyash --compile-wasm program.nyash -o public/app.wat
|
||||
```
|
||||
|
||||
### Cranelift AOT(ネイティブEXE)
|
||||
Cranelift ベースの AOT パイプライン。Egui Hello の EXE 化は `docs/guides/cranelift_aot_egui_hello.md` を参照。
|
||||
|
||||
### LLVM AOT(ネイティブEXE)
|
||||
```bash
|
||||
# ビルド時に wasm-backend feature が必要
|
||||
cargo build --release --features wasm-backend
|
||||
|
||||
# AOTコンパイル(.cwasm生成)
|
||||
nyash --compile-native program.nyash -o program
|
||||
# または
|
||||
nyash --aot program.nyash -o program
|
||||
|
||||
# 注意: 現在は完全なスタンドアロン実行ファイルではなく、
|
||||
# wasmtime用のプリコンパイル済みWASM(.cwasm)が生成されます
|
||||
```
|
||||
|
||||
### ⚡ ベンチマーク(パフォーマンス測定)
|
||||
```bash
|
||||
# 全バックエンド性能比較(デフォルト5回実行)
|
||||
nyash --benchmark
|
||||
|
||||
# 実行回数指定(統計精度向上)
|
||||
nyash --benchmark --iterations 100
|
||||
|
||||
# 結果をファイル保存
|
||||
nyash --benchmark --iterations 50 > benchmark_results.txt
|
||||
```
|
||||
|
||||
## 🎯 インタープリター(デフォルト)
|
||||
|
||||
### 特徴
|
||||
- **用途**: 開発・デバッグ・学習
|
||||
- **実行**: AST直接実行
|
||||
- **速度**: 最も低速
|
||||
- **機能**: 最も詳細なデバッグ情報
|
||||
|
||||
### 利点
|
||||
- 詳細な実行ログ
|
||||
- エラー位置の正確な特定
|
||||
- リアルタイム変数監視
|
||||
- メモリ使用量詳細表示
|
||||
|
||||
### デバッグ燃料システム
|
||||
```bash
|
||||
# パーサー無限ループ対策
|
||||
nyash --debug-fuel 10000 problem.nyash
|
||||
|
||||
# エラー例:
|
||||
🚨 PARSER INFINITE LOOP DETECTED at method call argument parsing
|
||||
🔍 Current token: IDENTIFIER("from") at line 17
|
||||
```
|
||||
|
||||
## 🏎️ VM実行(高速)
|
||||
|
||||
### 特徴
|
||||
- **用途**: 本番実行・性能重視
|
||||
- **実行**: AST→MIR→VM実行
|
||||
- **速度**: 中〜高速
|
||||
- **機能**: 最適化済み
|
||||
|
||||
### 実行パイプライン
|
||||
```
|
||||
Nyashソース → AST → MIR → VM → 結果
|
||||
```
|
||||
|
||||
### MIR(中間表現)
|
||||
```bash
|
||||
# MIR確認
|
||||
nyash --dump-mir simple.nyash
|
||||
|
||||
# 出力例:
|
||||
; MIR Module: main
|
||||
define void @main() {
|
||||
bb0:
|
||||
0: safepoint
|
||||
1: %0 = const 42
|
||||
2: %1 = const 8
|
||||
3: %2 = %0 Add %1
|
||||
4: print %2
|
||||
5: ret %2
|
||||
}
|
||||
```
|
||||
|
||||
### VMの特徴
|
||||
- **SSA形式**: 静的単一代入
|
||||
- **基本ブロック**: 制御フロー最適化
|
||||
- **効果追跡**: 副作用の管理
|
||||
- **型安全**: 実行時型チェック
|
||||
- **対応状況**: 命令ごとの実装は「MIR → VM Mapping」を参照(欠落・暫定箇所の把握に)
|
||||
- docs/reference/architecture/mir-to-vm-mapping.md
|
||||
|
||||
### 🧮 VM実行統計(命令カウント・時間計測)
|
||||
VMバックエンドは命令ごとの実行回数と総実行時間(ms)を出力できます。
|
||||
|
||||
有効化方法(CLI推奨):
|
||||
```bash
|
||||
# 人間向け表示
|
||||
nyash --backend vm --vm-stats program.nyash
|
||||
|
||||
# JSON出力(機械可読)
|
||||
nyash --backend vm --vm-stats --vm-stats-json program.nyash
|
||||
```
|
||||
|
||||
環境変数でも制御可能:
|
||||
```bash
|
||||
NYASH_VM_STATS=1 ./target/release/nyash --backend vm program.nyash
|
||||
NYASH_VM_STATS=1 NYASH_VM_STATS_JSON=1 ./target/release/nyash --backend vm program.nyash
|
||||
# もしくは NYASH_VM_STATS_FORMAT=json でも可
|
||||
```
|
||||
|
||||
JSON出力例:
|
||||
```json
|
||||
{
|
||||
"total": 1234,
|
||||
"elapsed_ms": 5.123,
|
||||
"counts": { "Const": 200, "BinOp": 300, "Return": 100 },
|
||||
"top20": [ { "op": "BinOp", "count": 300 } ],
|
||||
"timestamp_ms": 1724371200000
|
||||
}
|
||||
```
|
||||
|
||||
ベンチマークと併用して、ホット命令の抽出・命令セット最適化に活用できます。
|
||||
|
||||
### ⏱️ 協調スケジューラ(Phase 10.6b)
|
||||
- VMはMIRの`safepoint`命令到達時にランタイムのスケジューラ`poll()`を呼びます。
|
||||
- シングルスレ実装(既定)では、`spawn`/`spawn_after`で投入されたタスクを safepoint ごとに最大N件実行します。
|
||||
- 制御: `NYASH_SCHED_POLL_BUDGET`(既定: 1)でNを指定。
|
||||
|
||||
デモ実行:
|
||||
```bash
|
||||
cargo build --release -j32
|
||||
NYASH_SCHED_DEMO=1 NYASH_SCHED_POLL_BUDGET=2 \
|
||||
./target/release/nyash --backend vm examples/scheduler_demo.nyash
|
||||
```
|
||||
|
||||
### 🧹 GCトレーシング(Phase 10.4)
|
||||
- カウンタ有効化: `NYASH_GC_COUNTING=1`(CountingGcを注入)
|
||||
- 出力レベル: `NYASH_GC_TRACE=1/2/3`
|
||||
- 1: safepoint/barrierログ+カウンタ
|
||||
- 2: + ルート内訳
|
||||
- 3: + depth=2 リーチャビリティ概要
|
||||
- 厳格検証: `NYASH_GC_BARRIER_STRICT=1`(Write-Barrier未増分ならpanic)
|
||||
|
||||
```bash
|
||||
NYASH_GC_COUNTING=1 NYASH_GC_TRACE=2 \
|
||||
./target/release/nyash --backend vm examples/scheduler_demo.nyash
|
||||
```
|
||||
|
||||
#### Boxからの切替(GcConfigBox)
|
||||
環境変数ではなくNyashスクリプトから切り替える場合は `GcConfigBox` を使います。`apply()` で環境に反映され、その後の実行に適用されます。
|
||||
|
||||
```nyash
|
||||
// 最小例: CountingGc + trace をオン
|
||||
static box Main {
|
||||
main() {
|
||||
local G
|
||||
G = new GcConfigBox()
|
||||
G = G.setFlag("counting", true)
|
||||
G = G.setFlag("trace", true) // 1/2/3 は環境。Box では on/off を切替
|
||||
G.apply() // ← ここで反映
|
||||
return "ok"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
代表デモ(書き込みバリア/カウンタの可視化):
|
||||
```bash
|
||||
./target/release/nyash --backend vm examples/gc_counting_demo.nyash
|
||||
```
|
||||
|
||||
## 🌐 WASM実行(Web対応)
|
||||
|
||||
### 特徴
|
||||
- **用途**: Webブラウザ・サンドボックス実行
|
||||
- **実行**: AST→MIR→WASM→ブラウザ
|
||||
- **速度**: 最高速(ネイティブ並み)
|
||||
- **移植性**: 全プラットフォーム対応
|
||||
|
||||
### 実行パイプライン
|
||||
```
|
||||
Nyashソース → AST → MIR → WAT → WASM → ブラウザ
|
||||
```
|
||||
|
||||
### 生成例
|
||||
```nyash
|
||||
// Nyashコード
|
||||
static box Main {
|
||||
main() {
|
||||
return 42
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```wat
|
||||
; 生成されるWAT
|
||||
(module
|
||||
(import "env" "print" (func $print (param i32) ))
|
||||
(memory (export "memory") 1)
|
||||
(global $heap_ptr (mut i32) (i32.const 2048))
|
||||
(func $main (local $0 i32)
|
||||
nop ; safepoint
|
||||
i32.const 42 ; const 42
|
||||
local.set $0 ; store to local
|
||||
local.get $0 ; load from local
|
||||
return ; return 42
|
||||
)
|
||||
(export "main" (func $main))
|
||||
)
|
||||
```
|
||||
|
||||
### Web実行
|
||||
```html
|
||||
<!-- HTMLで読み込み -->
|
||||
<script>
|
||||
async function loadNyashWasm() {
|
||||
const response = await fetch('output.wat');
|
||||
const watText = await response.text();
|
||||
|
||||
const wabt = await WabtModule();
|
||||
const module = wabt.parseWat('output.wat', watText);
|
||||
const binary = module.toBinary({});
|
||||
|
||||
const importObject = {
|
||||
env: { print: console.log }
|
||||
};
|
||||
|
||||
const wasmModule = await WebAssembly.instantiate(binary.buffer, importObject);
|
||||
const result = wasmModule.instance.exports.main(); // 42
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 🚀 AOT/ネイティブコンパイル(実験的)
|
||||
|
||||
### 特徴
|
||||
- **用途**: 高速起動・配布用実行ファイル
|
||||
- **実行**: AST→MIR→WASM→プリコンパイル済みネイティブ
|
||||
- **速度**: 最高速(JIT起動オーバーヘッドなし)
|
||||
- **制約**: wasmtimeランタイムが必要
|
||||
|
||||
### コンパイルパイプライン
|
||||
```
|
||||
Nyashソース → AST → MIR → WASM → .cwasm(プリコンパイル済み)
|
||||
```
|
||||
|
||||
### ビルド方法
|
||||
```bash
|
||||
# 1. wasm-backend feature付きでNyashをビルド
|
||||
cargo build --release --features wasm-backend
|
||||
|
||||
# 2. AOTコンパイル実行
|
||||
./target/release/nyash --compile-native hello.nyash -o hello
|
||||
# または短縮形
|
||||
./target/release/nyash --aot hello.nyash -o hello
|
||||
|
||||
# 3. 生成されたファイル
|
||||
# hello.cwasm が生成される(wasmtimeプリコンパイル形式)
|
||||
```
|
||||
|
||||
### 現在の実装状況
|
||||
- ✅ MIR→WASM変換
|
||||
- ✅ WASM→.cwasm(wasmtimeプリコンパイル)
|
||||
- ❌ 完全なスタンドアロン実行ファイル生成(TODO)
|
||||
- ❌ ランタイム埋め込み(将来実装予定)
|
||||
|
||||
### 使用例
|
||||
```bash
|
||||
# コンパイル
|
||||
./target/release/nyash --aot examples/hello_world.nyash -o hello_aot
|
||||
|
||||
# 実行(将来的な目標)
|
||||
# ./hello_aot # 現在は未実装
|
||||
|
||||
# 現在は wasmtime で実行
|
||||
# wasmtime --precompiled hello_aot.cwasm
|
||||
```
|
||||
|
||||
### 技術的詳細
|
||||
AOTバックエンドは内部的に以下の処理を行います:
|
||||
1. **MirCompiler**: NyashコードをMIRに変換
|
||||
2. **WasmBackend**: MIRをWASMバイトコードに変換
|
||||
3. **wasmtime::Engine::precompile**: WASMをネイティブコードにプリコンパイル
|
||||
4. **出力**: .cwasm形式で保存(wasmtime独自形式)
|
||||
|
||||
## 📊 パフォーマンス比較
|
||||
|
||||
### 🚀 実際のベンチマーク結果(2025-08-14測定・修正)
|
||||
|
||||
#### ⚠️ **重要**: 性能測定の正確な説明
|
||||
|
||||
**真の実行性能比較**(wasmtime統合・100回実行平均):
|
||||
| Backend | 実行時間 | 速度比 | 測定内容 | 最適用途 |
|
||||
|---------|---------|---------|----------|----------|
|
||||
| **🌐 WASM** | **8.12ms** | **13.5x faster** | 真の実行性能 | Web配布・高速実行 |
|
||||
| **📝 Interpreter** | **110.10ms** | **1x (baseline)** | AST直接実行 | 開発・デバッグ |
|
||||
| **🏎️ VM** | **119.80ms** | **0.9x slower** | MIR→VM実行 | 🚨要改善 |
|
||||
|
||||
**コンパイル性能参考**(従来のベンチマーク):
|
||||
| Backend | コンパイル時間 | 速度比 | 測定内容 |
|
||||
|---------|-------------|---------|----------|
|
||||
| **🌐 WASM** | **0.17ms** | **280x faster** | MIR→WASM変換 |
|
||||
| **🏎️ VM** | **16.97ms** | **2.9x faster** | MIR→VM変換 |
|
||||
| **📝 Interpreter** | **48.59ms** | **1x (baseline)** | AST→実行 |
|
||||
|
||||
### 📈 ベンチマーク詳細
|
||||
|
||||
#### 🚨 **VM性能問題の発見**
|
||||
**異常事象**: VMがインタープリターより遅い結果が判明
|
||||
- **推定原因**: MIR変換オーバーヘッド、VM実行エンジン未最適化
|
||||
- **対策**: Phase 9でのJIT化、VM最適化が急務
|
||||
|
||||
#### 実行性能詳細(wasmtime統合測定)
|
||||
```
|
||||
🌐 WASM (wasmtime): 8.12 ms (13.5x faster - 真の実行性能)
|
||||
📝 Interpreter: 110.10 ms (1x baseline)
|
||||
🏎️ VM: 119.80 ms (0.9x slower - 要改善)
|
||||
```
|
||||
|
||||
#### コンパイル性能詳細(従来測定)
|
||||
```
|
||||
🌐 WASM変換: 0.15-0.21 ms (280x faster - コンパイル速度)
|
||||
🏎️ VM変換: 4.44-25.08 ms (3-120x faster - コンパイル速度)
|
||||
📝 実行のみ: 14.85-84.88 ms (1x baseline)
|
||||
```
|
||||
|
||||
### 💡 ベンチマーク実行方法
|
||||
```bash
|
||||
# 現在のマシンで性能測定
|
||||
nyash --benchmark --iterations 100
|
||||
|
||||
# 軽量テスト(開発中)
|
||||
nyash --benchmark --iterations 10
|
||||
```
|
||||
|
||||
### メモリ使用量
|
||||
```
|
||||
インタープリター ████████████████████ 高い(AST+実行情報)
|
||||
VM ████████████ 中程度(MIR+実行時)
|
||||
WASM ████ 低い(最適化済み)
|
||||
```
|
||||
|
||||
## 🎁 Everything is Box の維持
|
||||
|
||||
全ての実行方式で、Nyashの核心哲学「Everything is Box」が維持されます:
|
||||
|
||||
### インタープリター
|
||||
```rust
|
||||
// RustのArc<Mutex<dyn NyashBox>>として実装
|
||||
StringBox::new("Hello") → Arc<Mutex<StringBox>>
|
||||
```
|
||||
|
||||
### VM
|
||||
```
|
||||
// MIRのValueIdとして管理
|
||||
%0 = const "Hello" ; StringBox相当
|
||||
%1 = %0.length() ; メソッド呼び出し
|
||||
```
|
||||
|
||||
### WASM
|
||||
```wat
|
||||
;; WASMの線形メモリでBox表現
|
||||
;; [type_id:4][field_count:4][field0:4][field1:4]...
|
||||
i32.const 1001 ;; StringBox type ID
|
||||
i32.store offset=0 ;; メモリにBox情報格納
|
||||
```
|
||||
|
||||
## 🚀 用途別推奨
|
||||
|
||||
### 開発・デバッグ時
|
||||
```bash
|
||||
# 詳細ログでエラー特定
|
||||
nyash --debug-fuel unlimited debug_me.nyash
|
||||
```
|
||||
|
||||
### 本番実行時
|
||||
```bash
|
||||
# 高速・安定実行
|
||||
nyash --backend vm production.nyash
|
||||
```
|
||||
|
||||
### Web配布時
|
||||
```bash
|
||||
# ブラウザ対応WASM生成
|
||||
nyash --compile-wasm app.nyash -o public/app.wat
|
||||
```
|
||||
|
||||
## 🔧 トラブルシューティング
|
||||
|
||||
### パーサーエラー
|
||||
```bash
|
||||
# 無限ループ検出時
|
||||
🚨 PARSER INFINITE LOOP DETECTED
|
||||
→ nyash --debug-fuel 1000 problem.nyash
|
||||
```
|
||||
|
||||
### MIRエラー
|
||||
```bash
|
||||
# 未対応AST構文
|
||||
❌ MIR compilation error: Unsupported AST node type: BoxDeclaration
|
||||
→ 現在はstatic box Mainのみ対応
|
||||
```
|
||||
|
||||
### WASMエラー
|
||||
```bash
|
||||
# 未対応MIR命令
|
||||
❌ WASM compilation error: Instruction not yet supported: ComplexInstruction
|
||||
→ Phase 8.3で順次対応予定
|
||||
```
|
||||
|
||||
## 📈 今後の拡張予定
|
||||
|
||||
### Phase 8.3: Box操作のWASM対応
|
||||
- RefNew/RefGet/RefSet
|
||||
- オブジェクト指向プログラミング
|
||||
- メモリ管理の高度化
|
||||
|
||||
### Phase 8.4: 非同期処理のWASM対応
|
||||
- nowait/await構文
|
||||
- Future操作
|
||||
- 並列処理
|
||||
|
||||
### Phase 8.5: 最適化
|
||||
- デッドコード除去
|
||||
- インライン展開
|
||||
- ループ最適化
|
||||
|
||||
---
|
||||
|
||||
**💡 Tip**: 開発中は**インタープリター**、テスト時は**VM**、配布時は**WASM**という使い分けが効果的です!
|
||||
|
||||
最終更新: 2025-08-14
|
||||
作成者: Nyash Development Team
|
||||
### 🔥 JIT実行(Phase 10_c 最小経路)
|
||||
- 有効化: `NYASH_JIT_EXEC=1` とし、`NYASH_JIT_THRESHOLD=1` でホット判定しきい値を下げる
|
||||
- 追加情報: `NYASH_JIT_STATS=1` でJITコンパイル/実行時間、サイト集計を出力
|
||||
- ダンプ: `NYASH_JIT_DUMP=1` でLowerカバレッジ/emit統計を表示
|
||||
- HostCall(配列/Map最小): `NYASH_JIT_HOSTCALL=1`
|
||||
|
||||
例:
|
||||
```bash
|
||||
NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 NYASH_JIT_HOSTCALL=1 NYASH_JIT_STATS=1 \
|
||||
./target/release/nyash --backend vm examples/scheduler_demo.nyash
|
||||
```
|
||||
|
||||
現状のカバレッジ(Core-1)
|
||||
- Const(i64/bool), BinOp(Add/Sub/Mul/Div/Mod), Compare(Eq/Ne/Lt/Le/Gt/Ge), Return
|
||||
- Paramのi64経路(複数引数対応)
|
||||
- Array/Mapの最小HostCall(len/get/set/push/size)
|
||||
- Branch/JumpはPhase 10.7でCranelift配線を導入(feature: `cranelift-jit`)。
|
||||
- 分岐条件はb1化(i64の場合は !=0 で正規化)
|
||||
- 直線+if/elseでのreturnをJITで実行(副作用は未対応のためVMへ)
|
||||
- PHIは将来の`NYASH_JIT_PHI_MIN=1`で最小導入予定
|
||||
|
||||
#### 予約シンボル(Runtime/GC 橋渡し)
|
||||
- `nyash.rt.checkpoint`(セーフポイント)
|
||||
- JIT: no-op スタブを登録済み(将来のスケジューラ/GC連携用)
|
||||
- AOT: `nyrt` が同名シンボルをエクスポート(`#[export_name]`)。リンク済み
|
||||
- トレース: `NYASH_RUNTIME_CHECKPOINT_TRACE=1` でstderrに到達ログ
|
||||
- `nyash.gc.barrier_write`(書き込みバリア)
|
||||
- JIT: no-op スタブを登録済み(将来のインクリメンタルGC向けフック)
|
||||
- AOT: `nyrt` が同名シンボルをエクスポート(`#[export_name]`)
|
||||
- トレース: `NYASH_GC_BARRIER_TRACE=1` でstderrに到達ログ
|
||||
|
||||
メモ: 現時点では両シンボルとも副作用なし(no-op)。MIR側では `Safepoint` → `ExternCall(env.runtime.checkpoint)` へ段階移行中です。
|
||||
## ⚙️ 任意: Cranelift JIT ランタイム
|
||||
- デフォルト封印。必要時のみ `--features "cranelift-jit,jit-runtime"` で有効化
|
||||
- ランナーの `--backend cranelift` が利用可能に
|
||||
- 目的: デバッグ用途・将来の最適化検証。日常運用ではAOTを優先
|
||||
@ -1,98 +0,0 @@
|
||||
# MIR 26-Instruction Diet (Agreed Final Set)
|
||||
|
||||
Goal
|
||||
- Converge on a lean, proven instruction set guided by vm-stats and E2E.
|
||||
- Preserve hot paths, demote meta, fold type ops, reserve room for growth.
|
||||
|
||||
Agreed Final Set (26)
|
||||
1) Const
|
||||
2) Copy
|
||||
3) Load
|
||||
4) Store
|
||||
5) BinOp
|
||||
6) UnaryOp
|
||||
7) Compare
|
||||
8) Jump
|
||||
9) Branch
|
||||
10) Phi
|
||||
11) Return
|
||||
12) Call
|
||||
13) BoxCall
|
||||
14) NewBox
|
||||
15) ArrayGet
|
||||
16) ArraySet
|
||||
17) RefNew
|
||||
18) RefGet
|
||||
19) RefSet
|
||||
20) Await
|
||||
21) Print
|
||||
22) ExternCall (keep minimal; prefer BoxCall)
|
||||
23) TypeOp (unify TypeCheck/Cast)
|
||||
24) WeakRef (unify WeakNew/WeakLoad)
|
||||
25) Barrier (unify BarrierRead/BarrierWrite)
|
||||
26) Reserve (future async/error instr)
|
||||
|
||||
Hot/Core (keep)
|
||||
- Data: Const, Copy, Load, Store
|
||||
- ALU: BinOp, UnaryOp, Compare
|
||||
- Control: Jump, Branch, Phi, Return
|
||||
- Calls: Call, BoxCall
|
||||
- Objects: NewBox
|
||||
- Arrays: ArrayGet, ArraySet
|
||||
|
||||
Likely Keep (usage-dependent)
|
||||
- Refs: RefNew, RefGet, RefSet (seen in language features; keep unless stats prove cold)
|
||||
- Async: Await (FutureNew/Set can be Box/APIs)
|
||||
|
||||
Meta (demote to build-mode)
|
||||
- Debug, Nop, Safepoint
|
||||
|
||||
Type Ops (fold)
|
||||
- TypeCheck, Cast → fold/verify-time or unify as a single TypeOp (optional).
|
||||
|
||||
External (unify)
|
||||
- ExternCall → prefer BoxCall; keep ExternCall only where required.
|
||||
|
||||
Extended/Reserve
|
||||
- Weak*: WeakNew, WeakLoad
|
||||
- Barriers: BarrierRead, BarrierWrite
|
||||
- 2 Reserve IDs for future async/error instrumentation
|
||||
|
||||
Mapping Notes
|
||||
- HTTP E2E shows BoxCall/NewBox dominate (33–42%), then Const/NewBox, with Branch/Jump/Phi only in error flows.
|
||||
- FileBox path similarly heavy on BoxCall/NewBox/Const.
|
||||
- Implication: invest into BoxCall fast path and const/alloc optimization.
|
||||
|
||||
Migration Strategy
|
||||
1) Introduce an experimental feature gate that switches TypeCheck/Cast to TypeOp or folds them.
|
||||
2) Demote Debug/Nop/Safepoint under non-release builds.
|
||||
3) Keep ExternCall available, route new external APIs via BoxCall when possible.
|
||||
4) Track Weak*/Barrier usage; unify under WeakRef/Barrier. Graduate dedicated ops only if vm-stats shows recurring use.
|
||||
|
||||
Mapping from Current → Final
|
||||
- TypeCheck, Cast → TypeOp
|
||||
- WeakNew, WeakLoad → WeakRef
|
||||
- BarrierRead, BarrierWrite → Barrier
|
||||
- (Keep) ExternCall, but prefer BoxCall where possible(ExternCall は最小限に)
|
||||
- (Keep) Debug/Nop/Safepoint as meta under non-release builds(命令セット外のビルドモード制御に降格)
|
||||
|
||||
Verification
|
||||
- Add MIR verifier rule: use-before-def across merges is rejected (guards phi misuse).
|
||||
- Add snapshot tests for classic if-merge returning phi.
|
||||
|
||||
Appendix: Rationale
|
||||
- Smaller ISA simplifies VM fast paths and aids JIT/AOT later.
|
||||
- Data shows hot paths concentrated on calls, const, alloc; control sparse and localized.
|
||||
- Folding type ops reduces interpreter/VM dispatch; verification handles safety.
|
||||
---
|
||||
|
||||
Feature Flags (Cargo)
|
||||
- Deprecated flags (unified by default):
|
||||
- `mir_typeop_poc`: no-op now. Builder always emits `TypeOp(Check/Cast)` instead of legacy `TypeCheck/Cast`。
|
||||
- `mir_refbarrier_unify_poc`: no-op now. Builder always emits `WeakRef/Barrier` instead of legacy `WeakNew/WeakLoad/BarrierRead/Write`。
|
||||
- Optimizer has a Pass 0 that normalizes any残存の旧命令 → 統合命令(安全ネット)。
|
||||
|
||||
Status (2025-08-23)
|
||||
- Flags declared in `Cargo.toml` (off by default)
|
||||
- PoC design doc: `docs/development/proposals/mir-typeop-weakref-barrier-poc.md`
|
||||
- Next: land builder/VM mapping behind flags, add snapshot tests; no behavior change with flags off
|
||||
@ -1,218 +0,0 @@
|
||||
# MIR → VM Mapping (Draft)
|
||||
|
||||
最終更新: 2025-08-23
|
||||
|
||||
目的: 生成されたMIR命令がVMでどう実行されるかを1枚で把握し、欠落や暫定実装を洗い出す。26命令ダイエット検討の足場にする。
|
||||
|
||||
記法: 状態 = Implemented / Partial / No-op / TODO。
|
||||
|
||||
## コア命令
|
||||
- Const: Implemented
|
||||
- 定数を `VMValue` に格納。
|
||||
- BinOp: Partial
|
||||
- Integer: Add/Sub/Mul/Div 実装(Divは0割チェック)。他の算術/論理/ビット演算は TODO。
|
||||
- String: `+` 連結のみ対応。その他は TypeError。
|
||||
- UnaryOp: Partial
|
||||
- `Neg`(int), `Not`(bool) のみ。`BitNot` は TODO。
|
||||
- Compare: Partial
|
||||
- Integer/ String の Eq/Ne/Lt/Le/Gt/Ge 対応。Bool は Eq/Ne のみ。
|
||||
- Void は値を持たないため、比較は Eq/Ne のみ定義。
|
||||
- `Void == Void` は true、`Void != Void` は false
|
||||
- `Void == X` は false、`Void != X` は true(順序比較は TypeError)
|
||||
- Load / Store: Implemented
|
||||
- 現状はVM内の値スロット操作(簡易)。
|
||||
- Copy: Implemented
|
||||
- 値コピー+クラス名/内部参照印の伝播。
|
||||
|
||||
## 制御フロー
|
||||
- Branch / Jump / Return: Implemented
|
||||
- Branchの条件は `Bool` を期待。以下の動的変換を許容:
|
||||
- `Integer` → 非ゼロは true
|
||||
- `BoxRef(BoolBox)` → 中身のbool
|
||||
- `BoxRef(VoidBox)` → false(nullish false)
|
||||
- Phi: Implemented
|
||||
- `LoopExecutor` による選択実装(前BB情報を利用)。
|
||||
|
||||
## 呼び出し/Box関連
|
||||
- Call: Implemented
|
||||
- 関数名を `Const String` として解決しVM内ディスパッチ。
|
||||
- BoxCall: Partial
|
||||
- InstanceBox: `{Class}.{method}/{argc}` へ降格呼び出し(MIR関数)。
|
||||
- PluginBoxV2: cfg(feature="plugins")下でLoader経由invoke(引数: NyashBox配列)。
|
||||
- Builtinの簡易ディスパッチ: `StringBox.length/substr/concat`, `IntegerBox.toString/abs` 等の最小対応。
|
||||
- birth 特例: user-definedの `birth` はMIR関数へ直呼。
|
||||
- NewBox: Implemented
|
||||
- `runtime.box_registry` から生成。`scope_tracker` に登録。クラス名マップ更新。
|
||||
- TypeCheck: No-op (常にtrue)
|
||||
- TODO: 正式な型チェックに置換。
|
||||
- Cast: No-op (コピー)
|
||||
- TODO: 正式な型変換に置換。
|
||||
|
||||
## 配列
|
||||
- ArrayGet: ArrayBox.get(index) を呼び出し、戻り値を格納(VM対応済み)
|
||||
- ArraySet: ArrayBox.set(index, value) を呼び出し(VM対応済み)
|
||||
|
||||
## デバッグ/出力
|
||||
- Debug: No-op(性能優先)
|
||||
- Print: Implemented(`to_string()`して標準出力)
|
||||
- Nop: No-op
|
||||
|
||||
## 例外/安全ポイント
|
||||
- Throw: Partial
|
||||
- 例外値を表示してVMErrorで中断。ハンドラ探索なし。
|
||||
- Catch: No-op
|
||||
- 例外値スロットを `Void` セットのみ。制御遷移の実装は未対応。
|
||||
- Safepoint: No-op
|
||||
|
||||
## 参照/弱参照/バリア
|
||||
- RefNew / RefGet / RefSet: Partial
|
||||
- `object_fields` に簡易格納。`object_class` と `box_declarations` を用いた可視性(public/private)簡易検査あり。
|
||||
- WeakNew / WeakLoad: No-op相当(通常コピー/取得と同値)
|
||||
- TODO: 実際の弱参照生存判定を導入。
|
||||
- BarrierRead / BarrierWrite: No-op
|
||||
- 効果注釈のみ(将来の最適化/並行実行基盤に備えた形)。
|
||||
|
||||
## 非同期
|
||||
- FutureNew / FutureSet / Await: Implemented
|
||||
- `boxes::future::FutureBox` を利用し、同期ブロッキングで結果取得。
|
||||
|
||||
## 外部呼び出し
|
||||
- ExternCall: Implemented
|
||||
- `runtime::get_global_loader_v2().extern_call(iface, method, args)` にルーティング。Some/Noneで戻り値void扱いも考慮。
|
||||
|
||||
---
|
||||
|
||||
## Result / Err / Handle(BoxRef) 取り扱い(重要)
|
||||
|
||||
目的: プラグイン呼び出し(BoxCall→PluginLoaderV2)およびVM内の戻り値で、ResultとBoxRef(Handle)を正しく扱うための合意事項。
|
||||
|
||||
- HTTP系(Netプラグイン)の約束
|
||||
- unreachable(接続不可/タイムアウト等): `Result.Err(ErrorBox)` にマップする。
|
||||
- HTTP 404/500 等のステータス異常: `Result.Ok(Response)` として返す(アプリ層で扱う)。
|
||||
- FileBox等のVoid戻り
|
||||
- `close()` のような副作用のみのメソッドは `Ok(Void)` を返す。VMではVoidの実体は持たない。
|
||||
- Handle(BoxRef)戻り値
|
||||
- プラグインは TLV tag=8(Handle)で `type_id:u32, instance_id:u32` を返す。
|
||||
- Loader は返り値の `type_id` に対応する正しい `fini_method_id` を設定し、`PluginBoxV2` を生成してVMへ返す。
|
||||
- 注意: 生成元のBoxと返り値のBoxの型が異なるケースがあるため、「呼び出し元のfini値を流用しない」。必ず返り値 `type_id` を基に解決する。
|
||||
- Resultの整合
|
||||
- VMは `Result<T, ErrorBox>` をネイティブ表現し、`match` 等で分岐可能。
|
||||
- `Ok(Void)` は `match Ok(_)` と等価に扱える(Voidは値を持たない)。
|
||||
|
||||
参考: TLV/Loader仕様は `docs/reference/plugin-system/ffi-abi-specification.md` と `plugin-tester.md` を参照。
|
||||
|
||||
---
|
||||
|
||||
## 既知の課題(抜粋)
|
||||
- BinOp/UnaryOp/Compare の型拡張(浮動小数・Bool/Box等)。
|
||||
- ArrayGet/ArraySet の実装。
|
||||
- TypeCheck/Cast の正規化(型表現と整合)。
|
||||
- 例外ハンドリング(Throw/Catchの制御フロー接続)。
|
||||
- WeakRef/Barrier の実体化(必要性評価の上、命令ダイエット候補)。
|
||||
- PluginBoxV2 のVM側統合強化(引数/戻り値のTLV全型対応、Handle戻り値→BoxRef化)。
|
||||
|
||||
Verifier(検証)に関する追加事項(方針)
|
||||
- use-before-def across merge の強化: merge後にphiが未使用/未定義を選択するパスを禁止。
|
||||
- if-merge の戻り: retはphiのdstを返す(実装済み)。
|
||||
- TypeOp(TypeCheck/Cast)と命令の整合: Verifierで型注釈に基づく不一致を検出。
|
||||
|
||||
## VM統計(計測)
|
||||
- `--vm-stats` / `--vm-stats-json` で命令ごとの使用回数と時間(ms)を出力。
|
||||
- ホット命令抽出によりダイエット候補を定量化。
|
||||
|
||||
---
|
||||
|
||||
## 実測結果サマリー(初回プローブ)
|
||||
出所: `local_tests/vm_stats_hello.json`, `local_tests/vm_stats_loop.json`, `simple_math.nyash`
|
||||
|
||||
- ループ系(139命令 / 0.158ms)トップ:
|
||||
- Const: 25, BoxCall: 23, NewBox: 23, BinOp: 11, Branch: 11, Compare: 11, Jump: 11, Phi: 11, Safepoint: 11
|
||||
- 所見: ループloweringで Branch/Jump/Phi/Safepoint が並び、Box初期化とBoxCallが多い。
|
||||
- Hello系(6命令): 期待どおりの最小構成(Const/Print/Return中心)。
|
||||
- simple_math(18命令): BinOpの使用を確認(整数加減乗除)。
|
||||
|
||||
補足:
|
||||
- Safepoint はMIR上で挿入されるが、VMではNo-op(計測には現れる)。
|
||||
- NewBox/BoxCall が上位に入るため、命令セットから外すのは不可(コア扱い)。
|
||||
- Compare/Branch/Jump/Phi は制御フローのコア。26命令の中核として維持が妥当。
|
||||
|
||||
## 実測統計(2025-08-23)
|
||||
出所: vm-stats(正常系HTTP/異常系HTTP/FileBox)
|
||||
|
||||
- 正常系HTTP(40命令)
|
||||
- BoxCall: 17(42.5%)/ Const: 12(30%)/ NewBox: 9(22.5%)/ Return: 1 / Safepoint: 1
|
||||
- 異常系HTTP(21命令 = 正常の52.5%)
|
||||
- BoxCall: 7(33.3%)/ Const: 6(28.6%)/ NewBox: 3(14.3%)
|
||||
- Branch: 1 / Jump: 1 / Phi: 1(エラーハンドリング特有)/ Return: 1 / Safepoint: 1
|
||||
- FileBox(44命令)
|
||||
- BoxCall: 17(38.6%)/ Const: 13(29.5%)/ NewBox: 12(27.3%)/ Return: 1 / Safepoint: 1
|
||||
|
||||
設計含意:
|
||||
- BoxCallが常に最頻出(33〜42%)。呼び出しコスト最適化が最優先。
|
||||
- Const/NewBoxが次点。定数・生成の最適化(定数畳み込み/軽量生成・シェアリング)が効果的。
|
||||
- 異常系は早期収束で命令半減。if/phi修正は実戦で有効(Branch/Jump/Phiが顕在化)。
|
||||
|
||||
補足(HTTP 404/500の比較)
|
||||
- 404("Not Found")、500("Internal Server Error")ともに同一プロファイル(合計55命令)
|
||||
- 内訳例: BoxCall: 23 / Const: 16 / NewBox: 12 / BinOp: 2 / Return: 1 / Safepoint: 1
|
||||
- ステータス差はアプリ層で完結し、VM命令の分布には有意差なし(設計の意図どおり)
|
||||
|
||||
## 26命令ダイエット(検討のたたき台)
|
||||
方針: 「命令の意味は保ちつつ集約」。代表案:
|
||||
- 維持: Const / Copy / Load / Store / BinOp / UnaryOp / Compare / Jump / Branch / Phi / Return / Call / BoxCall / NewBox / ArrayGet / ArraySet
|
||||
- 参照: RefNew / RefGet / RefSet(Weak/Barrierは拡張枠へ)
|
||||
- 非同期: Await(FutureNew/SetはBox APIへ寄せる案も可)
|
||||
- I/O: Print は開発モード限定 or ExternCall統合(ExternCall自体はBoxCallへ統合方針)
|
||||
- 調整: TypeCheck/Cast はVerifier/型系に寄せる(命令から外す or 1命令に集約)
|
||||
- Debug/Nop/Safepoint: メタ扱い(命令数からは外す)
|
||||
|
||||
次ステップ:
|
||||
- サンプル/テストをVMで実行し、`vm-stats`結果から実使用命令セットを抽出。
|
||||
- 上記案に対し互換影響を洗い出し、段階移行(エイリアス→削除)を設計。
|
||||
|
||||
---
|
||||
|
||||
## 26命令ダイエットの指針(実測反映)
|
||||
- 維持(ホット・コア): BoxCall / NewBox / Const / BinOp / Compare / Branch / Jump / Phi / Return / Copy / Load / Store / Call
|
||||
- 実装方針: ExternCallは原則BoxCallへ集約(必要なら限定的に残す)。
|
||||
- メタ降格: Debug/Nop/Safepoint(ビルドモードで制御)。
|
||||
- 型系: TypeCheck/Castは折りたたみ or 検証時に処理(1命令に集約も可)。
|
||||
- 参照/弱参照/バリア: 需要ベースで拡張枠へ(vm-statsに登場しない限りコア外)。
|
||||
|
||||
提案(ドラフト):
|
||||
- コア候補(例): Const, Copy, Load, Store, BinOp, UnaryOp, Compare, Jump, Branch, Phi, Return, Call, BoxCall, NewBox, ArrayGet, ArraySet, RefNew, RefGet, RefSet, Await, Print, ExternCall(集約可), TypeOp(=TypeCheck/Cast), 予備2(将来枠)
|
||||
- 予備はWeak*/Barrierや将来の非同期拡張等に割当(実測で常用化したら昇格)。
|
||||
|
||||
---
|
||||
|
||||
## E2E更新(VM経由の実働確認)
|
||||
|
||||
成功ケース(VM):
|
||||
- FileBox.open/write/read: 引数2個のTLVエンコード(String, String)で成功(HELLO往復)
|
||||
- FileBox.copyFrom(handle): Handle引数(tag=8, size=8, type_id+instance_id)で成功
|
||||
- HttpClientBox.get + HttpServerBox: 基本GETの往復(ResultBox経由でResponse取得)
|
||||
- HttpClientBox.post + headers: Status/ヘッダー/ボディをVMで往復確認
|
||||
- HttpClientBox.get unreachable: 接続失敗時はResult.Err(ErrorBox)(ローダーがstring/bytesをErrにマップ)
|
||||
- HTTP 404/500: Result.Ok(Response)(ステータスはResponse上に保持)
|
||||
|
||||
デバッグ小技:
|
||||
- `NYASH_DEBUG_PLUGIN=1` で VM→Plugin 呼び出しTLVの ver/argc/先頭バイトをダンプ
|
||||
- Netプラグインの内部ログ: `NYASH_NET_LOG=1 NYASH_NET_LOG_FILE=net_plugin.log`
|
||||
## 型・Null/Void・比較の扱い(更新)
|
||||
|
||||
- NullはVM内部でVoidに折りたたみ(`Const Null → VMValue::Void`)。
|
||||
- VoidとNullは同一視されない(等価比較は `Void == Void` のみtrue)。
|
||||
- Compareの対応:
|
||||
- 整数/文字列: Eq/Ne/Lt/Le/Gt/Ge(実装済)
|
||||
- 真偽値: Eq/Ne のみ
|
||||
- Void: Eq/Ne のみ(Void==Voidはtrue、それ以外はfalse)
|
||||
- 浮動小数点: Eq/Ne/Lt/Le/Gt/Ge(新規)
|
||||
- 整数と浮動小数点の混在: 双方をf64比較で対応(新規)
|
||||
|
||||
## TypeOp(PoC)
|
||||
- 目的: TypeCheck/Castの統合。
|
||||
- Check: 最小意味論を実装(Integer/Float/Bool/String/Void/Box名に対し一致判定)。
|
||||
- Cast: 当面コピー等価(将来の変換方針に備える)。
|
||||
- me 参照
|
||||
- メソッド/コンストラクタlowering時は `%0` にマップ(パラメータ)。
|
||||
- それ以外の文脈ではフォールバックとして `Const "__me__"` を一度だけ発行して変数マップに保持し、以降の `me` は同一ValueIdを参照(RefGet/RefSetの整合性を保証)。
|
||||
@ -1,235 +0,0 @@
|
||||
# 🤖 Nyash MIR (Mid-level Intermediate Representation) - 統合リファレンス
|
||||
|
||||
*26命令削減実装中・ChatGPT5仕様準拠 - 2025年8月17日版*
|
||||
|
||||
## 🚨 **重要: MIR命令削減プロジェクト進行中**
|
||||
|
||||
**現状**: 35命令実装(175%膨張)→ **目標**: 26命令(ChatGPT5仕様)
|
||||
**Gemini評価**: 削減戦略「極めて健全」「断行推奨」
|
||||
|
||||
## 🎯 **MIR概要**
|
||||
|
||||
Nyash MIRは、Everything is Box哲学を基盤とした中間表現です。現在35命令が実装され、インタープリター・VM・WASM・AOTの全バックエンドで統一された実行を実現します。
|
||||
|
||||
### **🌟 主要特徴**
|
||||
- **Everything is Box**: 全データがBoxオブジェクトとして統一表現
|
||||
- **Effect System**: pure/mut/io/control効果による最適化基盤
|
||||
- **所有権管理**: 強参照森(ownership forest)+ weak参照システム
|
||||
- **非同期対応**: Future/Bus操作の言語レベル統合
|
||||
- **FFI/ABI統合**: ExternCall命令による外部API統一呼び出し
|
||||
|
||||
## 🏗️ **命令分類 - 35命令全体系**
|
||||
|
||||
### **Tier-0: コア演算 (8命令)**
|
||||
基本的な計算・制御フロー命令
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Const` | `%dst = const value` | pure | 定数値生成 |
|
||||
| `BinOp` | `%dst = %lhs op %rhs` | pure | 二項演算(+,-,*,/等) |
|
||||
| `UnaryOp` | `%dst = op %operand` | pure | 単項演算(not, neg等) |
|
||||
| `Compare` | `%dst = %lhs cmp %rhs` | pure | 比較演算(==, !=, <等) |
|
||||
| `Branch` | `br %cond -> %then, %else` | control | 条件分岐 |
|
||||
| `Jump` | `jmp %target` | control | 無条件ジャンプ |
|
||||
| `Return` | `ret %value?` | control | 関数戻り |
|
||||
| `Phi` | `%dst = phi [%val1:%bb1, %val2:%bb2]` | pure | SSA φ関数 |
|
||||
|
||||
### **Tier-1: メモリ・関数操作 (8命令)**
|
||||
メモリアクセス・関数呼び出し・型操作
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Load` | `%dst = load %ptr` | pure | メモリ読み取り |
|
||||
| `Store` | `store %value -> %ptr` | mut | メモリ書き込み |
|
||||
| `Call` | `%dst = call %func(%args...)` | context | 関数呼び出し |
|
||||
| `BoxCall` | `%dst = %box.method(%args...)` | context | Boxメソッド呼び出し |
|
||||
| `NewBox` | `%dst = new_box "Type"(%args...)` | mut | Box生成 |
|
||||
| `TypeCheck` | `%dst = type_check %box "Type"` | pure | 型チェック |
|
||||
| `Cast` | `%dst = cast %value as Type` | pure | 型変換 |
|
||||
| `Copy` | `%dst = copy %src` | pure | 値コピー |
|
||||
|
||||
### **Tier-2: 配列・デバッグ・制御 (7命令)**
|
||||
配列操作・デバッグ・例外処理
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `ArrayGet` | `%dst = %array[%index]` | pure | 配列要素取得 |
|
||||
| `ArraySet` | `%array[%index] = %value` | mut | 配列要素設定 |
|
||||
| `Debug` | `debug %value "message"` | io | デバッグ出力 |
|
||||
| `Print` | `print %value` | io | コンソール出力 |
|
||||
| `Nop` | `nop` | pure | 無操作 |
|
||||
| `Throw` | `throw %exception` | control | 例外発生 |
|
||||
| `Catch` | `catch %type -> %handler` | control | 例外捕捉 |
|
||||
|
||||
### **Tier-3: 参照・非同期・外部API (12命令)**
|
||||
所有権管理・非同期処理・外部連携
|
||||
|
||||
| 命令 | 形式 | 効果 | 説明 |
|
||||
|------|------|------|------|
|
||||
| `Safepoint` | `safepoint` | io | セーフポイント |
|
||||
| `RefNew` | `%dst = ref_new %box` | pure | 参照生成 |
|
||||
| `RefGet` | `%dst = ref_get %ref.field` | pure | 参照経由読み取り |
|
||||
| `RefSet` | `ref_set %ref.field = %value` | mut | 参照経由書き込み |
|
||||
| `WeakNew` | `%dst = weak_new %box` | pure | weak参照生成 |
|
||||
| `WeakLoad` | `%dst = weak_load %weak_ref` | pure | weak参照読み取り |
|
||||
| `BarrierRead` | `barrier_read %ptr` | io | メモリバリア読み |
|
||||
| `BarrierWrite` | `barrier_write %ptr` | io | メモリバリア書き |
|
||||
| `FutureNew` | `%dst = future_new %value` | mut | Future生成 |
|
||||
| `FutureSet` | `future_set %future = %value` | mut | Future値設定 |
|
||||
| `Await` | `%dst = await %future` | io | Future待機 |
|
||||
| `ExternCall` | `%dst = extern_call iface.method(%args...)` | context | 外部API呼び出し |
|
||||
|
||||
## 🎭 **Effect System - 4種類の効果**
|
||||
|
||||
### **効果分類と最適化ルール**
|
||||
|
||||
```rust
|
||||
pub enum Effect {
|
||||
Pure, // 再順序化可能、共通部分式除去可能
|
||||
Mut, // 同一リソースで順序保持必要
|
||||
Io, // 全順序保持必要(副作用あり)
|
||||
Control, // 制御フロー変更
|
||||
}
|
||||
```
|
||||
|
||||
### **効果別命令分類**
|
||||
|
||||
#### **Pure命令 (15命令)**
|
||||
```
|
||||
Const, BinOp, UnaryOp, Compare, Phi, Load, TypeCheck, Cast, Copy,
|
||||
ArrayGet, Nop, RefNew, RefGet, WeakNew, WeakLoad
|
||||
```
|
||||
|
||||
#### **Mut命令 (7命令)**
|
||||
```
|
||||
Store, NewBox, ArraySet, RefSet, FutureNew, FutureSet
|
||||
```
|
||||
|
||||
#### **Io命令 (6命令)**
|
||||
```
|
||||
Debug, Print, Safepoint, BarrierRead, BarrierWrite, Await
|
||||
```
|
||||
|
||||
#### **Control命令 (4命令)**
|
||||
```
|
||||
Branch, Jump, Return, Throw, Catch
|
||||
```
|
||||
|
||||
#### **Context依存命令 (3命令)**
|
||||
```
|
||||
Call, BoxCall, ExternCall
|
||||
```
|
||||
*効果は呼び出し先に依存*
|
||||
|
||||
## 🔧 **重要なMIR実装詳細**
|
||||
|
||||
### **ExternCall命令 - FFI/ABI統合**
|
||||
|
||||
```rust
|
||||
ExternCall {
|
||||
dst: Option<ValueId>,
|
||||
iface_name: String, // "env.console", "nyash.math"等
|
||||
method_name: String, // "log", "sqrt"等
|
||||
args: Vec<ValueId>,
|
||||
effects: EffectMask, // BID仕様から決定
|
||||
}
|
||||
```
|
||||
|
||||
**用途**: ブラウザーAPI・ネイティブライブラリ・プラグインの統一呼び出し
|
||||
|
||||
### **所有権管理システム**
|
||||
|
||||
#### **強参照森(Ownership Forest)**
|
||||
- 各Boxは最大1つの強参照を持つ(in-degree ≤ 1)
|
||||
- 強参照による循環は禁止(DAG構造保証)
|
||||
- `NewBox`, `RefSet`で所有権移転
|
||||
|
||||
#### **weak参照システム**
|
||||
- 所有権を持たない軽量参照
|
||||
- `WeakNew`で生成、`WeakLoad`で安全アクセス
|
||||
- 参照先削除時は自動的にnull化
|
||||
|
||||
### **非同期処理 - Future操作**
|
||||
|
||||
```mir
|
||||
%future = FutureNew %initial_value // Future生成
|
||||
FutureSet %future = %result // 結果設定
|
||||
%value = Await %future // 結果取得(ブロッキング)
|
||||
```
|
||||
|
||||
## 🚀 **バックエンド別対応状況**
|
||||
|
||||
### **実装済みバックエンド**
|
||||
|
||||
| バックエンド | 対応命令数 | 主要用途 | 特徴 |
|
||||
|-------------|-----------|----------|------|
|
||||
| **Interpreter** | 35/35 | デバッグ・開発 | 全命令完全対応 |
|
||||
| **VM** | 35/35 | 高速実行 | レジスタベース |
|
||||
| **WASM** | 30/35 | Web配布 | ExternCall→import対応 |
|
||||
| **AOT準備** | 計画中 | ネイティブ | LLVM IR生成予定 |
|
||||
|
||||
### **バックエンド固有の最適化**
|
||||
|
||||
#### **VM バックエンド**
|
||||
- レジスタベース実行
|
||||
- 局所最適化(ローカルBus elision)
|
||||
- 直接スレッド化
|
||||
|
||||
#### **WASM バックエンド**
|
||||
- メモリ線形化(文字列は (ptr,len))
|
||||
- ExternCall → import宣言自動生成
|
||||
- ホスト側JavaScript連携
|
||||
|
||||
## 📊 **MIR最適化パス**
|
||||
|
||||
### **Pure命令最適化**
|
||||
- **共通部分式除去 (CSE)**: 同一pure計算の除去
|
||||
- **不変コード移動 (LICM)**: ループ外移動
|
||||
- **定数畳み込み**: コンパイル時計算
|
||||
|
||||
### **Effect-aware最適化**
|
||||
- **Mut順序保持**: 同一リソースアクセス順序維持
|
||||
- **Io順序保持**: 全Io命令の順序保証
|
||||
- **Bus elision**: ローカル通信の直接アクセス化
|
||||
|
||||
## 🧪 **テスト・検証**
|
||||
|
||||
### **MIR検証項目**
|
||||
- [ ] **所有権森検証**: strong in-degree ≤ 1
|
||||
- [ ] **強循環禁止**: 強参照のDAG構造保証
|
||||
- [ ] **weak参照安全性**: 失効時null化
|
||||
- [ ] **効果注釈正確性**: 各命令の効果分類
|
||||
- [ ] **型安全性**: Box型システム整合性
|
||||
|
||||
### **バックエンド互換性テスト**
|
||||
```bash
|
||||
# 全バックエンドMIR一致テスト
|
||||
./target/release/nyash --dump-mir program.nyash > interpreter.mir
|
||||
./target/release/nyash --backend vm --dump-mir program.nyash > vm.mir
|
||||
./target/release/nyash --backend wasm --dump-mir program.nyash > wasm.mir
|
||||
diff interpreter.mir vm.mir && diff vm.mir wasm.mir
|
||||
```
|
||||
|
||||
## 🔮 **将来計画**
|
||||
|
||||
### **Phase 10: AOT/JIT対応**
|
||||
- LLVM IR生成バックエンド
|
||||
- ExternCall → ネイティブ関数呼び出し
|
||||
- 高度な最適化パス統合
|
||||
|
||||
### **Phase 11: MIR v2設計**
|
||||
- 命令数最適化(35 → 25命令目標)
|
||||
- BID統合(Box Interface Definition)
|
||||
- リソース所有権拡張(own<T>, borrow<T>)
|
||||
|
||||
## 📚 **関連ドキュメント**
|
||||
|
||||
- **FFI/ABI仕様**: `docs/説明書/reference/box-design/ffi-abi-specification.md`
|
||||
- **実装詳細**: `src/mir/instruction.rs`
|
||||
- **Phase計画**: `docs/予定/native-plan/copilot_issues.txt`
|
||||
|
||||
---
|
||||
|
||||
**最終更新**: 2025年8月17日
|
||||
**実装ベース**: 35命令完全対応
|
||||
**次期計画**: BID統合プラグインシステム(Phase 9.75f-BID)
|
||||
@ -1,45 +0,0 @@
|
||||
# Plugin Migration Guide v2 Enhancement Summary
|
||||
|
||||
## What was accomplished
|
||||
|
||||
This task involved enhancing the existing `docs/plugin-migration-request.md` with comprehensive implementation guidance based on the issue requirements.
|
||||
|
||||
## Key improvements made:
|
||||
|
||||
### 1. **Comprehensive nyash.toml explanation**
|
||||
- Added detailed explanation of the `from`/`to` type conversion system
|
||||
- Explained TLV (Type-Length-Value) encoding with specific tag mappings
|
||||
- Provided clear examples using FileBox as reference
|
||||
|
||||
### 2. **Detailed implementation examples**
|
||||
- Added complete Rust code examples for TLV parsing
|
||||
- Showed real HttpClientBox plugin implementation patterns
|
||||
- Included proper error handling and memory management examples
|
||||
|
||||
### 3. **Structured migration priorities**
|
||||
- **Phase 1**: Network boxes (HttpClientBox, SocketBox) - highest priority
|
||||
- **Phase 2**: GUI boxes (EguiBox, Canvas) - platform dependent
|
||||
- **Phase 3**: Special purpose boxes (TimerBox, QRBox) - independent
|
||||
|
||||
### 4. **Testing and validation guidelines**
|
||||
- Complete testing workflow with plugin-tester
|
||||
- Real Nyash code examples for validation
|
||||
- Troubleshooting guidance for common mistakes
|
||||
|
||||
### 5. **Reference implementation guidance**
|
||||
- FileBox plugin as the gold standard example
|
||||
- Specific file paths for all reference materials
|
||||
- Success tips and common pitfalls
|
||||
|
||||
## Document statistics:
|
||||
- **Length**: 368 lines (vs ~200 lines originally)
|
||||
- **Code examples**: 16 code blocks with real implementation patterns
|
||||
- **Comprehensive coverage**: TLV, nyash.toml, FFI, testing, and reference materials
|
||||
|
||||
## Validation:
|
||||
- All key sections verified to be present
|
||||
- Code examples cover the full implementation pipeline
|
||||
- References to FileBox plugin success story maintained
|
||||
- HttpClientBox positioned as Phase 1 priority target
|
||||
|
||||
The guide now serves as a complete reference for migrating any builtin Box to a plugin, with FileBox as the proven template and HttpClientBox as the next target.
|
||||
@ -1,369 +0,0 @@
|
||||
# 📦 Nyash ビルトインBox → プラグイン化移行ガイド v2
|
||||
|
||||
## 🎯 概要
|
||||
NyashのビルトインBoxをプラグイン化し、コアを軽量化します。
|
||||
FileBoxプラグインの成功例を詳しく解説しながら、移行方法を説明します。
|
||||
|
||||
## 🔑 重要な概念:nyash.tomlの型定義システム
|
||||
|
||||
### 型変換の仕組み
|
||||
nyash.tomlでは、Nyash側とプラグイン側の型変換を明示的に定義します:
|
||||
|
||||
```toml
|
||||
# FileBoxの例
|
||||
[plugins.FileBox.methods]
|
||||
# writeメソッド:Nyashのstringをプラグインではbytesとして扱う
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# openメソッド:2つのstring引数(型変換なし)
|
||||
open = { args = [
|
||||
{ name = "path", from = "string", to = "string" },
|
||||
{ name = "mode", from = "string", to = "string" }
|
||||
] }
|
||||
```
|
||||
|
||||
### from/toの意味
|
||||
- **from**: Nyash側の型(ユーザーが渡す型)
|
||||
- **to**: プラグイン側で受け取る型(TLVエンコーディング)
|
||||
|
||||
### TLVタグとの対応
|
||||
プラグインはTLV(Type-Length-Value)形式でデータを受け取ります:
|
||||
- `to = "i32"` → TLV tag=2(32ビット整数)
|
||||
- `to = "string"` → TLV tag=6(UTF-8文字列)
|
||||
- `to = "bytes"` → TLV tag=7(バイト配列)
|
||||
|
||||
## 📋 移行対象Box一覧(優先順位順)
|
||||
|
||||
### 🌐 Phase 1: ネットワーク系(最優先・最も簡単)
|
||||
既にスタブ実装があり、reqwest依存を追加するだけで完成します。
|
||||
|
||||
#### HttpClientBox
|
||||
```toml
|
||||
[plugins.HttpClientBox.methods]
|
||||
# シンプルなGETリクエスト
|
||||
get = {
|
||||
args = [{ from = "string", to = "string" }], # URL
|
||||
returns = "string" # レスポンスボディ
|
||||
}
|
||||
|
||||
# POSTリクエスト(ボディ付き)
|
||||
post = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "string", to = "bytes" } # ボディ(バイナリ対応)
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# 詳細なリクエスト(ヘッダー等を含む)
|
||||
request = {
|
||||
args = [
|
||||
{ from = "string", to = "string" }, # メソッド(GET/POST等)
|
||||
{ from = "string", to = "string" }, # URL
|
||||
{ from = "map", to = "map" } # オプション(headers, timeout等)
|
||||
],
|
||||
returns = "map" # { status: i32, body: string, headers: map }
|
||||
}
|
||||
```
|
||||
|
||||
### 🖼️ Phase 2: GUI系(プラットフォーム依存)
|
||||
EguiBoxは既にfeature分離されているので参考になります。
|
||||
|
||||
### 🎵 Phase 3: 特殊用途系(独立性高い)
|
||||
TimerBox、QRBox等は単機能で実装しやすいです。
|
||||
|
||||
## 🔧 実装ガイドライン
|
||||
|
||||
### 1. 参考にするファイル
|
||||
- **成功例**: `plugins/nyash-filebox-plugin/` - 動作確認済みのFileBoxプラグイン
|
||||
- **設定例**: `nyash.toml` - 型情報定義の書き方
|
||||
- **テスト**: `tools/plugin-tester/` - プラグイン診断ツール
|
||||
|
||||
### 2. 各プラグインの構成
|
||||
```
|
||||
plugins/nyash-xxx-plugin/
|
||||
├── Cargo.toml # 依存関係(例: reqwest for HTTP)
|
||||
├── src/
|
||||
│ └── lib.rs # FFI実装
|
||||
├── nyash.toml # 型情報定義
|
||||
└── README.md # 使用方法
|
||||
```
|
||||
|
||||
### 3. nyash.toml記述例(HttpClientBoxの場合)
|
||||
```toml
|
||||
[plugins.HttpClientBox.methods]
|
||||
# GETリクエスト
|
||||
get = {
|
||||
args = [{ name = "url", from = "string", to = "string" }],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# POSTリクエスト
|
||||
post = {
|
||||
args = [
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "body", from = "string", to = "string" }
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# ヘッダー付きリクエスト
|
||||
request = {
|
||||
args = [
|
||||
{ name = "method", from = "string", to = "string" },
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "options", from = "map", to = "map" }
|
||||
],
|
||||
returns = "map" # { status, body, headers }
|
||||
}
|
||||
|
||||
# DELETE リクエスト
|
||||
delete = {
|
||||
args = [{ name = "url", from = "string", to = "string" }],
|
||||
returns = "string"
|
||||
}
|
||||
|
||||
# PUT リクエスト
|
||||
put = {
|
||||
args = [
|
||||
{ name = "url", from = "string", to = "string" },
|
||||
{ name = "body", from = "string", to = "string" }
|
||||
],
|
||||
returns = "string"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. テスト方法
|
||||
```bash
|
||||
# ビルド
|
||||
cd plugins/nyash-xxx-plugin
|
||||
cargo build --release
|
||||
|
||||
# plugin-testerで診断
|
||||
cd ../../tools/plugin-tester
|
||||
./target/release/plugin-tester ../../plugins/nyash-xxx-plugin/target/release/libnyash_xxx_plugin.so
|
||||
|
||||
# Nyashで実行テスト
|
||||
./target/release/nyash test_xxx.nyash
|
||||
```
|
||||
|
||||
## 📝 特記事項
|
||||
|
||||
### HttpBox系
|
||||
- 現在スタブ実装なので移行しやすい
|
||||
- reqwest依存を復活させる
|
||||
- 非同期処理の考慮が必要
|
||||
|
||||
### EguiBox
|
||||
- 既にfeature分離されているので参考になる
|
||||
- メインスレッド制約に注意
|
||||
|
||||
### AudioBox/SoundBox
|
||||
- プラットフォーム依存性が高い
|
||||
- Web/Desktop両対応を検討
|
||||
|
||||
### 依存関係の管理
|
||||
- 各プラグインは独立したCargo.tomlを持つ
|
||||
- ビルド時間短縮のため最小限の依存にする
|
||||
|
||||
## 💡 実装の重要ポイント
|
||||
|
||||
### FFI境界での注意事項
|
||||
1. **メモリ管理**:
|
||||
- Rustの所有権とCのメモリ管理の違いに注意
|
||||
- 文字列は必ずCString/CStr経由で変換
|
||||
|
||||
2. **エラーハンドリング**:
|
||||
- パニックをFFI境界で止める(catch_unwind使用)
|
||||
- エラーコードで通信(0=成功, 負値=エラー)
|
||||
|
||||
3. **型変換パターン** (FileBoxプラグインより):
|
||||
```rust
|
||||
// Nyash文字列 → Rust文字列
|
||||
let path = get_string_arg(&args[0], 0)?;
|
||||
|
||||
// Rust文字列 → Nyash文字列
|
||||
encode_string_result(&contents, result, result_len)
|
||||
```
|
||||
|
||||
### 参考ファイルの具体的パス
|
||||
- **FileBoxプラグイン実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
|
||||
- **FFI仕様書**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
|
||||
- **プラグインシステム説明**: `docs/説明書/reference/plugin-system/plugin-system.md`
|
||||
- **BID-FFI型変換** (参考): `src/bid-converter-copilot/tlv.rs`
|
||||
|
||||
## 🔧 実装ガイド:FileBoxを例に
|
||||
|
||||
### 1. プラグイン側での型受け取り例
|
||||
|
||||
```rust
|
||||
// nyash.toml: write = { args = [{ from = "string", to = "bytes" }] }
|
||||
METHOD_WRITE => {
|
||||
// TLVでbytesとして受け取る
|
||||
let data = tlv_parse_bytes(args)?; // Vec<u8>として取得
|
||||
|
||||
// ファイルに書き込み
|
||||
match file.write(&data) {
|
||||
Ok(n) => {
|
||||
file.flush()?; // 重要:フラッシュを忘れずに!
|
||||
// 書き込んだバイト数を返す(TLV i32)
|
||||
write_tlv_i32(n as i32, result, result_len)
|
||||
}
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 複数引数の解析例
|
||||
|
||||
```rust
|
||||
// nyash.toml: open = { args = [{ from = "string", to = "string" }, { from = "string", to = "string" }] }
|
||||
METHOD_OPEN => {
|
||||
// 2つのstring引数を解析
|
||||
let (path, mode) = tlv_parse_two_strings(args)?;
|
||||
|
||||
// ファイルを開く
|
||||
let file = match mode.as_str() {
|
||||
"r" => File::open(&path)?,
|
||||
"w" => File::create(&path)?,
|
||||
"a" => OpenOptions::new().append(true).open(&path)?,
|
||||
_ => return NYB_E_INVALID_ARGS
|
||||
};
|
||||
|
||||
// 成功時はVoid(空)を返す
|
||||
write_tlv_void(result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 引数なしメソッドの例
|
||||
|
||||
```rust
|
||||
// nyash.toml: read = { args = [] }
|
||||
METHOD_READ => {
|
||||
// 引数なし - ファイル全体を読む
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
let mut buf = Vec::new();
|
||||
file.read_to_end(&mut buf)?;
|
||||
|
||||
// bytesとして返す
|
||||
write_tlv_bytes(&buf, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 HttpClientBox実装の具体例
|
||||
|
||||
```rust
|
||||
// HttpClientBoxプラグインの実装イメージ
|
||||
use reqwest::blocking::Client;
|
||||
|
||||
METHOD_GET => {
|
||||
// URLを解析
|
||||
let url = tlv_parse_string(args)?;
|
||||
|
||||
// HTTPリクエスト実行
|
||||
let client = Client::new();
|
||||
let response = client.get(&url).send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
// 文字列として返す
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
|
||||
METHOD_POST => {
|
||||
// URL と ボディを解析
|
||||
let (url, body_bytes) = tlv_parse_string_and_bytes(args)?;
|
||||
|
||||
// POSTリクエスト
|
||||
let client = Client::new();
|
||||
let response = client.post(&url)
|
||||
.body(body_bytes)
|
||||
.send()?;
|
||||
let body = response.text()?;
|
||||
|
||||
write_tlv_string(&body, result, result_len)
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 実装のコツとよくある間違い
|
||||
|
||||
### ✅ 正しいnyash.toml
|
||||
```toml
|
||||
# 引数の型変換を明示
|
||||
write = { args = [{ from = "string", to = "bytes" }] }
|
||||
|
||||
# 戻り値の型も指定可能
|
||||
exists = { args = [], returns = "bool" }
|
||||
```
|
||||
|
||||
### ❌ よくある間違い
|
||||
```toml
|
||||
# 間違い:型情報がない
|
||||
write = { args = ["string"] } # ❌ from/toが必要
|
||||
|
||||
# 間違い:不要なフィールド
|
||||
get = { args = [{ type = "string" }] } # ❌ typeではなくfrom/to
|
||||
```
|
||||
|
||||
### メモリ管理の注意点
|
||||
1. 文字列は必ずCString/CStr経由で変換
|
||||
2. プラグイン側でallocしたメモリはプラグイン側でfree
|
||||
3. ホスト側のVtableを使ってログ出力
|
||||
|
||||
### エラーハンドリング
|
||||
```rust
|
||||
// パニックをFFI境界で止める
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
// 実際の処理
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(val) => val,
|
||||
Err(_) => NYB_E_PLUGIN_ERROR
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 テスト方法
|
||||
|
||||
### 1. プラグインビルド
|
||||
```bash
|
||||
cd plugins/nyash-http-plugin
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### 2. plugin-testerで診断
|
||||
```bash
|
||||
cd ../../tools/plugin-tester
|
||||
./target/release/plugin-tester ../../plugins/nyash-http-plugin/target/release/libnyash_http_plugin.so
|
||||
|
||||
# 期待される出力:
|
||||
# Plugin Information:
|
||||
# Box Type: HttpClientBox (ID: 20)
|
||||
# Methods: 5
|
||||
# - birth [ID: 0] (constructor)
|
||||
# - get, post, put, delete
|
||||
# - fini [ID: 4294967295] (destructor)
|
||||
```
|
||||
|
||||
### 3. Nyashで実行
|
||||
```nyash
|
||||
// test_http.nyash
|
||||
local http = new HttpClientBox()
|
||||
local response = http.get("https://api.example.com/data")
|
||||
print(response)
|
||||
```
|
||||
|
||||
## 📚 参考資料
|
||||
- **FileBoxプラグイン完全実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
|
||||
- **TLVエンコーディング仕様**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
|
||||
- **nyash.toml設定例**: プロジェクトルートの`nyash.toml`
|
||||
|
||||
## 🎯 成功の秘訣
|
||||
1. **FileBoxを完全に理解してから始める** - コピペベースで改造
|
||||
2. **nyash.tomlの型定義を正確に** - from/toを明示
|
||||
3. **TLVの理解** - tag=6(string), tag=7(bytes)の違い
|
||||
4. **plugin-testerで早期検証** - 問題を早期発見
|
||||
|
||||
---
|
||||
|
||||
質問があれば、FileBoxの実装を参考にしてください。
|
||||
すべての答えがそこにあります!
|
||||
@ -1,54 +0,0 @@
|
||||
# 📦 Nyash Boxシステム設計ドキュメント
|
||||
|
||||
## 🎯 概要
|
||||
|
||||
Nyashの核心哲学「**Everything is Box**」に関する完全な設計ドキュメント集。
|
||||
言語設計の根幹から実装詳細まで、Boxシステムのすべてを網羅しています。
|
||||
|
||||
## 📚 ドキュメント構成
|
||||
|
||||
### 🌟 コア哲学
|
||||
|
||||
#### [everything-is-box.md](everything-is-box.md)
|
||||
Nyashの核心哲学「Everything is Box」の解説。なぜすべてをBoxにするのか、その設計思想と利点。
|
||||
|
||||
### 📖 完全リファレンス
|
||||
|
||||
#### [box-reference.md](box-reference.md)
|
||||
**統合版Box型完全リファレンス**。全ビルトインBox型のAPI仕様、基本型からプラグインBoxまで。
|
||||
|
||||
### 🔄 システム設計
|
||||
|
||||
#### [delegation-system.md](delegation-system.md)
|
||||
完全明示デリゲーションシステムの設計。`from`構文、`override`必須、`pack`構文の詳細仕様。
|
||||
|
||||
#### [memory-finalization.md](memory-finalization.md)
|
||||
**統合版メモリ管理&finiシステム**。Arc<Mutex>一元管理、fini()論理的解放、weak参照、プラグインメモリ安全性。
|
||||
|
||||
## 🔗 関連ドキュメント
|
||||
|
||||
- **[プラグインシステム](../plugin-system/)**: BID-FFIプラグインシステム完全仕様
|
||||
- **[言語仕様](../core-language/)**: デリゲーション構文、言語リファレンス
|
||||
- **[実行バックエンド](../execution-backend/)**: MIR、P2P通信仕様
|
||||
|
||||
## 🎨 設計原則
|
||||
|
||||
### Everything is Box
|
||||
- すべての値がBoxオブジェクト
|
||||
- 統一的なメソッド呼び出し
|
||||
- プリミティブ型と参照型の区別なし
|
||||
|
||||
### メモリ安全性
|
||||
- Arc<Mutex>による統一管理
|
||||
- fini()による決定論的リソース解放
|
||||
- weak参照による循環参照回避
|
||||
|
||||
### プラグイン拡張性
|
||||
- BID-FFIによる外部ライブラリ統合
|
||||
- 型情報管理による安全な変換
|
||||
- HostVtableによるメモリ管理
|
||||
|
||||
---
|
||||
|
||||
**最終更新**: 2025年8月19日 - boxes-system統合整理完了
|
||||
**Phase 9.75g-0成果**: プラグインシステムとの完全統合
|
||||
@ -1,246 +0,0 @@
|
||||
# 🔄 ビルトインBox → プラグイン変換手順書
|
||||
|
||||
## 🎯 概要
|
||||
|
||||
ビルトインBoxをBID-FFI v1プラグインに変換する標準手順。実際の変換作業で発見された問題と解決策を蓄積し、効率的な開発手法を確立する。
|
||||
|
||||
## 📊 変換パターン分析
|
||||
|
||||
### 🏆 成功事例:FileBox変換
|
||||
- **元実装**: `src/boxes/file/mod.rs` (RwLock<File>)
|
||||
- **プラグイン**: `plugins/nyash-filebox-plugin/` (BID-FFI v1)
|
||||
- **結果**: ✅ 完全動作、プラグイン優先使用
|
||||
|
||||
### 🔍 現状分析:HTTP系Box
|
||||
- **実装状況**: 完全実装済み(432行の高機能HTTPサーバー)
|
||||
- **問題**: Unified Registry未登録(Legacy Match使用)
|
||||
- **潜在性**: 即座にプラグイン化可能
|
||||
|
||||
## 🚀 標準変換手順(3段階アプローチ)
|
||||
|
||||
### Phase 1: ビルトイン最適化
|
||||
**目的**: 既存実装の性能向上・デバッグ
|
||||
**期間**: 1-3日
|
||||
|
||||
#### 手順
|
||||
1. **Unified Registry登録**
|
||||
```rust
|
||||
// src/box_factory/builtin.rs 内
|
||||
fn register_io_types(&mut self) {
|
||||
// HTTPServerBox追加
|
||||
self.register("HTTPServerBox", |args| {
|
||||
if !args.is_empty() {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: format!("HTTPServerBox constructor expects 0 arguments, got {}", args.len()),
|
||||
});
|
||||
}
|
||||
Ok(Box::new(HTTPServerBox::new()))
|
||||
});
|
||||
// 他のHTTP系Boxも同様に追加
|
||||
}
|
||||
```
|
||||
|
||||
2. **動作テスト作成**
|
||||
```nyash
|
||||
// local_tests/test_http_builtin.nyash
|
||||
static box Main {
|
||||
main() {
|
||||
local server = new HTTPServerBox()
|
||||
server.bind("localhost", 8080)
|
||||
server.get("/test", TestHandler.handle)
|
||||
return "HTTP builtin test complete"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **性能ベンチマーク**
|
||||
- Legacy Match vs Unified Registry比較
|
||||
- メモリ使用量測定
|
||||
|
||||
#### 期待効果
|
||||
- ✅ 高速化(Legacy Match削除)
|
||||
- ✅ デバッグ環境確立
|
||||
- ✅ 安定性確認
|
||||
|
||||
### Phase 2: プラグイン変換実装
|
||||
**目的**: BID-FFI v1プラグイン実装
|
||||
**期間**: 3-7日
|
||||
|
||||
#### 手順
|
||||
1. **プラグインプロジェクト作成**
|
||||
```bash
|
||||
mkdir plugins/nyash-http-plugin
|
||||
cd plugins/nyash-http-plugin
|
||||
cargo init --lib
|
||||
```
|
||||
|
||||
2. **Cargo.toml設定**
|
||||
```toml
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
once_cell = "1.0"
|
||||
# HTTP依存関係
|
||||
```
|
||||
|
||||
3. **BID-FFI v1実装**
|
||||
- マルチBox対応(HTTPServerBox, HTTPClientBox, SocketBox)
|
||||
- TLV Protocol実装
|
||||
- Method ID定義
|
||||
|
||||
4. **nyash.toml設定**
|
||||
```toml
|
||||
[libraries."libnyash_http_plugin.so"]
|
||||
boxes = ["HTTPServerBox", "HTTPClientBox", "SocketBox"]
|
||||
|
||||
[libraries."libnyash_http_plugin.so".HTTPServerBox]
|
||||
type_id = 10
|
||||
[libraries."libnyash_http_plugin.so".HTTPServerBox.methods]
|
||||
birth = { method_id = 0 }
|
||||
bind = { method_id = 1, args = ["address", "port"] }
|
||||
listen = { method_id = 2, args = ["backlog"] }
|
||||
start = { method_id = 3 }
|
||||
stop = { method_id = 4 }
|
||||
fini = { method_id = 4294967295 }
|
||||
```
|
||||
|
||||
### Phase 3: 移行・検証
|
||||
**目的**: 完全移行とパフォーマンス検証
|
||||
**期間**: 1-2日
|
||||
|
||||
#### 手順
|
||||
1. **プラグイン優先テスト**
|
||||
- 同じテストケースでビルトイン vs プラグイン比較
|
||||
- メモリリーク検証
|
||||
- エラーハンドリング確認
|
||||
|
||||
2. **ビルトイン実装削除**
|
||||
- `src/boxes/http_*` ファイル削除
|
||||
- BUILTIN_BOXES リストから除去
|
||||
- コンパイル確認
|
||||
|
||||
3. **本格アプリテスト**
|
||||
```nyash
|
||||
// apps/http_example/
|
||||
// 実用的なHTTPサーバーアプリで動作確認
|
||||
```
|
||||
|
||||
## 🔧 BID-FFI v1必須要件
|
||||
|
||||
### ✅ **絶対必須の2つのメソッド**
|
||||
|
||||
すべてのBID-FFI v1プラグインで実装必須:
|
||||
|
||||
**🔧 birth() - コンストラクタ (METHOD_ID = 0)**
|
||||
```rust
|
||||
const METHOD_BIRTH: u32 = 0; // Constructor
|
||||
```
|
||||
- **機能**: インスタンス作成、instance_id返却
|
||||
- **必須実装**: インスタンス管理、メモリ確保
|
||||
- **戻り値**: TLV形式のinstance_id (u32)
|
||||
|
||||
**🧹 fini() - デストラクタ (METHOD_ID = u32::MAX)**
|
||||
```rust
|
||||
const METHOD_FINI: u32 = u32::MAX; // Destructor (4294967295)
|
||||
```
|
||||
- **機能**: インスタンス解放、メモリクリーンアップ
|
||||
- **必須実装**: INSTANCES.remove(), リソース解放
|
||||
- **戻り値**: 成功ステータス
|
||||
|
||||
### 📝 設定例
|
||||
```toml
|
||||
[libraries."libnyash_example_plugin.so".ExampleBox.methods]
|
||||
birth = { method_id = 0 } # 🔧 必須
|
||||
# ... カスタムメソッド ...
|
||||
fini = { method_id = 4294967295 } # 🧹 必須
|
||||
```
|
||||
|
||||
## 🐛 発見済み問題と解決策
|
||||
|
||||
### Problem 1: toString()メソッドエラー
|
||||
**現象**: `Unknown method 'toString' for FileBox`
|
||||
```
|
||||
❌ Interpreter error: Invalid operation: Unknown method 'toString' for FileBox
|
||||
```
|
||||
|
||||
**原因**: プラグインにtoString()メソッド未定義
|
||||
**解決策**: nyash.tomlでtoStringメソッド追加
|
||||
```toml
|
||||
toString = { method_id = 5 }
|
||||
```
|
||||
|
||||
### Problem 2: Unified Registry未登録Box
|
||||
**現象**: `Falling back to legacy match statement`
|
||||
```
|
||||
🔍 Unified registry failed for HTTPServerBox: Unknown Box type
|
||||
🔍 Falling back to legacy match statement
|
||||
```
|
||||
|
||||
**原因**: BuiltinBoxFactory.register_io_types()未登録
|
||||
**解決策**: HTTP系Box登録追加
|
||||
|
||||
### Problem 3: 複雑な依存関係
|
||||
**予想問題**: HTTPServerBox → SocketBox → OS固有API
|
||||
**解決策**: プラグイン内で依存関係完結
|
||||
|
||||
## 📋 チェックリスト
|
||||
|
||||
### ✅ Phase 1完了条件
|
||||
- [ ] Unified Registry登録完了
|
||||
- [ ] Legacy Match削除確認
|
||||
- [ ] 基本動作テスト成功
|
||||
- [ ] パフォーマンス改善確認
|
||||
|
||||
### ✅ Phase 2完了条件
|
||||
- [ ] プラグインビルド成功
|
||||
- [ ] BID-FFI v1インターフェース実装
|
||||
- [ ] 全メソッドTLV対応
|
||||
- [ ] plugin-testerで検証成功
|
||||
|
||||
### ✅ Phase 3完了条件
|
||||
- [ ] プラグイン優先動作確認
|
||||
- [ ] ビルトイン実装削除成功
|
||||
- [ ] 実用アプリケーション動作確認
|
||||
- [ ] メモリリーク・エラーなし
|
||||
|
||||
## 🚀 期待効果
|
||||
|
||||
### 短期効果(Phase 1)
|
||||
- **5-10倍高速化**: Legacy Match → Unified Registry
|
||||
- **保守性向上**: 統一的なファクトリパターン
|
||||
- **デバッグ環境**: 安定したテスト基盤
|
||||
|
||||
### 長期効果(Phase 3)
|
||||
- **プラグイン化完了**: 外部配布可能
|
||||
- **アーキテクチャ改善**: コア軽量化
|
||||
- **拡張性向上**: 独立開発可能
|
||||
|
||||
## 🎯 次期対象Box候補
|
||||
|
||||
### 優先度高(実装済み)
|
||||
1. **HTTP系**: HTTPServerBox, HTTPClientBox, SocketBox
|
||||
2. **BufferBox**: バイナリデータ処理
|
||||
3. **RegexBox**: 正規表現処理
|
||||
|
||||
### 優先度中(要調査)
|
||||
1. **MathBox, RandomBox**: プラグイン実装あり(第1世代C ABI)
|
||||
2. **JSONBox**: データ交換
|
||||
3. **StreamBox**: ストリーム処理
|
||||
|
||||
## 📝 学習記録
|
||||
|
||||
### 成功パターン
|
||||
- FileBox: 単純構造、明確API → スムーズ変換
|
||||
- プラグイン優先システム動作確認済み
|
||||
|
||||
### 注意点
|
||||
- toString()等の基本メソッド必須
|
||||
- 依存関係の循環に注意
|
||||
- メモリ管理の完全分離
|
||||
|
||||
---
|
||||
|
||||
**最終更新**: 2025年8月20日 - 初版作成
|
||||
**Phase**: 9.75g-0 完了後 - HTTP系Box変換準備完了
|
||||
**Next**: Phase 1実装→Phase 2プラグイン化
|
||||
@ -1,180 +0,0 @@
|
||||
# 🧠 Nyash メモリ管理 & finiシステム
|
||||
|
||||
**最終更新: 2025年8月19日 - 統合仕様書**
|
||||
|
||||
## 📋 概要
|
||||
|
||||
Nyashは「Everything is Box」哲学のもと、統一的なメモリ管理と予測可能なリソース解放を実現しています。
|
||||
|
||||
## 🏗️ 基本アーキテクチャ
|
||||
|
||||
### Arc<Mutex>一元管理
|
||||
|
||||
```rust
|
||||
// インタープリターレベルでの統一管理
|
||||
type NyashObject = Arc<Mutex<dyn NyashBox>>;
|
||||
```
|
||||
|
||||
すべてのBoxは、インタープリターレベルで`Arc<Mutex>`によって管理されます。
|
||||
|
||||
#### 利点
|
||||
- **スレッドセーフティ**: 自動的に保証
|
||||
- **参照カウント**: 自動的なメモリ解放
|
||||
- **統一的アクセス**: すべて同じ方法で操作
|
||||
|
||||
#### 設計原則
|
||||
|
||||
```rust
|
||||
// ✅ 正しい設計(シンプルなフィールド)
|
||||
pub struct GoodBox {
|
||||
data: String,
|
||||
count: i32,
|
||||
}
|
||||
|
||||
// ❌ アンチパターン(Box内部での二重ロック)
|
||||
pub struct BadBox {
|
||||
data: Arc<Mutex<String>>, // 内部でロック管理しない
|
||||
}
|
||||
```
|
||||
|
||||
### プラグインシステムのメモリ管理
|
||||
|
||||
BID-FFIプラグインシステムでは、**HostVtable**を通じて安全なメモリ管理を実現:
|
||||
|
||||
```rust
|
||||
pub struct NyashHostVtable {
|
||||
pub alloc: unsafe extern "C" fn(size: usize) -> *mut u8,
|
||||
pub free: unsafe extern "C" fn(ptr: *mut u8),
|
||||
pub wake: unsafe extern "C" fn(handle: u64),
|
||||
pub log: unsafe extern "C" fn(level: i32, msg: *const c_char),
|
||||
}
|
||||
```
|
||||
|
||||
**重要**: プラグインが割り当てたメモリはプラグインが解放する原則
|
||||
|
||||
## 🔥 finiシステム - 論理的解放フック
|
||||
|
||||
### 核心コンセプト
|
||||
|
||||
`fini()`は**物理的メモリ破棄ではなく論理的使用終了**を宣言する革新的システムです。
|
||||
|
||||
```nyash
|
||||
box MyResource {
|
||||
init { name, file }
|
||||
|
||||
fini() {
|
||||
print("Resource " + me.name + " is being finalized")
|
||||
// ファイルクローズなどのクリーンアップ処理
|
||||
// 物理的メモリは共有参照が残っていても論理的には「終了」
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**重要**: `fini()`は「このオブジェクトをもう使わない」という宣言であり、物理的な即時破棄ではありません。
|
||||
|
||||
### 実行順序(確定仕様)
|
||||
|
||||
#### 自動カスケード解放
|
||||
```nyash
|
||||
box Pipeline {
|
||||
init { r1, r2, r3, weak monitor }
|
||||
|
||||
fini() {
|
||||
// 1) ユーザー定義処理(柔軟な順序制御可能)
|
||||
me.r3.fini() // 依存関係でr3→r2の順
|
||||
me.r2.fini()
|
||||
|
||||
// 2) 自動カスケード: 残りのr1がinit宣言順で自動解放
|
||||
// 3) weakフィールドは対象外(lazy nil化)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 決定的な解放順序
|
||||
1. **finalized チェック** - 既に解放済みなら何もしない(idempotent)
|
||||
2. **再入防止** - `in_finalization`フラグで再帰呼び出し防止
|
||||
3. **ユーザー定義fini()実行** - カスタムクリーンアップ処理
|
||||
4. **自動カスケード** - `init`宣言順で未処理フィールドを解放
|
||||
5. **フィールドクリア** - 全フィールドを無効化
|
||||
6. **finalized設定** - 以後の使用を禁止
|
||||
|
||||
### weak参照による循環参照回避
|
||||
|
||||
```nyash
|
||||
box Node {
|
||||
init { id, weak next } // 'next'は弱参照
|
||||
}
|
||||
|
||||
local node1 = new Node("A", null)
|
||||
local node2 = new Node("B", node1) // node2はnode1への弱参照を持つ
|
||||
node1.next = node2 // node1はnode2への強参照を持つ
|
||||
// 循環参照を回避し、安全に解放される
|
||||
```
|
||||
|
||||
#### weak参照の特性
|
||||
- **所有権なし**: オブジェクトの生存期間に影響しない
|
||||
- **自動nil化**: 参照先が解放されると自動的に`null`になる
|
||||
- **fini()対象外**: 弱参照フィールドはfini()カスケードでスキップ
|
||||
|
||||
### 不変条件(重要)
|
||||
|
||||
- **weak参照**: `weak`フィールドに対して`fini()`を直接呼ぶことはできません
|
||||
- **finalized後禁止**: `fini()`呼び出し後は、そのオブジェクトの使用はすべて禁止
|
||||
- **カスケード順序**: `init`宣言順の**逆順**で実行、`weak`フィールドはスキップ
|
||||
|
||||
## 🌟 実用例
|
||||
|
||||
### リソース管理
|
||||
```nyash
|
||||
box FileHandler {
|
||||
init { file, buffer }
|
||||
|
||||
fini() {
|
||||
// オブジェクト削除時に自動呼び出し
|
||||
if me.file != null {
|
||||
me.file.close()
|
||||
console.log("File closed automatically")
|
||||
}
|
||||
// bufferは自動カスケードで解放
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### プラグインリソース
|
||||
```nyash
|
||||
box PluginResource {
|
||||
init { plugin_handle }
|
||||
|
||||
fini() {
|
||||
// プラグイン側のリソース解放を呼び出し
|
||||
me.plugin_handle.cleanup()
|
||||
console.log("Plugin resource finalized")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🛡️ メモリ安全性保証
|
||||
|
||||
### valgrind検証済み
|
||||
- **セグフォルト回避**: HostVtableの生存期間問題解決済み
|
||||
- **メモリリーク検出**: プラグインシステムでのメモリ管理検証済み
|
||||
- **二重解放防止**: idempotentなfini()実装
|
||||
|
||||
### プラグインメモリ安全性
|
||||
- **プラグイン分離**: プラグインメモリはプラグインが管理
|
||||
- **境界明確化**: HostVtableを通じた安全なインターフェース
|
||||
- **ライフサイクル管理**: birth/finiによる明確な生存期間
|
||||
|
||||
## 🚀 Phase 9.75g-0での進化
|
||||
|
||||
- **BID-FFIプラグインシステム**: 外部ライブラリの安全な統合
|
||||
- **型情報管理**: nyash.tomlによる型安全な変換
|
||||
- **HostVtable**: プラグイン↔ホスト間の安全なメモリ管理
|
||||
- **plugin-tester**: メモリ安全性診断ツール
|
||||
|
||||
---
|
||||
|
||||
**関連ドキュメント**:
|
||||
- [Box型リファレンス](box-reference.md)
|
||||
- [プラグインシステム](../plugin-system/)
|
||||
- [BID-FFI仕様](../plugin-system/ffi-abi-specification.md)
|
||||
@ -1,39 +0,0 @@
|
||||
# P2PBox - Modern P2P Node (InProcess)
|
||||
|
||||
Status: Experimental (Phase 9.79a)
|
||||
|
||||
## Overview
|
||||
- Structured messaging with `IntentBox(name, payload)`
|
||||
- Local in-process routing via `MessageBus`
|
||||
- Deterministic smoke demo available without timers
|
||||
|
||||
## API
|
||||
- `new P2PBox(nodeId: String, transport: String)`
|
||||
- `send(to: String|Box, intent: IntentBox) -> ResultBox`
|
||||
- `on(name: String, handler: MethodRef) -> ResultBox`
|
||||
- `onOnce(name: String, handler: MethodRef) -> ResultBox`
|
||||
- `off(name: String) -> ResultBox`
|
||||
- `getNodeId() -> String`
|
||||
- `isReachable(nodeId: String) -> Bool`
|
||||
- `getTransportType() -> String`
|
||||
- `debugNodes() -> String` (inprocess only)
|
||||
- `debugBusId() -> String` (inprocess only)
|
||||
- `getLastFrom() -> String` (loopback trace)
|
||||
- `getLastIntentName() -> String` (loopback trace)
|
||||
|
||||
Notes:
|
||||
- Handlers currently accept a method reference (`MethodBox`) rather than an inline function literal.
|
||||
- For quick loopback smoke without handlers, send to self and read `getLast*()`.
|
||||
|
||||
## Quick Smoke (No Handlers)
|
||||
```
|
||||
alice = new P2PBox("alice", "inprocess")
|
||||
msg = new IntentBox("ping", { })
|
||||
res = alice.send("alice", msg)
|
||||
print("last.from=" + alice.getLastFrom())
|
||||
print("last.intent=" + alice.getLastIntentName())
|
||||
```
|
||||
|
||||
## Two-Node Ping-Pong (Concept)
|
||||
This is covered in unit tests; handler wiring uses `MethodBox` internally. A higher-level sugar for method references will arrive in later phases.
|
||||
|
||||
@ -1,109 +0,0 @@
|
||||
# プラグインBoxのライフサイクル(v2)と nyash.toml 定義
|
||||
|
||||
本書は、プラグインBox(PluginBoxV2)の生成(birth)と終了(fini)の流れ、`singleton` オプション、ならびに nyash.toml v2 における `methods` 定義の役割をまとめたものです。
|
||||
|
||||
---
|
||||
|
||||
## 1. 用語
|
||||
- birth: プラグインBoxのインスタンス生成(`method_id=0`)
|
||||
- fini: プラグインBoxの終了処理(任意の `method_id`。例: `4294967295`)
|
||||
- invoke_fn: プラグイン側の単一エントリポイント(`nyash_plugin_invoke`)
|
||||
|
||||
---
|
||||
|
||||
## 2. 生成(birth)の流れ
|
||||
1. `unified registry` が `PluginLoaderV2::create_box(box_type, args)` を呼び出す。
|
||||
2. `PluginLoaderV2` は `nyash.toml` から `type_id` と `methods` を読み込む。
|
||||
3. `invoke_fn(type_id, method_id=0 /* birth */, instance_id=0, ...)` を呼び、戻り値(出力TLV)の先頭4バイトから `instance_id` を取得。
|
||||
4. `PluginBoxV2 { box_type, inner: Arc<PluginHandleInner> }` を生成して返す。
|
||||
- `PluginHandleInner` は `{ type_id, instance_id, invoke_fn, fini_method_id, finalized }` を保持し、参照カウント(Arc)で共有される。
|
||||
|
||||
補足:
|
||||
- `fini_method_id` は `nyash.toml` の `methods` から `fini` の `method_id` を取り出して保持します。未定義の場合は `None`。
|
||||
|
||||
---
|
||||
|
||||
## 3. 終了(fini)の流れ(現在)
|
||||
- フィールド差し替え時(代入で旧値を置き換えるとき):
|
||||
- 旧値が `InstanceBox` の場合: インタプリタが `fini()` を呼び、finalized としてマーキングします。
|
||||
- 旧値が `PluginBoxV2` の場合: `fini_method_id` が設定されていれば `invoke_fn(type_id, fini_method_id, instance_id, ...)` を呼びます。
|
||||
- プラグインBox(PluginBoxV2):
|
||||
- すべての参照(Arc)がDropされ「最後の参照が解放」された時、`Drop`で一度だけ `fini` を呼ぶ(RAII、二重呼び出し防止)。
|
||||
- 明示finiが必要な場合は `PluginBoxV2::finalize_now()` を使える(内部的に一度だけfini実行)。
|
||||
- 代入/フィールド代入/Map.get/Array.get/slice/退避などは「PluginBoxV2は共有(share)、それ以外は複製(clone)」で統一。
|
||||
|
||||
---
|
||||
|
||||
## 4. nyash.toml v2 の定義例(methods + singleton)
|
||||
|
||||
```toml
|
||||
[libraries]
|
||||
[libraries."libnyash_filebox_plugin.so"]
|
||||
boxes = ["FileBox"]
|
||||
path = "./plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so"
|
||||
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox]
|
||||
type_id = 6
|
||||
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
|
||||
birth = { method_id = 0 }
|
||||
open = { method_id = 1 }
|
||||
read = { method_id = 2 }
|
||||
write = { method_id = 3 }
|
||||
close = { method_id = 4 }
|
||||
fini = { method_id = 4294967295 } # 任意の終端ID
|
||||
```
|
||||
|
||||
要点:
|
||||
- `methods` に `fini` を定義すれば、差し替え時などに fini が呼ばれます。
|
||||
- `fini` 未定義の場合、プラグインBoxの終了処理は呼ばれません(フォールバック動作)。
|
||||
|
||||
### singleton例
|
||||
|
||||
```toml
|
||||
[libraries."libnyash_counter_plugin.so".CounterBox]
|
||||
type_id = 7
|
||||
singleton = true
|
||||
|
||||
[libraries."libnyash_counter_plugin.so".CounterBox.methods]
|
||||
birth = { method_id = 0 }
|
||||
inc = { method_id = 1 }
|
||||
get = { method_id = 2 }
|
||||
fini = { method_id = 4294967295 }
|
||||
```
|
||||
|
||||
- `singleton = true` を設定すると、ローダー初期化時に事前birthし、ローダーが共有ハンドルを保持します。
|
||||
- `create_box()` は保持中の共有ハンドルを返すため、複数回の `new` でも同一インスタンスを共有できます。
|
||||
- Nyash終了時(または明示要求時)に `shutdown_plugins_v2()` を呼ぶと、ローダーが保持する全シングルトンの `fini` を実行し、クリーンに解放されます。
|
||||
|
||||
---
|
||||
|
||||
## 5. WASM(wasm-bindgen)との関係
|
||||
- WASMターゲットでは `libloading` が使えないため、プラグイン機構は features/cfg でスタブ化しています。
|
||||
- `plugins` フィーチャを外す、または `target_arch = "wasm32"` のときは、プラグイン生成・fini 呼び出しのコードはコンパイル対象外になります(ビルド可能化のため)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 将来拡張の方向
|
||||
- ローカル変数のスコープ終了時(関数/メソッド呼び出しの戻りなど)に、InstanceBox/PluginBoxV2 の fini を安全に呼び出す仕組み(順序・例外耐性・二重呼び出し防止を含む)。
|
||||
- `nyash.toml` にクラス名→プラグインBox型の `overrides` を加え、ユーザー定義Boxの外部置換を許可する設計(任意)。
|
||||
|
||||
以上。
|
||||
|
||||
---
|
||||
|
||||
## 7. v2.1: BoxRef(Box引数)サポート
|
||||
|
||||
目的: プラグインメソッドの引数として、他のBoxインスタンスを不透明参照で受け渡し可能にする。
|
||||
|
||||
- 仕様詳細: `docs/reference/plugin-system/nyash-toml-v2_1-spec.md`
|
||||
- 設定例(1引数にプラグインBoxを渡す):
|
||||
|
||||
```toml
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
|
||||
copyFrom = { method_id = 7, args = [ { kind = "box", category = "plugin" } ] }
|
||||
```
|
||||
|
||||
注意:
|
||||
- 当面は `category = "plugin"` のみ対応。ユーザー定義Boxや複雑なビルトインBoxは非対応。
|
||||
- 戻り値の BoxRef は次版(v2.2)で検討。
|
||||
@ -1,23 +0,0 @@
|
||||
# Nyash Core Language Documentation
|
||||
|
||||
## 📚 最新の言語仕様
|
||||
|
||||
**最新の完全な言語リファレンスは以下を参照してください:**
|
||||
|
||||
- **[🚀 Nyash Language Reference 2025](../../../../reference/language/LANGUAGE_REFERENCE_2025.md)** - 完全な言語仕様(最新版)
|
||||
- **[📝 構文早見表](../../quick-reference/syntax-cheatsheet.md)** - よく使う構文のクイックリファレンス
|
||||
|
||||
## 📁 このディレクトリの内容
|
||||
|
||||
- `design-philosophy.md` - Nyashの設計哲学
|
||||
- `override-delegation-syntax.md` - オーバーライド・デリゲーション構文の詳細
|
||||
- `portability-contract.md` - 移植性に関する契約
|
||||
|
||||
## 📦 アーカイブ
|
||||
|
||||
古い言語仕様ドキュメントは以下に移動しました:
|
||||
- `docs/archive/language-specs/`
|
||||
|
||||
---
|
||||
|
||||
**注意**: 言語仕様に関する最新情報は必ず [LANGUAGE_REFERENCE_2025.md](../../../../reference/language/LANGUAGE_REFERENCE_2025.md) を参照してください。
|
||||
@ -1,295 +0,0 @@
|
||||
# 🤝 Nyash Portability Contract v0
|
||||
|
||||
*ChatGPT5アドバイス・全バックエンド互換性保証仕様*
|
||||
|
||||
## 🎯 目的
|
||||
|
||||
**「nyash --target= interp / vm / wasm / aot-rust / jit-cranelift」で同一プログラムが同一結果を保証**
|
||||
|
||||
全バックエンドでNyashプログラムが確実に動作し、最適化レベルに関係なく**決定的で予測可能な実行**を実現。
|
||||
|
||||
## 🔧 **Contract v0 仕様**
|
||||
|
||||
### 1️⃣ **決定的破棄(Deterministic Finalization)**
|
||||
|
||||
#### **強参照のみ伝播保証**
|
||||
```rust
|
||||
// ✅ 保証される動作
|
||||
box Parent {
|
||||
child_strong: ChildBox // 強参照→破棄連鎖
|
||||
}
|
||||
|
||||
parent.fini() // 必ずchild_strong.fini()も呼ばれる
|
||||
```
|
||||
|
||||
#### **破棄順序の決定性**
|
||||
```nyash
|
||||
// 破棄順序: 最新→最古(スタック順序)
|
||||
box Child from Parent {
|
||||
init { data }
|
||||
pack() {
|
||||
from Parent.pack() // 1. Parent初期化
|
||||
me.data = "child" // 2. Child初期化
|
||||
}
|
||||
// fini順序: 2→1(逆順破棄)
|
||||
}
|
||||
```
|
||||
|
||||
#### **例外安全性**
|
||||
```rust
|
||||
pub enum FinalizationGuarantee {
|
||||
AlwaysExecuted, // fini()は例外時も必ず実行
|
||||
NoDoubleDestroy, // 同一オブジェクトの二重破棄禁止
|
||||
OrderPreserved, // 初期化と逆順での破棄保証
|
||||
}
|
||||
```
|
||||
|
||||
### 2️⃣ **weak参照の非伝播+生存チェック**
|
||||
|
||||
#### **非伝播保証**
|
||||
```nyash
|
||||
box Parent {
|
||||
init { child_weak }
|
||||
|
||||
pack() {
|
||||
local child = new Child()
|
||||
me.child_weak = weak(child) // weak参照生成
|
||||
// child がfini()されても Parent は影響なし
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **生存チェック必須**
|
||||
```mir
|
||||
// MIR レベルでの生存チェック
|
||||
%alive = weak_load %weak_ref
|
||||
br %alive -> %use_bb, %null_bb
|
||||
|
||||
%use_bb:
|
||||
// weak参照が有効な場合の処理
|
||||
%value = /* weak_refの値使用 */
|
||||
jmp %continue_bb
|
||||
|
||||
%null_bb:
|
||||
// weak参照が無効な場合の処理
|
||||
%value = const null
|
||||
jmp %continue_bb
|
||||
|
||||
%continue_bb:
|
||||
// 合流地点(Phi必須)
|
||||
%result = phi [%value from %use_bb, %value from %null_bb]
|
||||
```
|
||||
|
||||
#### **自動null化契約**
|
||||
```rust
|
||||
pub struct WeakContract {
|
||||
auto_nullification: true, // 参照先fini()時に自動null
|
||||
no_dangling_pointers: true, // ダングリングポインタ禁止
|
||||
thread_safe_access: true, // マルチスレッド安全アクセス
|
||||
}
|
||||
```
|
||||
|
||||
### 3️⃣ **Effect意味論(最適化可能性)**
|
||||
|
||||
#### **Effect分類契約**
|
||||
```rust
|
||||
pub enum EffectLevel {
|
||||
Pure, // 副作用なし→並び替え・除去・重複実行可能
|
||||
Mut, // メモリ変更→順序保証必要・並列化制限
|
||||
Io, // I/O操作→実行順序厳密保証・キャッシュ禁止
|
||||
Bus, // 分散通信→elision対象・ネットワーク最適化可能
|
||||
}
|
||||
```
|
||||
|
||||
#### **最適化契約**
|
||||
```mir
|
||||
// Pure関数→最適化可能
|
||||
%result1 = call @pure_function(%arg) effects=[PURE]
|
||||
%result2 = call @pure_function(%arg) effects=[PURE]
|
||||
// → 最適化: %result2 = copy %result1
|
||||
|
||||
// Mut操作→順序保証
|
||||
store %value1 -> %ptr effects=[MUT]
|
||||
store %value2 -> %ptr effects=[MUT]
|
||||
// → 順序維持必須
|
||||
|
||||
// Bus操作→elision対象
|
||||
send %bus, %message effects=[BUS]
|
||||
// → ネットワーク最適化・バッチ化可能
|
||||
```
|
||||
|
||||
### 4️⃣ **Bus-elision基盤契約**
|
||||
|
||||
#### **elision ON/OFF同一結果保証**
|
||||
```bash
|
||||
# 最適化ON→高速実行
|
||||
nyash --elide-bus --target wasm program.nyash
|
||||
|
||||
# 最適化OFF→完全分散実行
|
||||
nyash --no-elide-bus --target vm program.nyash
|
||||
|
||||
# 結果は必ず同一(契約保証)
|
||||
```
|
||||
|
||||
#### **Bus操作の意味保証**
|
||||
```mir
|
||||
// Bus送信の意味論
|
||||
send %bus, %message effects=[BUS] {
|
||||
// elision OFF: 実際のネットワーク送信
|
||||
// elision ON: ローカル最適化(結果同一)
|
||||
}
|
||||
|
||||
// Bus受信の意味論
|
||||
%msg = recv %bus effects=[BUS] {
|
||||
// elision OFF: ネットワーク受信待ち
|
||||
// elision ON: ローカル値返却(結果同一)
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 **Contract検証システム**
|
||||
|
||||
### **互換テストスイート**
|
||||
```rust
|
||||
// tests/portability_contract_tests.rs
|
||||
#[test]
|
||||
fn test_deterministic_finalization() {
|
||||
let program = "/* fini順序テスト */";
|
||||
|
||||
let interp_result = run_interpreter(program);
|
||||
let vm_result = run_vm(program);
|
||||
let wasm_result = run_wasm(program);
|
||||
|
||||
// 破棄順序・タイミングが全バックエンドで同一
|
||||
assert_eq!(interp_result.finalization_order, vm_result.finalization_order);
|
||||
assert_eq!(vm_result.finalization_order, wasm_result.finalization_order);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_reference_semantics() {
|
||||
let program = "/* weak参照テスト */";
|
||||
|
||||
// 生存チェック・null化が全バックエンドで同一動作
|
||||
let results = run_all_backends(program);
|
||||
assert_all_equal(results.map(|r| r.weak_behavior));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_effect_optimization_equivalence() {
|
||||
let program = "/* Effect最適化テスト */";
|
||||
|
||||
// PURE関数の最適化結果が同一
|
||||
let optimized = run_with_optimization(program);
|
||||
let reference = run_without_optimization(program);
|
||||
assert_eq!(optimized.output, reference.output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bus_elision_equivalence() {
|
||||
let program = "/* Bus通信テスト */";
|
||||
|
||||
let elision_on = run_with_flag(program, "--elide-bus");
|
||||
let elision_off = run_with_flag(program, "--no-elide-bus");
|
||||
|
||||
// Bus最適化ON/OFFで結果同一
|
||||
assert_eq!(elision_on.output, elision_off.output);
|
||||
}
|
||||
```
|
||||
|
||||
### **Golden Dump検証**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# scripts/verify_portability_contract.sh
|
||||
|
||||
echo "🧪 Portability Contract v0 検証中..."
|
||||
|
||||
# 1. MIR出力一致検証
|
||||
nyash --dump-mir test.nyash > golden.mir
|
||||
nyash --dump-mir test.nyash > current.mir
|
||||
if ! diff golden.mir current.mir; then
|
||||
echo "❌ MIR回帰エラー検出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. 全バックエンド同一出力
|
||||
declare -a backends=("interp" "vm" "wasm")
|
||||
for backend in "${backends[@]}"; do
|
||||
nyash --target $backend test.nyash > ${backend}.out
|
||||
done
|
||||
|
||||
# 出力一致確認
|
||||
if diff interp.out vm.out && diff vm.out wasm.out; then
|
||||
echo "✅ 全バックエンド出力一致"
|
||||
else
|
||||
echo "❌ バックエンド出力差異検出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. Bus-elision検証
|
||||
nyash --elide-bus test.nyash > elision_on.out
|
||||
nyash --no-elide-bus test.nyash > elision_off.out
|
||||
if diff elision_on.out elision_off.out; then
|
||||
echo "✅ Bus-elision同一結果"
|
||||
else
|
||||
echo "❌ Bus-elision結果差異"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🎉 Portability Contract v0 検証完了"
|
||||
```
|
||||
|
||||
## 📊 **Contract適合レベル**
|
||||
|
||||
### **Tier-0: 基本互換性**
|
||||
- [ ] **決定的破棄**: fini()順序がバックエンド間で同一
|
||||
- [ ] **weak非伝播**: weak参照が親破棄に影響しない
|
||||
- [ ] **基本Effect**: PURE/MUT/IO の意味論統一
|
||||
- [ ] **出力一致**: 同一プログラム→同一標準出力
|
||||
|
||||
### **Tier-1: 最適化互換性**
|
||||
- [ ] **PURE最適化**: 純粋関数の除去・移動がバックエンド間で同等
|
||||
- [ ] **weak生存チェック**: 全バックエンドで同一タイミング
|
||||
- [ ] **Bus-elision**: ON/OFF切り替えで結果同一
|
||||
- [ ] **性能予測**: 最適化レベル差が定量的
|
||||
|
||||
### **Tier-2: 高度互換性**
|
||||
- [ ] **メモリレイアウト**: Box構造がバックエンド間で互換
|
||||
- [ ] **エラー処理**: 例外・パニックが同一動作
|
||||
- [ ] **並行性**: Future/awaitが同一意味論
|
||||
- [ ] **デバッグ**: スタックトレース・診断情報が同等
|
||||
|
||||
## ⚡ **実装優先順位**
|
||||
|
||||
### **Phase 8.4(今すぐ)**
|
||||
1. **Tier-0契約実装**: 基本互換性確保
|
||||
2. **Golden dump自動化**: CI/CDで回帰検出
|
||||
3. **Bus命令設計**: elision基盤構築
|
||||
|
||||
### **Phase 8.5(短期)**
|
||||
1. **Tier-1契約実装**: 最適化互換性
|
||||
2. **性能ベンチマーク**: 契約準拠性測定
|
||||
3. **エラー契約**: 例外処理統一
|
||||
|
||||
### **Phase 9+(中長期)**
|
||||
1. **Tier-2契約実装**: 高度互換性
|
||||
2. **形式検証**: 契約の数学的証明
|
||||
3. **認証システム**: 契約適合認定
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **期待効果**
|
||||
|
||||
### **開発者体験**
|
||||
- **予測可能性**: どのバックエンドでも同一動作保証
|
||||
- **デバッグ容易性**: バックエンド切り替えで問題切り分け
|
||||
- **最適化信頼性**: 高速化しても結果不変保証
|
||||
|
||||
### **Nyash言語価値**
|
||||
- **差別化**: 「全バックエンド互換」言語として独自性
|
||||
- **信頼性**: エンタープライズ採用の技術的根拠
|
||||
- **拡張性**: 新バックエンド追加時の品質保証
|
||||
|
||||
---
|
||||
|
||||
*最終更新: 2025-08-14 - ChatGPT5アドバイス完全実装*
|
||||
|
||||
*「Everything is Box」×「全バックエンド互換」= Nyashの技術的優位性*
|
||||
@ -1,52 +0,0 @@
|
||||
# JIT Events JSON (v0.1)
|
||||
|
||||
最小のイベントJSONスキーマ。観測の足場として、値は安定キーのみを出力します。
|
||||
|
||||
- 出力形態: 1行 = 1 JSON(JSONL)
|
||||
- 出力先: 標準出力 or `NYASH_JIT_EVENTS_PATH` で指定したファイル
|
||||
- phase分離:
|
||||
- compile: `phase: "lower"`(明示opt-in: `NYASH_JIT_EVENTS_COMPILE=1`)
|
||||
- runtime: `phase: "execute"`(既定ON可: `NYASH_JIT_EVENTS=1` または `NYASH_JIT_EVENTS_RUNTIME=1`)
|
||||
|
||||
## フィールド(必須)
|
||||
- kind: 文字列(例: "hostcall")
|
||||
- function: 文字列(現状は "<jit>" で固定)
|
||||
- phase: 文字列("lower" | "execute")
|
||||
- id: シンボル名(例: "nyash.map.get_hh")
|
||||
- decision: 文字列("allow" | "fallback")
|
||||
- reason: 文字列("sig_ok" | "receiver_not_param" | "policy_denied_mutating" | "sig_mismatch" など)
|
||||
- argc: 数値(観測引数数)
|
||||
- arg_types: 文字列配列(例: ["Handle","I64"])
|
||||
|
||||
任意フィールド(存在時のみ)
|
||||
- handle: 数値(JITハンドル)
|
||||
- ms: 数値(処理時間ミリ秒)
|
||||
|
||||
## 出力例
|
||||
|
||||
compile(lower):
|
||||
```json
|
||||
{"kind":"hostcall","function":"<jit>","id":"nyash.map.get_hh","decision":"allow","reason":"sig_ok","argc":2,"arg_types":["Handle","Handle"],"phase":"lower"}
|
||||
```
|
||||
|
||||
runtime(execute):
|
||||
```json
|
||||
{"kind":"hostcall","function":"<jit>","id":"nyash.array.push_h","decision":"fallback","reason":"policy_denied_mutating","argc":2,"arg_types":["Handle","I64"],"phase":"execute"}
|
||||
```
|
||||
|
||||
trap(execute 中の失敗):
|
||||
```json
|
||||
{"kind":"trap","function":"<jit>","reason":"jit_execute_failed","ms":0,"phase":"execute"}
|
||||
```
|
||||
|
||||
## 環境変数(抜粋)
|
||||
- NYASH_JIT_EVENTS=1: 既定のruntime出力
|
||||
- NYASH_JIT_EVENTS_COMPILE=1: compile(lower)出力
|
||||
- NYASH_JIT_EVENTS_RUNTIME=1: runtime出力
|
||||
- NYASH_JIT_EVENTS_PATH=path.jsonl: ファイルに追記
|
||||
- NYASH_JIT_THRESHOLD(未設定時): 観測ONで自動的に1が補われます(Runner/DebugConfigBoxが補助)
|
||||
|
||||
## 推奨の最小運用
|
||||
- 現象確認: `NYASH_JIT_EVENTS=1`(runtimeのみ)
|
||||
- 解析時のみcompile出力: `NYASH_JIT_EVENTS_COMPILE=1 NYASH_JIT_EVENTS_PATH=events.jsonl`
|
||||
- HostCall系の例では `NYASH_JIT_HOSTCALL=1` を明示
|
||||
@ -1,43 +0,0 @@
|
||||
# MIR Core (~15) Coverage Checklist
|
||||
|
||||
Goal: Verify that the core MIR set executes correctly across VM and JIT (exe), then proceed to LLVM.
|
||||
|
||||
Target instructions (representative core):
|
||||
- Basics: Const, UnaryOp, BinOp, Compare, TypeOp
|
||||
- Memory: Load, Store
|
||||
- Control: Branch, Jump, Return, Phi
|
||||
- Box: NewBox, BoxCall, PluginInvoke
|
||||
- Arrays: ArrayGet, ArraySet
|
||||
- External: ExternCall
|
||||
|
||||
How to verify
|
||||
- VM path
|
||||
- Run representative examples or unit snippets via `--backend vm`.
|
||||
- Enable VM stats for visibility: `NYASH_VM_STATS=1`
|
||||
|
||||
- JIT (compiler-only, exe emission where applicable)
|
||||
- Enable JIT compile path and hostcall: `NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 NYASH_JIT_HOSTCALL=1`
|
||||
- For PHI minimal path tests: `NYASH_JIT_PHI_MIN=1`
|
||||
- Optional DOT/trace: `NYASH_JIT_DUMP=1` and/or `NYASH_JIT_EVENTS_COMPILE=1`
|
||||
|
||||
Quick smoke
|
||||
- Build: `cargo build --release --features cranelift-jit`
|
||||
- Run: `tools/mir15_smoke.sh release`
|
||||
- Policy: Core-1 is required green; hostcall-based cases are optional (fallback allowed).
|
||||
|
||||
Suggested minimal scenarios
|
||||
- Const/Return: function returns 0/1/42.
|
||||
- BinOp/Compare: arithmetic and boolean conditions.
|
||||
- Branch/Jump/Phi: single-diamond if/else with merging value.
|
||||
- Load/Store: local slot store → load (VM) and JIT local slots (lower/core) coverage.
|
||||
- TypeOp: `is`/`as` via builder emits TypeOp.
|
||||
- NewBox/BoxCall: call basic methods (e.g., StringBox.length, IntegerBox.get via PluginInvoke where applicable).
|
||||
- PluginInvoke/by-name: `nyash.handle.of` + invoke name path.
|
||||
- Arrays: len/get/set/push hostcalls (JIT: handle-based externs wired).
|
||||
- ExternCall: `env.console.log`, `env.debug.trace`, `env.runtime.checkpoint`.
|
||||
|
||||
Notes
|
||||
- Debug/Safepoint/Future/Await are rewritable via env toggles; core stays focused on the above.
|
||||
- JIT direct path is read-only; mutating ops should fallback or be whitelisted accordingly.
|
||||
|
||||
Once coverage is green on VM and JIT, proceed to LLVM feature work (inkwell-backed) following docs in execution-backends.
|
||||
@ -1,167 +0,0 @@
|
||||
# Nyash Plugin System Documentation
|
||||
|
||||
## 🎯 Quick Start
|
||||
|
||||
**For new developers**: Start with [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md)
|
||||
|
||||
## 📚 Documentation Index
|
||||
|
||||
### 🟢 **Current & Accurate**
|
||||
- **[bid-ffi-v1-actual-specification.md](./bid-ffi-v1-actual-specification.md)** - **主要仕様書**
|
||||
- 実際に動作している実装をベースとした正確な仕様
|
||||
- FileBoxプラグインで実証済み
|
||||
- プラグイン開発者はここから始める
|
||||
|
||||
- **[../architecture/dynamic-plugin-flow.md](../architecture/dynamic-plugin-flow.md)** - **動的プラグインシステムの全体フロー** 🆕
|
||||
- MIR→VM→Registry→プラグインの動的解決フロー
|
||||
- コンパイル時決め打ちなし、実行時動的判定の仕組み
|
||||
- nyash.tomlによる透過的な切り替え
|
||||
|
||||
- **[vm-plugin-integration.md](./vm-plugin-integration.md)** - **VM統合仕様書** 🆕
|
||||
- VMバックエンドとプラグインシステムの統合
|
||||
- BoxRef型による統一アーキテクチャ
|
||||
- パフォーマンス最適化とエラーハンドリング
|
||||
|
||||
- **[plugin-tester.md](./plugin-tester.md)** - プラグイン診断ツール
|
||||
- プラグインの動作確認とデバッグに使用
|
||||
- `tools/plugin-tester`ツールの使用方法
|
||||
|
||||
- **[plugin_lifecycle.md](./plugin_lifecycle.md)** - ライフサイクル/RAII/シングルトン/ログ
|
||||
- 共有ハンドル、scope終了時の扱い、`shutdown_plugins_v2()` の動作
|
||||
- NetPlugin(HTTP/TCP)の並列E2E時の注意点
|
||||
|
||||
- **[net-plugin.md](./net-plugin.md)** - Netプラグイン(HTTP/TCP PoC)
|
||||
- GET/POST、ヘッダ、Content-Length、環境変数によるログ
|
||||
|
||||
- **[returns-result.md](./returns-result.md)** - 可選のResultBox正規化
|
||||
- `returns_result = true` で成功/失敗を `Ok/Err` に統一(段階導入推奨)
|
||||
|
||||
### ⚙️ 戻り値のResult化(B案サポート)
|
||||
- `nyash.toml` のメソッド定義に `returns_result = true` を付けると、
|
||||
- 成功: `Ok(value)` の `ResultBox` に包んで返す
|
||||
- 失敗(BID負エラー): `Err(ErrorBox(message))` を返す(例外にはしない)
|
||||
|
||||
```toml
|
||||
[libraries."libnyash_example.so".ExampleBox.methods]
|
||||
dangerousOp = { method_id = 10, returns_result = true }
|
||||
```
|
||||
|
||||
未指定の場合は従来通り(成功=生値、失敗=例外として伝播)。
|
||||
|
||||
- **[filebox-bid-mapping.md](./filebox-bid-mapping.md)** - 参考資料
|
||||
- FileBox APIとプラグイン実装の対応表
|
||||
- API設計の参考として有用
|
||||
|
||||
### 🔄 **Migration & Reference**
|
||||
- **[migration-guide.md](./migration-guide.md)** - 移行ガイド
|
||||
- 古いドキュメントから現在の実装への移行方法
|
||||
- ドキュメント状況の整理
|
||||
|
||||
### ⚠️ **Deprecated - 非推奨**
|
||||
- **[ffi-abi-specification.md](./ffi-abi-specification.md)** - ❌ 理想案、未実装
|
||||
- **[plugin-system.md](./plugin-system.md)** - ❌ 将来構想
|
||||
- **[nyash-toml-v2-spec.md](./nyash-toml-v2-spec.md)** - ⚠️ 部分的に古い
|
||||
|
||||
## 🚀 For Plugin Developers
|
||||
|
||||
### 1. **Read the Specification**
|
||||
```bash
|
||||
# 主要仕様書を読む
|
||||
cat docs/説明書/reference/plugin-system/bid-ffi-v1-actual-specification.md
|
||||
```
|
||||
|
||||
### 2. **Study Working Example**
|
||||
```bash
|
||||
# FileBoxプラグインを参考にする
|
||||
cd plugins/nyash-filebox-plugin
|
||||
cat src/lib.rs
|
||||
```
|
||||
|
||||
### 3. **Configure Your Plugin**
|
||||
```bash
|
||||
# 新スタイル(推奨): 中央=nyash.toml(レジストリ最小) + 各プラグイン=nyash_box.toml(仕様書)
|
||||
cat nyash.toml
|
||||
cat plugins/<your-plugin>/nyash_box.toml
|
||||
```
|
||||
|
||||
中央の `nyash.toml` 例(抜粋)
|
||||
```toml
|
||||
[plugins]
|
||||
"libnyash_filebox_plugin" = "./plugins/nyash-filebox-plugin"
|
||||
|
||||
[plugin_paths]
|
||||
search_paths = ["./plugins/*/target/release", "./plugins/*/target/debug"]
|
||||
|
||||
[box_types]
|
||||
FileBox = 6
|
||||
```
|
||||
|
||||
各プラグインの `nyash_box.toml` 例(抜粋)
|
||||
```toml
|
||||
[box]
|
||||
name = "FileBox"
|
||||
version = "1.0.0"
|
||||
description = "File I/O operations Box"
|
||||
|
||||
[provides]
|
||||
boxes = ["FileBox"]
|
||||
|
||||
[FileBox]
|
||||
type_id = 6
|
||||
|
||||
[FileBox.methods.open]
|
||||
id = 1
|
||||
args = [ { name = "path", type = "string" }, { name = "mode", type = "string", default = "r" } ]
|
||||
returns = { type = "void", error = "string" }
|
||||
```
|
||||
|
||||
ロード時は `nyash_box.toml` が優先参照され、OS差(.so/.dll/.dylib、libプリフィックス)は自動吸収されます。従来の `[libraries]` 設定も当面は後方互換で有効です。
|
||||
|
||||
### 4. **Test Your Plugin**
|
||||
```bash
|
||||
# プラグインテスターで確認
|
||||
cd tools/plugin-tester
|
||||
cargo build --release
|
||||
./target/release/plugin-tester check path/to/your/plugin.so
|
||||
```
|
||||
|
||||
### 5. **nyash_box.toml テンプレ & スモーク** 🆕
|
||||
- テンプレート: `docs/reference/plugin-system/nyash_box.toml.template`
|
||||
- スモーク実行(VM・厳格チェックON):
|
||||
```bash
|
||||
bash tools/smoke_plugins.sh
|
||||
```
|
||||
- 実行内容: Python デモと Integer デモを `NYASH_PLUGIN_STRICT=1` で起動し、nyash_box.toml 経路のロードと実行を確認
|
||||
- 事前条件: `cargo build --release --features cranelift-jit` 済み、各プラグインも release ビルド済み
|
||||
|
||||
### 6. **プラグイン優先(ビルトイン上書き)設定** 🆕
|
||||
- 既定では、ビルトインの実装が優先されます(安全第一)。
|
||||
- プラグインで置き換えたい型(ConsoleBox など)がある場合は環境変数で上書き可能:
|
||||
```bash
|
||||
export NYASH_USE_PLUGIN_BUILTINS=1
|
||||
export NYASH_PLUGIN_OVERRIDE_TYPES="ArrayBox,MapBox,ConsoleBox"
|
||||
```
|
||||
- 上記により、`new ConsoleBox()` などの生成がプラグイン経路に切替わります。
|
||||
- 後方互換のため `[libraries]` にも対象プラグインを登録しておくと、解決の一貫性が高まります。
|
||||
|
||||
## 🔧 For Nyash Core Developers
|
||||
|
||||
### Implementation Files
|
||||
- **[plugin_loader_v2.rs](../../../../src/runtime/plugin_loader_v2.rs)** - プラグインローダー実装
|
||||
- **[nyash_toml_v2.rs](../../../../src/config/nyash_toml_v2.rs)** - 設定パーサー
|
||||
- **[tlv.rs](../../../../src/bid/tlv.rs)** - TLVエンコーダー/デコーダー
|
||||
|
||||
### Next Steps
|
||||
- **Phase 3**: MIR ExternCall → plugin system 接続実装
|
||||
- **Future**: HTTP系ボックスのプラグイン化
|
||||
|
||||
## 📞 Support & Issues
|
||||
|
||||
- **Working Examples**: `plugins/nyash-filebox-plugin/`
|
||||
- **Issues**: Report at [GitHub Issues](https://github.com/moe-charm/nyash/issues)
|
||||
- **Configuration**: `nyash.toml` in project root
|
||||
|
||||
---
|
||||
|
||||
**Status**: Phase 2 Documentation Reorganization - Completed
|
||||
**Last Updated**: 2025-08-20
|
||||
@ -1,626 +0,0 @@
|
||||
# Box FFI/ABI v0 (BID-1 Enhanced Edition)
|
||||
|
||||
> ⚠️ **DEPRECATED - 理想案、未実装**
|
||||
>
|
||||
> この文書は将来の理想的なプラグインシステム設計案です。
|
||||
> **現在の実装とは異なります。**
|
||||
>
|
||||
> **実際に動作している仕様については、以下を参照してください:**
|
||||
> - [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md) - 現在動作中の仕様
|
||||
> - [nyash.toml設定例](../../../../nyash.toml) - 実際の設定形式
|
||||
> - [plugin_loader_v2.rs](../../../../src/runtime/plugin_loader_v2.rs) - 実装詳細
|
||||
|
||||
Purpose
|
||||
- Define a language-agnostic ABI to call external libraries as Boxes.
|
||||
- Serve as a single source of truth for MIR ExternCall, WASM RuntimeImports, VM stubs, and future language codegens (TS/Python/Rust/LLVM IR).
|
||||
- Support Everything is Box philosophy with efficient Handle design.
|
||||
|
||||
Design Goals
|
||||
- Simple first: UTF-8 strings as (ptr,len), i32 for small integers, 32-bit linear memory alignment friendly.
|
||||
- Deterministic and portable across WASM/VM/native backends.
|
||||
- Align with MIR effect system (pure/mut/io/control) to preserve optimization safety.
|
||||
- Efficient Handle design for Box instances (type_id + instance_id).
|
||||
|
||||
Core Types
|
||||
- i32, i64, f32, f64, bool (0|1)
|
||||
- string: UTF-8 in linear memory as (ptr: usize, len: usize)
|
||||
- bytes: Binary data as (ptr: usize, len: usize)
|
||||
- handle: Efficient Box handle as {type_id: u32, instance_id: u32} or packed u64
|
||||
- array(T): (ptr: usize, len: usize)
|
||||
- void (no return value)
|
||||
|
||||
Memory & Alignment
|
||||
- All pointers are platform-dependent (usize): 32-bit in WASM MVP, 64-bit on native x86-64.
|
||||
- Alignment: 8-byte boundary for all structures.
|
||||
- Strings/arrays must be contiguous in linear memory; no NUL terminator required (len is authoritative).
|
||||
- Box layout examples for built-ins (for backends that materialize Boxes in memory):
|
||||
- Header: [type_id:i32][ref_count:i32][field_count:i32]
|
||||
- StringBox: header + [data_ptr:usize][length:usize]
|
||||
|
||||
Handle Design (BID-1 Enhancement)
|
||||
- Handle represents a Box instance with two components:
|
||||
- type_id: u32 (1=StringBox, 6=FileBox, 7=FutureBox, 8=P2PBox, etc.)
|
||||
- instance_id: u32 (unique instance identifier)
|
||||
- Can be passed as single u64 (type_id << 32 | instance_id) or struct
|
||||
|
||||
Naming & Resolution
|
||||
- Interface namespace: `env.console`, `env.canvas`, `nyash.file`, etc.
|
||||
- Method: `log`, `fillRect`, `fillText`, `open`, `read`, `write`, `close`.
|
||||
- Fully-qualified name: `env.console.log`, `env.canvas.fillRect`, `nyash.file.open`.
|
||||
|
||||
Calling Convention (BID-1)
|
||||
- Single entry point: `nyash_plugin_invoke`
|
||||
- Arguments passed as BID-1 TLV format
|
||||
- Return values in BID-1 TLV format
|
||||
- Two-call pattern for dynamic results:
|
||||
1. First call with null result buffer to get size
|
||||
2. Second call with allocated buffer to get data
|
||||
|
||||
Error Model (BID-1)
|
||||
- Standardized error codes:
|
||||
- NYB_SUCCESS (0): Operation successful
|
||||
- NYB_E_SHORT_BUFFER (-1): Buffer too small
|
||||
- NYB_E_INVALID_TYPE (-2): Invalid type ID
|
||||
- NYB_E_INVALID_METHOD (-3): Invalid method ID
|
||||
- NYB_E_INVALID_ARGS (-4): Invalid arguments
|
||||
- NYB_E_PLUGIN_ERROR (-5): Plugin internal error
|
||||
|
||||
Effects
|
||||
- Each BID method declares one of: pure | mut | io | control.
|
||||
- Optimizer/verifier rules:
|
||||
- pure: reordering permitted, memoization possible
|
||||
- mut: preserve order w.r.t same resource
|
||||
- io: preserve program order strictly
|
||||
- control: affects CFG; handled as terminators or dedicated ops
|
||||
|
||||
BID-1 TLV Format
|
||||
```c
|
||||
// BID-1 TLV specification - unified format for arguments and results
|
||||
struct BidTLV {
|
||||
u16 version; // 1 (BID-1)
|
||||
u16 argc; // argument count
|
||||
// followed by TLVEntry array
|
||||
};
|
||||
|
||||
struct TLVEntry {
|
||||
u8 tag; // type tag
|
||||
u8 reserved; // future use (0)
|
||||
u16 size; // payload size
|
||||
// followed by payload data
|
||||
};
|
||||
|
||||
// Tag definitions (Phase 1)
|
||||
#define BID_TAG_BOOL 1 // payload: 1 byte (0/1)
|
||||
#define BID_TAG_I32 2 // payload: 4 bytes (little-endian)
|
||||
#define BID_TAG_I64 3 // payload: 8 bytes (little-endian)
|
||||
#define BID_TAG_F32 4 // payload: 4 bytes (IEEE 754)
|
||||
#define BID_TAG_F64 5 // payload: 8 bytes (IEEE 754)
|
||||
#define BID_TAG_STRING 6 // payload: UTF-8 bytes
|
||||
#define BID_TAG_BYTES 7 // payload: binary data
|
||||
#define BID_TAG_HANDLE 8 // payload: 8 bytes (type_id + instance_id)
|
||||
|
||||
// Phase 2 reserved
|
||||
#define BID_TAG_RESULT 20 // Result<T,E>
|
||||
#define BID_TAG_OPTION 21 // Option<T>
|
||||
#define BID_TAG_ARRAY 22 // Array<T>
|
||||
```
|
||||
|
||||
Plugin API (BID-1)
|
||||
```c
|
||||
// src/bid/plugin_api.h - Plugin API complete version
|
||||
|
||||
// Host function table
|
||||
typedef struct {
|
||||
void* (*alloc)(size_t size); // Memory allocation
|
||||
void (*free)(void* ptr); // Memory deallocation
|
||||
void (*wake)(u32 future_id); // FutureBox wake
|
||||
void (*log)(const char* msg); // Log output
|
||||
} NyashHostVtable;
|
||||
|
||||
// Plugin information
|
||||
typedef struct {
|
||||
u32 type_id; // Box type ID
|
||||
const char* type_name; // "FileBox" etc.
|
||||
u32 method_count; // Method count
|
||||
const NyashMethodInfo* methods; // Method table
|
||||
} NyashPluginInfo;
|
||||
|
||||
typedef struct {
|
||||
u32 method_id; // Method ID
|
||||
const char* method_name; // "open", "read" etc.
|
||||
u32 signature_hash; // Type signature hash
|
||||
} NyashMethodInfo;
|
||||
|
||||
// Plugin API (required implementation)
|
||||
extern "C" {
|
||||
// Get ABI version
|
||||
u32 nyash_plugin_abi(void);
|
||||
|
||||
// Initialize (host integration & metadata registration)
|
||||
i32 nyash_plugin_init(const NyashHostVtable* host, NyashPluginInfo* info);
|
||||
|
||||
// Unified method invocation
|
||||
i32 nyash_plugin_invoke(
|
||||
u32 type_id, // Box type ID
|
||||
u32 method_id, // Method ID
|
||||
u32 instance_id, // Instance ID
|
||||
const u8* args, // BID-1 TLV arguments
|
||||
size_t args_len, // Arguments size
|
||||
u8* result, // BID-1 TLV result
|
||||
size_t* result_len // Result size (in/out)
|
||||
);
|
||||
|
||||
// Shutdown
|
||||
void nyash_plugin_shutdown(void);
|
||||
}
|
||||
```
|
||||
|
||||
BID (Box Interface Definition) — YAML
|
||||
```yaml
|
||||
version: 1 # BID-1 format
|
||||
interfaces:
|
||||
- name: env.console
|
||||
box: Console
|
||||
methods:
|
||||
- name: log
|
||||
params: [ {string: msg} ]
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: env.canvas
|
||||
box: Canvas
|
||||
methods:
|
||||
- name: fillRect
|
||||
params:
|
||||
- {string: canvas_id}
|
||||
- {i32: x}
|
||||
- {i32: y}
|
||||
- {i32: w}
|
||||
- {i32: h}
|
||||
- {string: color}
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: fillText
|
||||
params:
|
||||
- {string: canvas_id}
|
||||
- {string: text}
|
||||
- {i32: x}
|
||||
- {i32: y}
|
||||
- {string: font}
|
||||
- {string: color}
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: nyash.file
|
||||
box: FileBox
|
||||
type_id: 6
|
||||
methods:
|
||||
- name: open
|
||||
method_id: 1
|
||||
params:
|
||||
- {string: path}
|
||||
- {string: mode}
|
||||
returns: {handle: FileBox}
|
||||
effect: io
|
||||
|
||||
- name: read
|
||||
method_id: 2
|
||||
params:
|
||||
- {handle: handle}
|
||||
- {i32: size}
|
||||
returns: {bytes: data}
|
||||
effect: io
|
||||
|
||||
- name: write
|
||||
method_id: 3
|
||||
params:
|
||||
- {handle: handle}
|
||||
- {bytes: data}
|
||||
returns: {i32: written}
|
||||
effect: io
|
||||
|
||||
- name: close
|
||||
method_id: 4
|
||||
params:
|
||||
- {handle: handle}
|
||||
returns: void
|
||||
effect: io
|
||||
```
|
||||
|
||||
FileBox Plugin Example (BID-1)
|
||||
```c
|
||||
// plugins/nyash-file/src/lib.c
|
||||
|
||||
#include "nyash_plugin_api.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const NyashHostVtable* g_host = NULL;
|
||||
|
||||
// ABI version
|
||||
u32 nyash_plugin_abi(void) {
|
||||
return 1; // BID-1 support
|
||||
}
|
||||
|
||||
// Method table
|
||||
static const NyashMethodInfo FILE_METHODS[] = {
|
||||
{0, "birth", 0xBEEFCAFE}, // birth(path: string, mode: string) - Constructor
|
||||
{1, "open", 0x12345678}, // open(path: string, mode: string) -> Handle
|
||||
{2, "read", 0x87654321}, // read(handle: Handle, size: i32) -> Bytes
|
||||
{3, "write", 0x11223344}, // write(handle: Handle, data: Bytes) -> i32
|
||||
{4, "close", 0xABCDEF00}, // close(handle: Handle) -> Void
|
||||
{5, "fini", 0xDEADBEEF}, // fini() - Destructor
|
||||
};
|
||||
|
||||
// Initialize
|
||||
i32 nyash_plugin_init(const NyashHostVtable* host, NyashPluginInfo* info) {
|
||||
info->type_id = 6; // FileBox
|
||||
info->type_name = "FileBox";
|
||||
info->method_count = 4;
|
||||
info->methods = FILE_METHODS;
|
||||
|
||||
// Save host functions
|
||||
g_host = host;
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// Method execution
|
||||
i32 nyash_plugin_invoke(u32 type_id, u32 method_id, u32 instance_id,
|
||||
const u8* args, size_t args_len,
|
||||
u8* result, size_t* result_len) {
|
||||
if (type_id != 6) return NYB_E_INVALID_TYPE;
|
||||
|
||||
switch (method_id) {
|
||||
case 1: return file_open(args, args_len, result, result_len);
|
||||
case 2: return file_read(instance_id, args, args_len, result, result_len);
|
||||
case 3: return file_write(instance_id, args, args_len, result, result_len);
|
||||
case 4: return file_close(instance_id, args, args_len, result, result_len);
|
||||
default: return NYB_E_INVALID_METHOD;
|
||||
}
|
||||
}
|
||||
|
||||
// File open implementation
|
||||
static i32 file_open(const u8* args, size_t args_len,
|
||||
u8* result, size_t* result_len) {
|
||||
// BID-1 TLV parsing
|
||||
BidTLV* tlv = (BidTLV*)args;
|
||||
if (tlv->version != 1 || tlv->argc != 2) {
|
||||
return NYB_E_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// Extract arguments: path, mode
|
||||
const char* path = extract_string_arg(tlv, 0);
|
||||
const char* mode = extract_string_arg(tlv, 1);
|
||||
|
||||
// Open file
|
||||
FILE* fp = fopen(path, mode);
|
||||
if (!fp) return NYB_E_PLUGIN_ERROR;
|
||||
|
||||
// Generate handle
|
||||
u32 handle_id = register_file_handle(fp);
|
||||
|
||||
// BID-1 result creation
|
||||
if (!result) {
|
||||
*result_len = sizeof(BidTLV) + sizeof(TLVEntry) + 8; // Handle
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// Return Handle{type_id: 6, instance_id: handle_id} in TLV
|
||||
encode_handle_result(result, 6, handle_id);
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// birth implementation - Box constructor
|
||||
static i32 file_birth(u32 instance_id, const u8* args, size_t args_len,
|
||||
u8* result, size_t* result_len) {
|
||||
// Parse constructor arguments
|
||||
BidTLV* tlv = (BidTLV*)args;
|
||||
const char* path = extract_string_arg(tlv, 0);
|
||||
const char* mode = extract_string_arg(tlv, 1);
|
||||
|
||||
// Create instance
|
||||
FileInstance* instance = malloc(sizeof(FileInstance));
|
||||
instance->fp = fopen(path, mode);
|
||||
instance->buffer = NULL;
|
||||
|
||||
// Register instance
|
||||
register_instance(instance_id, instance);
|
||||
|
||||
// No return value for birth
|
||||
*result_len = 0;
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
// fini implementation - Box destructor
|
||||
static i32 file_fini(u32 instance_id) {
|
||||
FileInstance* instance = get_instance(instance_id);
|
||||
if (!instance) return NYB_E_INVALID_HANDLE;
|
||||
|
||||
// Free plugin-allocated memory
|
||||
if (instance->buffer) {
|
||||
free(instance->buffer);
|
||||
}
|
||||
|
||||
// Close file handle
|
||||
if (instance->fp) {
|
||||
fclose(instance->fp);
|
||||
}
|
||||
|
||||
// Free instance
|
||||
free(instance);
|
||||
unregister_instance(instance_id);
|
||||
|
||||
return NYB_SUCCESS;
|
||||
}
|
||||
|
||||
void nyash_plugin_shutdown(void) {
|
||||
// Cleanup all remaining instances
|
||||
cleanup_all_instances();
|
||||
}
|
||||
```
|
||||
|
||||
WASM Mapping (RuntimeImports)
|
||||
- Import examples:
|
||||
- `(import "env" "console_log" (func $console_log (param i32 i32)))` // (ptr,len)
|
||||
- `(import "env" "canvas_fillRect" (func $canvas_fillRect (param i32 i32 i32 i32 i32 i32)))`
|
||||
- `(import "env" "canvas_fillText" (func $canvas_fillText (param i32 i32 i32 i32 i32 i32 i32 i32)))` // two strings as (ptr,len) each
|
||||
- Host responsibilities:
|
||||
- Resolve strings from memory via `(ptr,len)` using TextDecoder('utf-8')
|
||||
- Map to DOM/Canvas/Console as appropriate
|
||||
- For plugins: use dlopen/dlsym to load and invoke nyash_plugin_* functions
|
||||
|
||||
WASM Mapping Rules (v0)
|
||||
- String marshalling: UTF-8 `(ptr:i32, len:i32)`; memory exported as `memory`.
|
||||
- Alignment: `ptr` 4-byte aligned is推奨(必須ではないが実装簡素化のため)。
|
||||
- Import naming: `env.<iface>_<method>` or nested `env` modules(実装都合でどちらでも可)。
|
||||
- 推奨: `env.console_log`, `env.canvas_fillRect`, `env.canvas_fillText`。
|
||||
- Argument order: 文字列は `(ptr,len)` を1引数扱いで連続配置。複数文字列はその都度 `(ptr,len)`。
|
||||
- Return: v0では`void`または整数のみ(複合戻りはout-paramに委譲)。
|
||||
- Memory growth: ホストは`memory.buffer`の再割当を考慮(必要に応じて毎回ビューを取り直す)。
|
||||
|
||||
RuntimeImportsとBIDの関係
|
||||
- `RuntimeImports` は ABI/BID をWASM向けに具体化した実装レイヤー(WASM専用の橋渡し)。
|
||||
- 生成方針: 将来的にBID(YAML/JSON)から`importObject`と`(import ...)`宣言を自動生成する。
|
||||
- 例(BID→WASM):
|
||||
- `env.console.log(string msg)` → `console_log(ptr:i32, len:i32)`
|
||||
- `env.canvas.fillRect(string canvasId, i32 x, i32 y, i32 w, i32 h, string color)`
|
||||
→ `canvas_fillRect(id_ptr, id_len, x, y, w, h, color_ptr, color_len)`
|
||||
|
||||
============================================================
|
||||
ABIの確定事項(BID-1, 日本語)
|
||||
============================================================
|
||||
|
||||
基本方針(BID-1)
|
||||
- 文字列は UTF-8 の `(ptr:usize, len:usize)` で受け渡す(NUL終端不要、内部NUL禁止)。
|
||||
- 配列/バイト列は `(ptr:usize, len:usize)` とする。
|
||||
- 数値は WASM/LLVM と親和性の高い素のプリミティブ(i32/i64/f32/f64)。
|
||||
- 真偽値は `i32` で 0=false, 1=true。
|
||||
- ポインタは `usize`(WASM MVPは32bit、ネイティブx86-64は64bit)。
|
||||
- エンディアンはリトルエンディアン(WASM/一般的なネイティブと一致)。
|
||||
- 呼出規約は単一エントリーポイント `nyash_plugin_invoke` + BID-1 TLV形式。
|
||||
- 戻り値はBID-1 TLV形式(2回呼び出しパターンでサイズ取得)。
|
||||
- メモリは `memory` をエクスポート(WASM)。ホスト側で管理。
|
||||
- 効果(effect)は BID に必須。pure は再順序化可、mut/io は順序保持。
|
||||
- 同期のみ(非同期は将来拡張)。
|
||||
- スレッド前提:シングルスレッド(Phase 1)。
|
||||
|
||||
メモリ管理戦略
|
||||
- 2回呼び出しパターン:
|
||||
1. result=NULLでサイズ取得
|
||||
2. ホストがallocateして結果取得
|
||||
- 文字列エンコーディング:UTF-8必須、内部NUL禁止
|
||||
- ハンドル再利用対策:generation追加で ABA問題回避(将来)
|
||||
|
||||
Boxライフサイクル管理
|
||||
- **birth/fini原則**:
|
||||
- method_id=0 は必ず`birth()`(コンストラクタ)
|
||||
- method_id=最大値 は必ず`fini()`(デストラクタ)
|
||||
- birthで割り当てたリソースはfiniで解放
|
||||
- **メモリ所有権**:
|
||||
- プラグインがmalloc()したメモリ → プラグインがfree()
|
||||
- ホストが提供したバッファ → ホストが管理
|
||||
- 引数として渡されたメモリ → read-onlyとして扱う
|
||||
- **インスタンス管理**:
|
||||
- instance_idはホストが発行・管理
|
||||
- プラグインは内部マップでinstance_id → 実装構造体を管理
|
||||
- nyash_plugin_shutdown()で全インスタンスをクリーンアップ
|
||||
|
||||
型と表現(BID-1)
|
||||
- `i32`: 32bit 符号付き整数
|
||||
- `i64`: 64bit 符号付き整数(WASMではJSブリッジ注意。Host側はBigInt等)
|
||||
- `f32/f64`: IEEE 754
|
||||
- `bool`: i32(0/1)
|
||||
- `string`: UTF-8 `(ptr:usize, len:usize)`
|
||||
- `bytes`: バイナリデータ `(ptr:usize, len:usize)`
|
||||
- `array<T>`: `(ptr:usize, len:usize)`
|
||||
- `handle`: Box参照 `{type_id:u32, instance_id:u32}` または packed u64
|
||||
- `void`: 戻り値なし
|
||||
|
||||
BidType Rust実装
|
||||
```rust
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum BidType {
|
||||
// プリミティブ(FFI境界で値渡し)
|
||||
Bool, I32, I64, F32, F64,
|
||||
String, Bytes,
|
||||
|
||||
// Handle設計
|
||||
Handle { type_id: u32, instance_id: u32 },
|
||||
|
||||
// メタ型
|
||||
Void,
|
||||
|
||||
// Phase 2予約
|
||||
Option(Box<BidType>),
|
||||
Result(Box<BidType>, Box<BidType>),
|
||||
Array(Box<BidType>),
|
||||
}
|
||||
```
|
||||
|
||||
アラインメント/境界
|
||||
- `ptr` は 8byte アライン必須(構造体の効率的アクセス)。
|
||||
- 範囲外アクセスは未定義ではなく「Hostが防ぐ/検証する」方針(将来、Verifier/境界チェック生成)。
|
||||
- プラットフォーム依存:
|
||||
- Linux x86-64: 8バイト境界
|
||||
- WASM MVP: 4バイト境界(互換性のため)
|
||||
|
||||
命名規約
|
||||
- `env.console.log`, `env.canvas.fillRect` のように `<namespace>.<iface>.<method>`。
|
||||
- WASM import 名は `env.console_log` 等の平坦化でも可(生成側で一貫)。
|
||||
- プラグイン関数名: `nyash_plugin_*` プレフィックス必須。
|
||||
|
||||
エラー/例外
|
||||
- BID-1標準エラーコード使用(NYB_*)。
|
||||
- 失敗は整数ステータスで返却。
|
||||
- 例外/シグナルは範囲外。
|
||||
|
||||
セキュリティ/権限(将来)
|
||||
- BID に必要権限(console/canvas/storage/net…)を記述。HostはAllowlistで制御(Phase 9.9)。
|
||||
|
||||
実装上の注意点
|
||||
- ハンドル再利用/ABA: generation追加で回避
|
||||
- スレッド前提: シングルスレッド前提を明記
|
||||
- メソッドID衝突: ビルド時固定で回避
|
||||
- エラー伝播: トランスポート/ドメインエラー分離
|
||||
- 文字列エンコード: UTF-8必須、内部NUL禁止
|
||||
|
||||
============================================================
|
||||
BIDサンプル(YAML, 日本語)
|
||||
============================================================
|
||||
|
||||
```yaml
|
||||
version: 0
|
||||
interfaces:
|
||||
- name: env.console
|
||||
box: Console
|
||||
methods:
|
||||
- name: log
|
||||
params: [ { string: msg } ]
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: env.canvas
|
||||
box: Canvas
|
||||
methods:
|
||||
- name: fillRect
|
||||
params:
|
||||
- { string: canvas_id }
|
||||
- { i32: x }
|
||||
- { i32: y }
|
||||
- { i32: w }
|
||||
- { i32: h }
|
||||
- { string: color }
|
||||
returns: void
|
||||
effect: io
|
||||
|
||||
- name: fillText
|
||||
params:
|
||||
- { string: canvas_id }
|
||||
- { string: text }
|
||||
- { i32: x }
|
||||
- { i32: y }
|
||||
- { string: font }
|
||||
- { string: color }
|
||||
returns: void
|
||||
effect: io
|
||||
```
|
||||
|
||||
ファイルとしてのサンプル(同等内容)
|
||||
- `docs/nyir/bid_samples/console.yaml`
|
||||
- `docs/nyir/bid_samples/canvas.yaml`
|
||||
|
||||
============================================================
|
||||
Host側 importObject サンプル(ブラウザ, 日本語)
|
||||
============================================================
|
||||
|
||||
```js
|
||||
// 文字列(ptr,len)の復元ヘルパ
|
||||
function utf8FromMemory(memory, ptr, len) {
|
||||
const u8 = new Uint8Array(memory.buffer, ptr, len);
|
||||
return new TextDecoder('utf-8').decode(u8);
|
||||
}
|
||||
|
||||
const importObject = {
|
||||
env: {
|
||||
print: (v) => console.log(v),
|
||||
print_str: (ptr, len) => {
|
||||
console.log(utf8FromMemory(wasmInstance.exports.memory, ptr, len));
|
||||
},
|
||||
console_log: (ptr, len) => {
|
||||
console.log(utf8FromMemory(wasmInstance.exports.memory, ptr, len));
|
||||
},
|
||||
canvas_fillRect: (idPtr, idLen, x, y, w, h, colorPtr, colorLen) => {
|
||||
const mem = wasmInstance.exports.memory;
|
||||
const id = utf8FromMemory(mem, idPtr, idLen);
|
||||
const color = utf8FromMemory(mem, colorPtr, colorLen);
|
||||
const cv = document.getElementById(id);
|
||||
if (!cv) return;
|
||||
const ctx = cv.getContext('2d');
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(x, y, w, h);
|
||||
},
|
||||
canvas_fillText: (idPtr, idLen, textPtr, textLen, x, y, fontPtr, fontLen, colorPtr, colorLen) => {
|
||||
const mem = wasmInstance.exports.memory;
|
||||
const id = utf8FromMemory(mem, idPtr, idLen);
|
||||
const text = utf8FromMemory(mem, textPtr, textLen);
|
||||
const font = utf8FromMemory(mem, fontPtr, fontLen);
|
||||
const color = utf8FromMemory(mem, colorPtr, colorLen);
|
||||
const cv = document.getElementById(id);
|
||||
if (!cv) return;
|
||||
const ctx = cv.getContext('2d');
|
||||
ctx.font = font;
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
============================================================
|
||||
ExternCall → WASM 呼び出しの例(日本語)
|
||||
============================================================
|
||||
|
||||
Nyash コード(概念):
|
||||
```
|
||||
console = new WebConsoleBox("output")
|
||||
console.log("Hello Nyash!")
|
||||
|
||||
canvas = new WebCanvasBox("game-canvas", 400, 300)
|
||||
canvas.fillRect(50, 50, 80, 60, "red")
|
||||
```
|
||||
|
||||
MIR(ExternCall化のイメージ):
|
||||
```
|
||||
ExternCall { iface: "env.console", method: "log", args: [ string("Hello Nyash!") ] }
|
||||
ExternCall { iface: "env.canvas", method: "fillRect", args: [ string("game-canvas"), 50, 50, 80, 60, string("red") ] }
|
||||
```
|
||||
|
||||
WASM import 呼び出し(概念):
|
||||
```
|
||||
call $console_log(msg_ptr, msg_len)
|
||||
call $canvas_fillRect(id_ptr, id_len, 50, 50, 80, 60, color_ptr, color_len)
|
||||
```
|
||||
|
||||
備考
|
||||
- 文字列定数は data segment に配置し、実行時に (ptr,len) を与える。
|
||||
- 動的文字列はランタイムでバッファ確保→(ptr,len) を渡す。
|
||||
|
||||
|
||||
VM Mapping (Stub v0)
|
||||
- Maintain a registry of externs by FQN (e.g., env.console.log) → function pointer.
|
||||
- Console: print to stdout; Canvas: log params or no-op.
|
||||
|
||||
LLVM IR Mapping (Preview)
|
||||
- Declare external functions with matching signatures (i32/i64/f32/f64/bool, i8* + i32 for strings).
|
||||
- Example: `declare void @env_console_log(i8* nocapture, i32)`
|
||||
- Strings allocated in data segment or heap; pass pointer + length.
|
||||
|
||||
Versioning
|
||||
- `version: 0` for the first public draft.
|
||||
- Backward-compatible extensions should add new methods/imports; breaking changes bump major.
|
||||
|
||||
Open Points (to validate post v0)
|
||||
- Boxref passing across FFI boundaries (opaque handles vs pointers).
|
||||
- Async externs and scheduling.
|
||||
- Error model harmonization (status vs result-box).
|
||||
@ -1,104 +0,0 @@
|
||||
# Plugin Documentation Migration Guide
|
||||
|
||||
## 🎯 概要
|
||||
|
||||
このガイドは、Nyashプラグインシステムの古いドキュメントから実際の実装に移行するためのものです。
|
||||
|
||||
## 📚 Documentation Status
|
||||
|
||||
### ✅ **Current Working Specification**
|
||||
- **[BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md)** - **RECOMMENDED**
|
||||
- 実際に動作している実装をベースとした正確な仕様
|
||||
- FileBoxプラグインで実証済み
|
||||
- `plugin_loader_v2.rs`の実装に基づく
|
||||
|
||||
### ⚠️ **Deprecated Documentation**
|
||||
- **[ffi-abi-specification.md](./ffi-abi-specification.md)** - ❌ DEPRECATED
|
||||
- 理想的な設計案だが未実装
|
||||
- MIR ExternCall設計が含まれているが、実際には使われていない
|
||||
|
||||
- **[plugin-system.md](./plugin-system.md)** - ❌ DEPRECATED
|
||||
- YAML DSLを使った将来構想
|
||||
- 現在の実装とは大きく異なる
|
||||
|
||||
- **[nyash-toml-v2-spec.md](./nyash-toml-v2-spec.md)** - ⚠️ PARTIALLY OUTDATED
|
||||
- 基本構造は正しいが、実際の形式と部分的に異なる
|
||||
|
||||
### ✅ **Still Accurate Documentation**
|
||||
- **[plugin-tester.md](./plugin-tester.md)** - ✅ CURRENT
|
||||
- プラグイン診断ツールの使用方法
|
||||
- 実際のツールと一致
|
||||
|
||||
- **[filebox-bid-mapping.md](./filebox-bid-mapping.md)** - ✅ USEFUL REFERENCE
|
||||
- FileBox APIとプラグイン実装の対応表
|
||||
- 開発時の参考資料として有効
|
||||
|
||||
## 🔄 Migration Steps
|
||||
|
||||
### For Plugin Developers
|
||||
|
||||
1. **Start with**: [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md)
|
||||
2. **Refer to**: [実際のnyash.toml](../../../../nyash.toml) for configuration format
|
||||
3. **Use**: [plugin-tester](../../../../tools/plugin-tester/) for testing
|
||||
4. **Study**: [FileBox plugin](../../../../plugins/nyash-filebox-plugin/) as reference implementation
|
||||
|
||||
### For Nyash Core Developers
|
||||
|
||||
1. **Phase 1**: ✅ COMPLETED - Documentation cleanup with deprecation notices
|
||||
2. **Phase 2**: ✅ COMPLETED - Accurate specification creation
|
||||
3. **Phase 3**: 🚧 TODO - MIR ExternCall implementation to connect with plugin system
|
||||
|
||||
## 🎯 Key Differences
|
||||
|
||||
### Old Documentation vs Reality
|
||||
|
||||
| Aspect | Old Docs | Reality |
|
||||
|--------|----------|---------|
|
||||
| Configuration | YAML DSL | TOML format |
|
||||
| API Design | Complex handle system | Simple TLV + method_id |
|
||||
| MIR Integration | Fully designed | Stub only |
|
||||
| ABI Version | Multiple versions | BID-FFI v1 only |
|
||||
|
||||
### Working Configuration Format
|
||||
|
||||
**Old (in deprecated docs)**:
|
||||
```yaml
|
||||
# filebox.plugin.yaml
|
||||
schema: 1
|
||||
apis:
|
||||
- sig: "FileBox::open(path: string) -> FileBox"
|
||||
```
|
||||
|
||||
**Current (actual)**:
|
||||
```toml
|
||||
[libraries."libnyash_filebox_plugin.so"]
|
||||
boxes = ["FileBox"]
|
||||
path = "./plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so"
|
||||
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
|
||||
birth = { method_id = 0 }
|
||||
open = { method_id = 1 }
|
||||
```
|
||||
|
||||
## 📞 FFI Interface
|
||||
|
||||
**Old (complex)**:
|
||||
- Multiple entry points
|
||||
- Complex handle management
|
||||
- Dynamic type discovery
|
||||
|
||||
**Current (simple)**:
|
||||
- Single entry point: `nyash_plugin_invoke`
|
||||
- Fixed TLV protocol
|
||||
- Static configuration in nyash.toml
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. ✅ **Documentation Cleanup**: Completed
|
||||
2. 🚧 **MIR Integration**: Implement ExternCall → plugin system connection
|
||||
3. 🔮 **Future**: Consider implementing some ideas from deprecated docs
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-08-20
|
||||
**Status**: Documentation reorganization Phase 2 completed
|
||||
@ -1,163 +0,0 @@
|
||||
# nyash.toml v2 仕様 - 究極のシンプル設計
|
||||
|
||||
> ⚠️ **PARTIALLY OUTDATED - 部分的に古い**
|
||||
>
|
||||
> この文書の基本構造は正しいですが、実際の形式と一部異なります。
|
||||
>
|
||||
> **最新の実際の設定形式については、以下を参照してください:**
|
||||
> - [BID-FFI v1 実装仕様書](./bid-ffi-v1-actual-specification.md) - 現在動作中の仕様
|
||||
> - [nyash.toml設定例](../../../../nyash.toml) - 実際の設定形式
|
||||
|
||||
## 🎯 概要
|
||||
**革命的シンプル設計**: nyash.toml中心アーキテクチャ + 最小限FFI
|
||||
|
||||
## 📝 nyash.toml v2形式
|
||||
|
||||
### マルチBox型プラグイン対応
|
||||
```toml
|
||||
[libraries]
|
||||
# ライブラリ定義(1つのプラグインで複数のBox型を提供可能)
|
||||
"libnyash_filebox_plugin.so" = {
|
||||
boxes = ["FileBox"],
|
||||
path = "./target/release/libnyash_filebox_plugin.so"
|
||||
}
|
||||
|
||||
# 将来の拡張例: 1つのプラグインで複数Box型
|
||||
"libnyash_network_plugin.so" = {
|
||||
boxes = ["SocketBox", "HTTPServerBox", "HTTPClientBox"],
|
||||
path = "./target/release/libnyash_network_plugin.so"
|
||||
}
|
||||
|
||||
# FileBoxの型情報定義
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox]
|
||||
type_id = 6
|
||||
abi_version = 1 # ABIバージョンもここに!
|
||||
|
||||
[libraries."libnyash_filebox_plugin.so".FileBox.methods]
|
||||
# method_id だけで十分(引数情報は実行時チェック)
|
||||
birth = { method_id = 0 }
|
||||
open = { method_id = 1 }
|
||||
read = { method_id = 2 }
|
||||
write = { method_id = 3 }
|
||||
close = { method_id = 4 }
|
||||
fini = { method_id = 4294967295 } # 0xFFFFFFFF
|
||||
```
|
||||
|
||||
## 🚀 究極のシンプルFFI
|
||||
|
||||
### プラグインが実装する関数
|
||||
|
||||
#### 必須: メソッド実行エントリーポイント
|
||||
```c
|
||||
// 唯一の必須関数 - すべてのメソッド呼び出しはここから
|
||||
extern "C" fn nyash_plugin_invoke(
|
||||
type_id: u32, // Box型ID(例: FileBox = 6)
|
||||
method_id: u32, // メソッドID(0=birth, 0xFFFFFFFF=fini)
|
||||
instance_id: u32, // インスタンスID(0=static/birth)
|
||||
args: *const u8, // TLVエンコード引数
|
||||
args_len: usize,
|
||||
result: *mut u8, // TLVエンコード結果バッファ
|
||||
result_len: *mut usize // [IN/OUT]バッファサイズ
|
||||
) -> i32 // 0=成功, 負=エラー
|
||||
```
|
||||
|
||||
#### オプション: グローバル初期化
|
||||
```c
|
||||
// プラグインロード時に1回だけ呼ばれる(実装は任意)
|
||||
extern "C" fn nyash_plugin_init() -> i32 {
|
||||
// グローバルリソースの初期化
|
||||
// 設定ファイルの読み込み
|
||||
// ログファイルのオープン
|
||||
// 0=成功, 負=エラー(プラグインは無効化される)
|
||||
}
|
||||
```
|
||||
|
||||
### 廃止されたAPI
|
||||
```c
|
||||
// ❌ これらは全部不要!
|
||||
nyash_plugin_abi_version() // → nyash.tomlのabi_version
|
||||
nyash_plugin_get_box_count() // → nyash.tomlのboxes配列
|
||||
nyash_plugin_get_box_info() // → nyash.tomlから取得
|
||||
NyashHostVtable // → 完全廃止!
|
||||
```
|
||||
|
||||
## 📊 設計原則
|
||||
|
||||
### 1. **Single Source of Truth**
|
||||
- すべてのメタ情報はnyash.tomlに集約
|
||||
- プラグインは純粋な実装のみ
|
||||
|
||||
### 2. **Zero Dependencies**
|
||||
- Host VTable廃止 = 依存関係ゼロ
|
||||
- プラグインは完全に独立
|
||||
|
||||
### 3. **シンプルなライフサイクル**
|
||||
- `init` (オプション): プラグインロード時の初期化
|
||||
- `birth` (method_id=0): インスタンス作成
|
||||
- 各種メソッド: インスタンス操作
|
||||
- `fini` (method_id=0xFFFFFFFF): 論理的終了
|
||||
|
||||
### 4. **ログ出力**
|
||||
```rust
|
||||
// プラグインは自己完結でログ出力
|
||||
eprintln!("[FileBox] Opened: {}", path); // 標準エラー
|
||||
|
||||
// または専用ログファイル
|
||||
let mut log = File::create("plugin_debug.log")?;
|
||||
writeln!(log, "{}: FileBox birth", chrono::Local::now())?;
|
||||
```
|
||||
|
||||
### 5. **init関数の活用例**
|
||||
```rust
|
||||
static mut LOG_FILE: Option<File> = None;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn nyash_plugin_init() -> i32 {
|
||||
// ログファイルを事前に開く
|
||||
match File::create("filebox.log") {
|
||||
Ok(f) => {
|
||||
unsafe { LOG_FILE = Some(f); }
|
||||
0 // 成功
|
||||
}
|
||||
Err(_) => -1 // エラー → プラグイン無効化
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 実装の流れ
|
||||
|
||||
### Phase 1: nyash.toml v2パーサー
|
||||
1. 新形式の読み込み
|
||||
2. Box型情報の抽出
|
||||
3. メソッドID管理
|
||||
|
||||
### Phase 2: プラグインローダー簡素化
|
||||
1. `nyash_plugin_init`(オプション)と`nyash_plugin_invoke`(必須)をロード
|
||||
2. nyash.tomlベースの型登録
|
||||
3. Host VTable関連コードを削除
|
||||
4. init関数が存在し失敗した場合はプラグインを無効化
|
||||
|
||||
### Phase 3: プラグイン側の対応
|
||||
1. abi/get_box_count/get_box_info関数を削除
|
||||
2. init関数は必要に応じて実装(グローバル初期化)
|
||||
3. invoke関数でメソッド処理
|
||||
4. ログ出力を自己完結に
|
||||
|
||||
## 🎉 メリット
|
||||
|
||||
1. **究極のシンプルさ** - 基本的にFFI関数1つ(initはオプション)
|
||||
2. **保守性向上** - 複雑な相互依存なし
|
||||
3. **テスト容易性** - モック不要
|
||||
4. **移植性** - どの言語でも実装可能
|
||||
5. **拡張性** - nyash.toml編集で機能追加
|
||||
6. **初期化保証** - init関数で早期エラー検出可能
|
||||
|
||||
## 🚨 注意事項
|
||||
|
||||
- プラグインのログは標準エラー出力かファイル出力で
|
||||
- メモリ管理はプラグイン内で完結
|
||||
- 非同期処理はNyash側でFutureBoxラップ
|
||||
|
||||
---
|
||||
|
||||
**革命完了**: これ以上シンプルにできない究極の設計!
|
||||
@ -1,66 +0,0 @@
|
||||
Nyash Plugin Tester - 開発者向けツールガイド
|
||||
|
||||
概要
|
||||
- 目的: Nyash用プラグイン(BID-FFI準拠)の基本健全性を素早く診断するツール。
|
||||
- 実装場所: `tools/plugin-tester`
|
||||
- 想定対象: C ABIで `nyash_plugin_*` をエクスポートする動的ライブラリ(.so/.dll/.dylib)
|
||||
|
||||
ビルド
|
||||
- コマンド: `cd tools/plugin-tester && cargo build --release`
|
||||
- 実行ファイル: `tools/plugin-tester/target/release/plugin-tester`
|
||||
|
||||
サブコマンド
|
||||
- `check <plugin>`: プラグインのロード、ABI確認、init呼び出し、型名・メソッド一覧の表示
|
||||
- `lifecycle <plugin>`: birth→fini の往復テスト(インスタンスIDを返すことを確認)
|
||||
- `io <plugin>`: FileBox向けE2E(open→write→close→open→read)テスト
|
||||
|
||||
使用例
|
||||
- チェック:
|
||||
- `tools/plugin-tester/target/release/plugin-tester check plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so`
|
||||
- 期待出力例:
|
||||
- `ABI version: 1`
|
||||
- `Plugin initialized`
|
||||
- `Box Type: FileBox (ID: 6)` と 6メソッド(birth/open/read/write/close/fini)の列挙
|
||||
- ライフサイクル:
|
||||
- `tools/plugin-tester/target/release/plugin-tester lifecycle <path-to-plugin>`
|
||||
- 期待出力例: `birth → instance_id=1`, `fini → instance 1 cleaned`
|
||||
- ファイルI/O:
|
||||
- `tools/plugin-tester/target/release/plugin-tester io <path-to-plugin>`
|
||||
- 期待出力例: `open(w)`, `write 25 bytes`, `open(r)`, `read 25 bytes → 'Hello from plugin-tester!'`
|
||||
|
||||
BID-FFI 前提(v1)
|
||||
- 必須シンボル: `nyash_plugin_abi`, `nyash_plugin_init`, `nyash_plugin_invoke`, `nyash_plugin_shutdown`
|
||||
- 返却コード: 0=成功, -1=ShortBuffer(2段階応答), -2=InvalidType, -3=InvalidMethod, -4=InvalidArgs, -5=PluginError, -8=InvalidHandle
|
||||
- 2段階応答: `result`がNULLまたは小さい場合は `*result_len` に必要サイズを設定し -1 を返す(副作用なし)
|
||||
|
||||
TLV(Type-Length-Value)概要(簡易)
|
||||
- ヘッダ: `u16 version (=1)`, `u16 argc`
|
||||
- エントリ: `u8 tag`, `u8 reserved(0)`, `u16 size`, `payload...`
|
||||
- 主なタグ: 1=Bool, 2=I32, 3=I64, 4=F32, 5=F64, 6=String, 7=Bytes, 8=Handle(u64), 9=Void
|
||||
- plugin-testerの `io` は最小限のTLVエンコード/デコードを内蔵
|
||||
|
||||
プラグイン例(FileBox)
|
||||
- 実装場所: `plugins/nyash-filebox-plugin`
|
||||
- メソッドID: 0=birth, 1=open, 2=read, 3=write, 4=close, 0xFFFF_FFFF=fini
|
||||
- `open(path, mode)`: 引数は TLV(String, String)、返り値は TLV(Void)
|
||||
- `read(size)`: 引数 TLV(I32)、返 TLV(Bytes)
|
||||
- `write(bytes)`: 引数 TLV(Bytes)、返 TLV(I32: 書き込みバイト数)
|
||||
- `close()`: 返 TLV(Void)
|
||||
|
||||
パスの指定(例)
|
||||
- Linux: `plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.so`
|
||||
- Windows: `plugins\nyash-filebox-plugin\target\release\nyash_filebox_plugin.dll`
|
||||
- macOS: `plugins/nyash-filebox-plugin/target/release/libnyash_filebox_plugin.dylib`
|
||||
|
||||
トラブルシュート
|
||||
- `nyash_plugin_abi not found`: ビルド設定(cdylib)やシンボル名を再確認
|
||||
- `ShortBuffer`が返るのにデータが取れない: 2回目の呼び出しで `result` と `*result_len` を適切に設定しているか確認
|
||||
- 読み出しサイズが0: 書き込み後に `close`→`open(r)` してから `read` を実行しているか確認
|
||||
|
||||
関連ドキュメント
|
||||
- `docs/CURRENT_TASK.md`(現在の進捗)
|
||||
- `docs/予定/native-plan/issues/phase_9_75g_bid_integration_architecture.md`(設計計画)
|
||||
|
||||
備考
|
||||
- 本説明書は `C:\git\nyash-project\nyash\docs\説明書\reference\plugin-tester.md` に配置されます(Windowsパス例)。
|
||||
|
||||
@ -1,407 +0,0 @@
|
||||
# 🏆 Nyash Golden Dump Testing System
|
||||
|
||||
*ChatGPT5推奨・MIR互換テスト(回帰検出)完全仕様*
|
||||
|
||||
## 🎯 目的
|
||||
|
||||
**「同じ入力→同じ出力」をinterp/vm/wasm/aot間で保証する自動検証システム**
|
||||
|
||||
MIR仕様の揺れ・バックエンド差異・最適化バグを**即座検出**し、Portability Contract v0を技術的に保証。
|
||||
|
||||
## 🔧 **Golden Dump方式**
|
||||
|
||||
### **基本原理**
|
||||
```bash
|
||||
# 1. MIR「黄金標準」生成
|
||||
nyash --dump-mir program.nyash > program.golden.mir
|
||||
|
||||
# 2. 実行時MIR比較(回帰検出)
|
||||
nyash --dump-mir program.nyash > program.current.mir
|
||||
diff program.golden.mir program.current.mir
|
||||
|
||||
# 3. 全バックエンド出力比較(互換検証)
|
||||
nyash --target interp program.nyash > interp.out
|
||||
nyash --target vm program.nyash > vm.out
|
||||
nyash --target wasm program.nyash > wasm.out
|
||||
diff interp.out vm.out && diff vm.out wasm.out
|
||||
```
|
||||
|
||||
### **階層化検証戦略**
|
||||
| レベル | 検証対象 | 目的 | 頻度 |
|
||||
|--------|----------|------|------|
|
||||
| **L1: MIR構造** | AST→MIR変換 | 回帰検出 | 毎commit |
|
||||
| **L2: 実行結果** | stdout/stderr | 互換性 | 毎PR |
|
||||
| **L3: 最適化効果** | 性能・メモリ | 最適化回帰 | 毎週 |
|
||||
| **L4: エラー処理** | 例外・エラー | 堅牢性 | 毎リリース |
|
||||
|
||||
## 🧪 **検証テストスイート**
|
||||
|
||||
### **1️⃣ MIR Structure Tests (L1)**
|
||||
|
||||
#### **基本構造検証**
|
||||
```rust
|
||||
// tests/golden_dump/mir_structure_tests.rs
|
||||
#[test]
|
||||
fn test_basic_arithmetic_mir_stability() {
|
||||
let source = r#"
|
||||
static box Main {
|
||||
main() {
|
||||
local a, b, result
|
||||
a = 42
|
||||
b = 8
|
||||
result = a + b
|
||||
print(result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let golden_mir = load_golden_mir("basic_arithmetic.mir");
|
||||
let current_mir = compile_to_mir(source);
|
||||
|
||||
assert_eq!(golden_mir, current_mir, "MIR回帰検出");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box_operations_mir_stability() {
|
||||
let source = r#"
|
||||
box DataBox {
|
||||
init { value }
|
||||
pack(val) { me.value = val }
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local obj = new DataBox(100)
|
||||
print(obj.value)
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let golden_mir = load_golden_mir("box_operations.mir");
|
||||
let current_mir = compile_to_mir(source);
|
||||
|
||||
assert_mir_equivalent(golden_mir, current_mir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_reference_mir_stability() {
|
||||
let source = r#"
|
||||
box Parent { init { child_weak } }
|
||||
box Child { init { data } }
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local parent = new Parent()
|
||||
local child = new Child(42)
|
||||
parent.child_weak = weak(child)
|
||||
|
||||
if parent.child_weak.isAlive() {
|
||||
print(parent.child_weak.get().data)
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
verify_mir_golden("weak_reference", source);
|
||||
}
|
||||
```
|
||||
|
||||
#### **MIR比較アルゴリズム**
|
||||
```rust
|
||||
// src/testing/mir_comparison.rs
|
||||
pub fn assert_mir_equivalent(golden: &MirModule, current: &MirModule) {
|
||||
// 1. 関数数・名前一致
|
||||
assert_eq!(golden.functions.len(), current.functions.len());
|
||||
|
||||
for (name, golden_func) in &golden.functions {
|
||||
let current_func = current.functions.get(name)
|
||||
.expect(&format!("関数{}が見つからない", name));
|
||||
|
||||
// 2. 基本ブロック構造一致
|
||||
assert_eq!(golden_func.blocks.len(), current_func.blocks.len());
|
||||
|
||||
// 3. 命令列意味的等価性(ValueId正規化)
|
||||
let golden_normalized = normalize_value_ids(golden_func);
|
||||
let current_normalized = normalize_value_ids(current_func);
|
||||
assert_eq!(golden_normalized, current_normalized);
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_value_ids(func: &MirFunction) -> MirFunction {
|
||||
// ValueIdを連番に正規化(%0, %1, %2...)
|
||||
// 意味的に同じ命令列を確実に比較可能にする
|
||||
}
|
||||
```
|
||||
|
||||
### **2️⃣ Cross-Backend Output Tests (L2)**
|
||||
|
||||
#### **標準出力一致検証**
|
||||
```rust
|
||||
// tests/golden_dump/output_compatibility_tests.rs
|
||||
#[test]
|
||||
fn test_cross_backend_arithmetic_output() {
|
||||
let program = "arithmetic_test.nyash";
|
||||
|
||||
let interp_output = run_backend("interp", program);
|
||||
let vm_output = run_backend("vm", program);
|
||||
let wasm_output = run_backend("wasm", program);
|
||||
|
||||
assert_eq!(interp_output.stdout, vm_output.stdout);
|
||||
assert_eq!(vm_output.stdout, wasm_output.stdout);
|
||||
assert_eq!(interp_output.exit_code, vm_output.exit_code);
|
||||
assert_eq!(vm_output.exit_code, wasm_output.exit_code);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cross_backend_object_lifecycle() {
|
||||
let program = "object_lifecycle_test.nyash";
|
||||
|
||||
let results = run_all_backends(program);
|
||||
|
||||
// fini()順序・タイミングが全バックエンドで同一
|
||||
let finalization_orders: Vec<_> = results.iter()
|
||||
.map(|r| &r.finalization_order)
|
||||
.collect();
|
||||
|
||||
assert!(finalization_orders.windows(2).all(|w| w[0] == w[1]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cross_backend_weak_reference_behavior() {
|
||||
let program = "weak_reference_test.nyash";
|
||||
|
||||
let results = run_all_backends(program);
|
||||
|
||||
// weak参照の生存チェック・null化が同一タイミング
|
||||
let weak_behaviors: Vec<_> = results.iter()
|
||||
.map(|r| &r.weak_reference_timeline)
|
||||
.collect();
|
||||
|
||||
assert_all_equivalent(weak_behaviors);
|
||||
}
|
||||
```
|
||||
|
||||
#### **エラー処理一致検証**
|
||||
```rust
|
||||
#[test]
|
||||
fn test_cross_backend_error_handling() {
|
||||
let error_programs = [
|
||||
"null_dereference.nyash",
|
||||
"division_by_zero.nyash",
|
||||
"weak_reference_after_fini.nyash",
|
||||
"infinite_recursion.nyash"
|
||||
];
|
||||
|
||||
for program in &error_programs {
|
||||
let results = run_all_backends(program);
|
||||
|
||||
// エラー種別・メッセージが全バックエンドで同一
|
||||
let error_types: Vec<_> = results.iter()
|
||||
.map(|r| &r.error_type)
|
||||
.collect();
|
||||
assert_all_equivalent(error_types);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **3️⃣ Optimization Effect Tests (L3)**
|
||||
|
||||
#### **Bus-elision検証**
|
||||
```rust
|
||||
// tests/golden_dump/optimization_tests.rs
|
||||
#[test]
|
||||
fn test_bus_elision_output_equivalence() {
|
||||
let program = "bus_communication_test.nyash";
|
||||
|
||||
let elision_on = run_with_flag(program, "--elide-bus");
|
||||
let elision_off = run_with_flag(program, "--no-elide-bus");
|
||||
|
||||
// 出力は同一・性能は差がある
|
||||
assert_eq!(elision_on.stdout, elision_off.stdout);
|
||||
assert!(elision_on.execution_time < elision_off.execution_time);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pure_function_optimization_equivalence() {
|
||||
let program = "pure_function_optimization.nyash";
|
||||
|
||||
let optimized = run_with_flag(program, "--optimize");
|
||||
let reference = run_with_flag(program, "--no-optimize");
|
||||
|
||||
// 最適化ON/OFFで結果同一
|
||||
assert_eq!(optimized.output, reference.output);
|
||||
|
||||
// PURE関数の呼び出し回数が最適化で削減
|
||||
assert!(optimized.pure_function_calls <= reference.pure_function_calls);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_memory_layout_compatibility() {
|
||||
let program = "memory_intensive_test.nyash";
|
||||
|
||||
let results = run_all_backends(program);
|
||||
|
||||
// Box構造・フィールドアクセスが全バックエンドで同一結果
|
||||
let memory_access_patterns: Vec<_> = results.iter()
|
||||
.map(|r| &r.memory_access_log)
|
||||
.collect();
|
||||
|
||||
assert_memory_semantics_equivalent(memory_access_patterns);
|
||||
}
|
||||
```
|
||||
|
||||
#### **性能回帰検証**
|
||||
```rust
|
||||
#[test]
|
||||
fn test_performance_regression() {
|
||||
let benchmarks = [
|
||||
"arithmetic_heavy.nyash",
|
||||
"object_creation_heavy.nyash",
|
||||
"weak_reference_heavy.nyash"
|
||||
];
|
||||
|
||||
for benchmark in &benchmarks {
|
||||
let golden_perf = load_golden_performance(benchmark);
|
||||
let current_perf = measure_current_performance(benchmark);
|
||||
|
||||
// 性能が大幅に劣化していないことを確認
|
||||
let regression_threshold = 1.2; // 20%まで許容
|
||||
assert!(current_perf.execution_time <= golden_perf.execution_time * regression_threshold);
|
||||
assert!(current_perf.memory_usage <= golden_perf.memory_usage * regression_threshold);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤖 **自動化CI/CD統合**
|
||||
|
||||
### **GitHub Actions設定**
|
||||
```yaml
|
||||
# .github/workflows/golden_dump_testing.yml
|
||||
name: Golden Dump Testing
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
mir-stability:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Run MIR Structure Tests (L1)
|
||||
run: |
|
||||
cargo test --test mir_structure_tests
|
||||
|
||||
- name: Verify MIR Golden Dumps
|
||||
run: |
|
||||
./scripts/verify_mir_golden_dumps.sh
|
||||
|
||||
cross-backend-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
needs: mir-stability
|
||||
steps:
|
||||
- name: Run Cross-Backend Tests (L2)
|
||||
run: |
|
||||
cargo test --test output_compatibility_tests
|
||||
|
||||
- name: Verify All Backend Output Equality
|
||||
run: |
|
||||
./scripts/verify_backend_compatibility.sh
|
||||
|
||||
optimization-regression:
|
||||
runs-on: ubuntu-latest
|
||||
needs: cross-backend-compatibility
|
||||
steps:
|
||||
- name: Run Optimization Tests (L3)
|
||||
run: |
|
||||
cargo test --test optimization_tests
|
||||
|
||||
- name: Performance Regression Check
|
||||
run: |
|
||||
./scripts/check_performance_regression.sh
|
||||
```
|
||||
|
||||
### **自動Golden Dump更新**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# scripts/update_golden_dumps.sh
|
||||
|
||||
echo "🏆 Golden Dump更新中..."
|
||||
|
||||
# 1. 現在のMIRを新しい黄金標準として設定
|
||||
for test_file in tests/golden_dump/programs/*.nyash; do
|
||||
program_name=$(basename "$test_file" .nyash)
|
||||
echo "更新中: $program_name"
|
||||
|
||||
# MIR golden dump更新
|
||||
./target/release/nyash --dump-mir "$test_file" > "tests/golden_dump/mir/${program_name}.golden.mir"
|
||||
|
||||
# 出力 golden dump更新
|
||||
./target/release/nyash --target interp "$test_file" > "tests/golden_dump/output/${program_name}.golden.out"
|
||||
done
|
||||
|
||||
echo "✅ Golden Dump更新完了"
|
||||
|
||||
# 2. 更新を確認するためのテスト実行
|
||||
cargo test --test golden_dump_tests
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "🎉 新しいGolden Dumpでテスト成功"
|
||||
else
|
||||
echo "❌ 新しいGolden Dumpでテスト失敗"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## 📊 **実装優先順位**
|
||||
|
||||
### **Phase 8.4(緊急)**
|
||||
- [ ] **L1実装**: MIR構造検証・基本golden dump
|
||||
- [ ] **基本自動化**: CI/CDでのMIR回帰検出
|
||||
- [ ] **Bus命令テスト**: elision ON/OFF検証基盤
|
||||
|
||||
### **Phase 8.5(短期)**
|
||||
- [ ] **L2実装**: 全バックエンド出力一致検証
|
||||
- [ ] **エラー処理**: 例外・エラーケース検証
|
||||
- [ ] **性能基準**: ベンチマーク回帰検出
|
||||
|
||||
### **Phase 9+(中長期)**
|
||||
- [ ] **L3-L4実装**: 最適化・堅牢性検証
|
||||
- [ ] **高度自動化**: 自動修復・性能トレンド分析
|
||||
- [ ] **形式検証**: 数学的正当性証明
|
||||
|
||||
## 🎯 **期待効果**
|
||||
|
||||
### **品質保証**
|
||||
- **回帰即座検出**: MIR仕様変更のバグを即座発見
|
||||
- **バックエンド信頼性**: 全実行環境で同一動作保証
|
||||
- **最適化安全性**: 高速化による動作変更防止
|
||||
|
||||
### **開発効率**
|
||||
- **自動品質確認**: 手動テスト不要・CI/CDで自動化
|
||||
- **リファクタリング安全性**: 大規模変更の影響範囲特定
|
||||
- **新機能信頼性**: 追加機能が既存動作に影響しない保証
|
||||
|
||||
### **Nyash言語価値**
|
||||
- **エンタープライズ品質**: 厳密な品質保証プロセス
|
||||
- **技術的差別化**: 「全バックエンド互換保証」の実証
|
||||
- **拡張性基盤**: 新バックエンド追加時の品質維持
|
||||
|
||||
---
|
||||
|
||||
## 📚 **関連ドキュメント**
|
||||
|
||||
- **MIRリファレンス**: [mir-reference.md](mir-reference.md)
|
||||
- **互換性契約**: [portability-contract.md](portability-contract.md)
|
||||
- **ベンチマークシステム**: [../../../benchmarks/README.md](../../../benchmarks/README.md)
|
||||
- **CI/CD設定**: [../../../.github/workflows/](../../../.github/workflows/)
|
||||
|
||||
---
|
||||
|
||||
*最終更新: 2025-08-14 - ChatGPT5推奨3点セット完成*
|
||||
|
||||
*Golden Dump Testing = Nyash品質保証の技術的基盤*
|
||||
Reference in New Issue
Block a user