5.6 KiB
5.6 KiB
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 へ委譲
- InstanceBoxは
- Registry/Runtime:
NyashRuntime+box_registry+plugin_loader_v2nyash.tomlのlibraries.*を読み込み、Box名→ライブラリ名、type_id、method_id等を集約
NewBox(生成)
- MIRの
NewBox { box_type, args } - VM:
runtime.box_registryにbox_typeを問い合わせ - PluginBoxの場合、Loader v2が
birth(method_id=0)を TLV で呼び出し - Pluginは
type_idと新規instance_idを返却 → Loader はPluginBoxV2を構築 - 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)
- tag=8/2 →
補足
- 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)
- Nyash:
r = cli.get(url) - MIR:
BoxCall(returns_result=true) - VM→Loader: TLV(url = tag=6)
- Loader→Plugin:
invoke(type_id=HttpClient, method_id=get) - Plugin:
- 接続成功:
Handle(HttpResponse)を返す → LoaderはResult.Ok(PluginBoxV2) - 接続失敗:
String("connect failed …")を返す → LoaderはResult.Err(ErrorBox)
- 接続成功:
- 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.mddocs/reference/architecture/mir-to-vm-mapping.mddocs/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統計とプラグイン周りの既知制約