📚 Phase 12: Nyashスクリプトプラグインシステム設計と埋め込みVM構想

## 主な成果
- Nyashスクリプトでプラグイン作成可能という革命的発見
- C ABI制約の分析と埋め込みVMによる解決策
- MIR/VM/JIT層での箱引数サポートの詳細分析

## ドキュメント作成
- Phase 12基本構想(README.md)
- Gemini/Codex先生の技術分析
- C ABIとの整合性問題と解決策
- 埋め込みVM実装ロードマップ
- 箱引数サポートの技術詳細

## 重要な洞察
- 制約は「リンク時にC ABI必要」のみ
- 埋め込みVMでMIRバイトコード実行により解決可能
- Nyashスクリプト→C ABIプラグイン変換が実現可能

Everything is Box → Everything is Plugin → Everything is Possible!
This commit is contained in:
Moe Charm
2025-08-30 22:52:16 +09:00
parent 7a0f9bd432
commit c13d9c045e
82 changed files with 5842 additions and 138 deletions

View File

@ -467,6 +467,12 @@ impl LowerCore {
}
if let Some(v) = self.known_i64.get(id).copied() {
b.emit_const_i64(v);
return;
}
// Load from a local slot if this ValueId was previously materialized (e.g., handle results)
if let Some(slot) = self.local_index.get(id).copied() {
b.load_local_i64(slot);
return;
}
}
@ -534,36 +540,61 @@ impl LowerCore {
}
}
I::NewBox { dst, box_type, args } => {
// Minimal JIT lowering for builtin pluginized boxes: birth() via handle-based shim
if std::env::var("NYASH_USE_PLUGIN_BUILTINS").ok().as_deref() == Some("1") && args.is_empty() {
let bt = box_type.as_str();
match bt {
"StringBox" => {
// Emit host-call to create a new StringBox handle; push as i64
b.emit_host_call(crate::jit::r#extern::collections::SYM_STRING_BIRTH_H, 0, true);
}
"IntegerBox" => {
b.emit_host_call(crate::jit::r#extern::collections::SYM_INTEGER_BIRTH_H, 0, true);
}
_ => {
// Any other NewBox (e.g., ArrayBox/MapBox/etc.) is UNSUPPORTED in JIT for now
// Allow plugin boxes to be created at runtime; treat as no-op for lowering
if bt != "PyRuntimeBox" && bt != "StringBox" && bt != "ConsoleBox" { self.unsupported += 1; }
}
}
} else {
// NewBox with args or NYASH_USE_PLUGIN_BUILTINS!=1
// Special-case: IntegerBox(v) → track known i64, but do not treat as unsupported
if box_type == "IntegerBox" {
if let Some(src) = args.get(0) { if let Some(iv) = self.known_i64.get(src).copied() { self.known_i64.insert(*dst, iv); } }
// no-op lowering; avoid marking unsupported
} else if box_type == "PyRuntimeBox" && args.is_empty() {
// Allow PyRuntimeBox creation as no-op in strict AOT path
} else if box_type == "StringBox" || box_type == "ConsoleBox" {
// Allow StringBox creation (with/without arg) as no-op; valueはシム/実行時にTLVへ
// 最適化は後段へ(現状は汎用・安全な実装に徹する)
// 通常経路:
// - 引数なし: 汎用 birth_htype_idのみでハンドル生成
// - 引数あり: 既存のチェーン(直後の plugin_invoke birth で初期化)を維持(段階的導入)
if args.is_empty() {
let decision = crate::jit::policy::invoke::decide_box_method(box_type, "birth", 0, true);
if let crate::jit::policy::invoke::InvokeDecision::PluginInvoke { type_id, .. } = decision {
b.emit_const_i64(type_id as i64);
b.emit_host_call(crate::jit::r#extern::birth::SYM_BOX_BIRTH_H, 1, true);
self.handle_values.insert(*dst);
let slot = *self.local_index.entry(*dst).or_insert_with(|| { let id = self.next_local; self.next_local += 1; id });
b.store_local_i64(slot);
} else {
self.unsupported += 1;
}
} else {
// 引数あり: 安全なパターンから段階的に birth_i64 に切替
// 1) IntegerBox(const i64)
if box_type == "IntegerBox" && args.len() == 1 {
if let Some(src) = args.get(0) {
if let Some(iv) = self.known_i64.get(src).copied() {
// 汎用 birth_i64(type_id, argc=1, a1=iv)
if let crate::jit::policy::invoke::InvokeDecision::PluginInvoke { type_id, .. } = crate::jit::policy::invoke::decide_box_method(box_type, "birth", 1, true) {
b.emit_const_i64(type_id as i64);
b.emit_const_i64(1);
b.emit_const_i64(iv);
b.emit_host_call("nyash.box.birth_i64", 3, true);
self.handle_values.insert(*dst);
let slot = *self.local_index.entry(*dst).or_insert_with(|| { let id = self.next_local; self.next_local += 1; id });
b.store_local_i64(slot);
// 値伝搬も継続
self.known_i64.insert(*dst, iv);
return Ok(());
}
}
}
}
// 2) 引数がハンドルStringBox等で既に存在する場合最大2引数
if args.len() <= 2 && args.iter().all(|a| self.handle_values.contains(a)) {
if let crate::jit::policy::invoke::InvokeDecision::PluginInvoke { type_id, .. } = crate::jit::policy::invoke::decide_box_method(box_type, "birth", args.len(), true) {
b.emit_const_i64(type_id as i64);
b.emit_const_i64(args.len() as i64);
// a1, a2 を pushローカルに保存済みのハンドルをロード
for a in args.iter().take(2) { self.push_value_if_known_or_param(b, a); }
b.emit_host_call("nyash.box.birth_i64", 2 + args.len(), true);
self.handle_values.insert(*dst);
let slot = *self.local_index.entry(*dst).or_insert_with(|| { let id = self.next_local; self.next_local += 1; id });
b.store_local_i64(slot);
return Ok(());
}
}
// フォールバック: 既存チェーンに委譲(互換)+ 既知値伝搬のみ
if box_type == "IntegerBox" {
if let Some(src) = args.get(0) { if let Some(iv) = self.known_i64.get(src).copied() { self.known_i64.insert(*dst, iv); } }
}
}
// Track boxed numeric literals to aid signature checks (FloatBox/IntegerBox)
if box_type == "FloatBox" {
@ -603,15 +634,27 @@ impl LowerCore {
let argc = 1 + args.len();
// push receiver param index (a0) if known
if let Some(pidx) = self.param_index.get(box_val).copied() { b.emit_param_i64(pidx); } else { b.emit_const_i64(-1); }
// push primary arguments if availablea1, a2 ...
for a in args.iter() { self.push_value_if_known_or_param(b, a); }
b.emit_plugin_invoke_by_name(m, argc, dst.is_some());
if let Some(d) = dst { self.handle_values.insert(*d); }
if let Some(d) = dst {
self.handle_values.insert(*d);
// Store handle result into a local slot so it can be used as argument later
let slot = *self.local_index.entry(*d).or_insert_with(|| { let id = self.next_local; self.next_local += 1; id });
b.store_local_i64(slot);
}
} else if self.handle_values.contains(box_val) && (m == "getattr" || m == "call") {
let argc = 1 + args.len();
// push receiver handle/param index if possible (here receiver is a handle result previously returned)
// We cannot reconstruct handle here; pass -1 to allow shim fallback.
b.emit_const_i64(-1);
for a in args.iter() { self.push_value_if_known_or_param(b, a); }
b.emit_plugin_invoke_by_name(m, argc, dst.is_some());
if let Some(d) = dst { self.handle_values.insert(*d); }
if let Some(d) = dst {
self.handle_values.insert(*d);
let slot = *self.local_index.entry(*d).or_insert_with(|| { let id = self.next_local; self.next_local += 1; id });
b.store_local_i64(slot);
}
} else if (bt == "PyRuntimeBox" && (m == "birth" || m == "eval"))
|| (bt == "IntegerBox" && m == "birth")
|| (bt == "StringBox" && m == "birth")