3.9 KiB
3.9 KiB
解決策:埋め込みVMによるスクリプトプラグイン実現
💡 発想の転換
制約は「リンク時にC ABIが必要」だけ。つまり、C ABI関数の中でVMを動かせばいい!
🎯 アーキテクチャ
// C ABI関数(静的リンク可能)
extern "C" int32_t nyplug_custom_math_invoke(
uint32_t method_id,
const uint8_t* args,
size_t args_len,
uint8_t* result,
size_t* result_len
) {
// 埋め込みVM起動
static NyashVM* embedded_vm = NULL;
if (!embedded_vm) {
embedded_vm = nyash_vm_create_minimal();
nyash_vm_load_script(embedded_vm, EMBEDDED_SCRIPT);
}
// スクリプト実行
return nyash_vm_invoke(embedded_vm, method_id, args, args_len, result, result_len);
}
// スクリプトは文字列リテラルとして埋め込み
static const char* EMBEDDED_SCRIPT = R"(
export box CustomMath {
cached_sin(x) {
// Nyashコード
}
}
)";
🔄 実現方法
1. Nyash→C トランスパイラー
# Nyashスクリプト → C関数
nyash-to-c custom_math.ny > custom_math_plugin.c
# 生成されるC
// custom_math_plugin.c
#include "nyash_embedded_vm.h"
static const char* SCRIPT = "..."; // Nyashコード埋め込み
extern "C" int32_t nyplug_custom_math_invoke(...) {
return nyash_embedded_invoke(SCRIPT, method_id, ...);
}
2. 最小VM実装
// crates/nyash-embedded-vm
pub struct EmbeddedVM {
// 最小限の実行環境
values: Vec<VMValue>,
// スクリプトはプリコンパイル済みMIR
mir: MirModule,
}
#[no_mangle]
pub extern "C" fn nyash_embedded_invoke(
script: *const c_char,
method_id: u32,
// ... TLV args/result
) -> i32 {
// MIR実行(インタープリター)
}
📊 利点と制約
✅ 可能になること
- スクリプトプラグインがEXEに埋め込み可能
- JIT/AOTから呼び出し可能(C ABI経由)
- 既存のプラグインシステムと完全互換
⚠️ 制約
- パフォーマンス: 埋め込みVMのオーバーヘッド
- サイズ: 最小VMランタイムが必要(~500KB?)
- 機能制限: フルVMの一部機能のみ
🚀 段階的実装
Phase 1: 最小埋め込みVM
// 必要最小限の機能
- MIR実行(インタープリター)
- 基本型(Integer, String, Bool)
- メソッド呼び出し
- TLVエンコード/デコード
Phase 2: Nyash→Cトランスパイラー
// input: custom_math.ny
export box CustomMath {
sin(x) { ... }
}
// output: custom_math_plugin.c
extern "C" int32_t nyplug_custom_math_invoke(...) {
static const uint8_t MIR_BYTECODE[] = { ... };
return nyash_embedded_execute(MIR_BYTECODE, ...);
}
Phase 3: 最適化
- MIRプリコンパイル
- 頻出パスのネイティブ化
- 選択的JITコンパイル
💡 実装例
// 生成されたプラグイン
#include <nyash_embedded.h>
// MIRバイトコード(事前コンパイル)
static const uint8_t CUSTOM_MATH_MIR[] = {
0x01, 0x00, // version
0x10, 0x00, // function count
// ... MIR instructions
};
extern "C" int32_t nyplug_custom_math_abi_version() {
return 1;
}
extern "C" int32_t nyplug_custom_math_invoke(
uint32_t method_id,
const uint8_t* args,
size_t args_len,
uint8_t* result,
size_t* result_len
) {
// 埋め込みVM実行
return nyash_mir_execute(
CUSTOM_MATH_MIR,
sizeof(CUSTOM_MATH_MIR),
method_id,
args, args_len,
result, result_len
);
}
🎯 結論
「リンク時にC ABI」という制約は、埋め込みVMで解決可能!
- Nyashスクリプト → MIR → Cコード → ネイティブプラグイン
- 開発の容易さ(Nyash)と配布の利便性(C ABI)を両立
- 既存のプラグインエコシステムと完全互換
これで「Everything is Box」が真に実現する!