Files
hakorune/docs/development/roadmap/phases/phase-12/EMBEDDED-VM-BOX-HANDLING.md
Moe Charm c13d9c045e 📚 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!
2025-08-30 22:52:16 +09:00

207 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 埋め込みVMでのBox処理設計
## 🎯 核心MIRレベルでのBox処理を再現
### 現在のMIR/VMでのBox処理フロー
```
1. MIR: BoxCall/PluginInvoke命令
2. VM: ValueId → VMValue変換
3. VMValue → Box<dyn NyashBox> or TLVエンコード
4. メソッド実行
5. 結果をVMValueに戻す
```
## 📊 埋め込みVMの設計
### 1. 軽量VMValue定義
```c
// 埋め込みVM用の値表現
typedef enum {
NYVM_TYPE_INT,
NYVM_TYPE_FLOAT,
NYVM_TYPE_BOOL,
NYVM_TYPE_STRING,
NYVM_TYPE_HANDLE, // Box参照ハンドル
NYVM_TYPE_VOID
} NyVMType;
typedef struct {
NyVMType type;
union {
int64_t i;
double f;
uint8_t b;
struct { const char* data; size_t len; } s;
uint64_t h; // ハンドルBox参照
} value;
} NyVMValue;
```
### 2. MIRバイトコード形式
```c
// BoxCall命令のエンコード
enum {
OP_BOXCALL = 0x20,
OP_PLUGIN_INVOKE = 0x21,
// ...
};
// BoxCall: [op:1] [dst:1] [box_val:1] [method_id:2] [argc:1] [args...]
// 例: BoxCall %2 = %1.toString()
// → 0x20 0x02 0x01 0x00 0x00 0x00
```
### 3. 埋め込みVMでのBoxCall実行
```c
int nyvm_execute_boxcall(
NyashEmbeddedVM* vm,
uint8_t dst,
uint8_t box_val,
uint16_t method_id,
uint8_t argc,
uint8_t* args
) {
// 1. レシーバー取得
NyVMValue* recv = &vm->values[box_val];
// 2. プリミティブ型の場合
if (recv->type != NYVM_TYPE_HANDLE) {
// プリミティブ→TLV変換
uint8_t tlv_buf[256];
size_t tlv_len = encode_primitive_to_tlv(recv, tlv_buf);
// 組み込み実装を呼び出し
return call_builtin_method(recv->type, method_id, tlv_buf, tlv_len);
}
// 3. Boxハンドルの場合
uint64_t handle = recv->value.h;
// 引数をTLVエンコード
uint8_t args_tlv[1024];
size_t args_len = 0;
for (int i = 0; i < argc; i++) {
NyVMValue* arg = &vm->values[args[i]];
args_len += encode_value_to_tlv(arg, &args_tlv[args_len]);
}
// 4. プラグイン呼び出しC ABI
uint8_t result[4096];
size_t result_len = sizeof(result);
int rc = nyash_plugin_invoke(
get_type_id_from_handle(handle),
method_id,
get_instance_id_from_handle(handle),
args_tlv, args_len,
result, &result_len
);
// 5. 結果をVMValueに変換
if (rc == 0) {
decode_tlv_to_value(result, result_len, &vm->values[dst]);
}
return rc;
}
```
## 🔄 Box引数の処理
### 現在のVMRust
```rust
// VMValue → Box<dyn NyashBox>変換
let val = self.get_value(*arg)?;
Ok(val.to_nyash_box())
```
### 埋め込みVMC
```c
// NyVMValue → TLVエンコード
switch (value->type) {
case NYVM_TYPE_INT:
encode_i64(tlv, value->value.i);
break;
case NYVM_TYPE_HANDLE:
encode_handle(tlv,
get_type_id_from_handle(value->value.h),
get_instance_id_from_handle(value->value.h)
);
break;
// ...
}
```
## 💡 実装のポイント
### 1. ハンドル管理
```c
// グローバルハンドルテーブル
typedef struct {
uint32_t type_id;
uint32_t instance_id;
void* native_ptr; // 実際のBoxポインタ必要な場合
} HandleEntry;
static HandleEntry g_handles[MAX_HANDLES];
static uint64_t g_next_handle = 1;
uint64_t register_handle(uint32_t type_id, uint32_t instance_id) {
uint64_t h = g_next_handle++;
g_handles[h].type_id = type_id;
g_handles[h].instance_id = instance_id;
return h;
}
```
### 2. 組み込みメソッド
```c
// 頻出メソッドは埋め込みVMに直接実装
int call_builtin_method(NyVMType type, uint16_t method_id, ...) {
switch (type) {
case NYVM_TYPE_INT:
if (method_id == 0) { // toString
// 整数→文字列変換
}
break;
// ...
}
}
```
### 3. プラグインとの統合
```c
// 生成されるCコード
extern "C" int32_t nyplug_mybox_invoke(...) {
// MIRバイトコード実行
NyashEmbeddedVM vm;
nyvm_init(&vm, BYTECODE, sizeof(BYTECODE));
// 引数をVMスタックに設定
nyvm_decode_args(&vm, args, args_len);
// メソッド実行
nyvm_execute_method(&vm, method_id);
// 結果をTLVエンコード
return nyvm_encode_result(&vm, result, result_len);
}
```
## 🎯 結論
埋め込みVMは
1. **MIRのBoxCall/PluginInvoke命令を忠実に実装**
2. **TLVエンコード/デコードでC ABIと通信**
3. **ハンドルでBox参照を管理**
4. **頻出処理は最適化実装**
これにより、Nyashスクリプトで書いたプラグインも、ネイティブプラグインと同じC ABIで動作します