2025-09-03 05:04:56 +09:00
|
|
|
/*!
|
|
|
|
|
* Host reverse-call API for plugins (Phase 12 / A-1)
|
|
|
|
|
*
|
|
|
|
|
* - Provides C ABI functions that plugins can call to operate on HostHandle (user/builtin boxes) via TLV.
|
|
|
|
|
* - Minimal supported methods: InstanceBox.getField/setField, ArrayBox.get/set
|
|
|
|
|
* - GC correctness: setField/Array.set triggers write barrier using current VM's runtime (TLS-bound during plugin calls).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
use crate::box_trait::NyashBox;
|
|
|
|
|
|
|
|
|
|
// ===== TLS: current VM pointer during plugin invoke =====
|
2025-09-17 16:11:01 +09:00
|
|
|
// When legacy VM is enabled, keep a real pointer for write barriers.
|
|
|
|
|
#[cfg(feature = "vm-legacy")]
|
2025-09-03 05:04:56 +09:00
|
|
|
thread_local! {
|
|
|
|
|
static CURRENT_VM: std::cell::Cell<*mut crate::backend::vm::VM> = std::cell::Cell::new(std::ptr::null_mut());
|
|
|
|
|
}
|
2025-09-17 16:11:01 +09:00
|
|
|
#[cfg(feature = "vm-legacy")]
|
2025-09-17 07:43:07 +09:00
|
|
|
pub fn set_current_vm(ptr: *mut crate::backend::vm::VM) {
|
|
|
|
|
CURRENT_VM.with(|c| c.set(ptr));
|
|
|
|
|
}
|
2025-09-17 16:11:01 +09:00
|
|
|
#[cfg(feature = "vm-legacy")]
|
2025-09-17 07:43:07 +09:00
|
|
|
pub fn clear_current_vm() {
|
|
|
|
|
CURRENT_VM.with(|c| c.set(std::ptr::null_mut()));
|
|
|
|
|
}
|
2025-09-17 16:11:01 +09:00
|
|
|
#[cfg(feature = "vm-legacy")]
|
2025-09-03 05:04:56 +09:00
|
|
|
fn with_current_vm_mut<F, R>(f: F) -> Option<R>
|
2025-09-17 07:43:07 +09:00
|
|
|
where
|
|
|
|
|
F: FnOnce(&mut crate::backend::vm::VM) -> R,
|
|
|
|
|
{
|
2025-09-03 05:04:56 +09:00
|
|
|
CURRENT_VM.with(|c| {
|
|
|
|
|
let p = c.get();
|
2025-09-17 07:43:07 +09:00
|
|
|
if p.is_null() {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(unsafe { f(&mut *p) })
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-17 16:11:01 +09:00
|
|
|
// When legacy VM is disabled, provide stubs (no GC barriers).
|
|
|
|
|
#[cfg(not(feature = "vm-legacy"))]
|
|
|
|
|
pub fn set_current_vm(_ptr: *mut ()) {}
|
|
|
|
|
#[cfg(not(feature = "vm-legacy"))]
|
|
|
|
|
pub fn clear_current_vm() {}
|
|
|
|
|
#[cfg(not(feature = "vm-legacy"))]
|
|
|
|
|
fn with_current_vm_mut<F, R>(_f: F) -> Option<R>
|
|
|
|
|
where
|
|
|
|
|
F: FnOnce(&mut ()) -> R,
|
|
|
|
|
{
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 05:04:56 +09:00
|
|
|
// ===== Utilities: TLV encode helpers (single-value) =====
|
|
|
|
|
fn tlv_encode_one(val: &crate::backend::vm::VMValue) -> Vec<u8> {
|
|
|
|
|
use crate::runtime::plugin_ffi_common as tlv;
|
|
|
|
|
let mut buf = tlv::encode_tlv_header(1);
|
|
|
|
|
match val {
|
|
|
|
|
crate::backend::vm::VMValue::Integer(i) => tlv::encode::i64(&mut buf, *i),
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => tlv::encode::f64(&mut buf, *f),
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b) => tlv::encode::bool(&mut buf, *b),
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => tlv::encode::string(&mut buf, s),
|
|
|
|
|
crate::backend::vm::VMValue::BoxRef(b) => {
|
|
|
|
|
// Return HostHandle for arbitrary boxes
|
|
|
|
|
let h = crate::runtime::host_handles::to_handle_arc(b.clone());
|
|
|
|
|
tlv::encode::host_handle(&mut buf, h);
|
|
|
|
|
}
|
|
|
|
|
_ => tlv::encode::string(&mut buf, "void"),
|
|
|
|
|
}
|
|
|
|
|
buf
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn vmvalue_from_tlv(tag: u8, payload: &[u8]) -> Option<crate::backend::vm::VMValue> {
|
|
|
|
|
use crate::runtime::plugin_ffi_common as tlv;
|
|
|
|
|
match tag {
|
2025-09-17 07:43:07 +09:00
|
|
|
1 => Some(crate::backend::vm::VMValue::Bool(
|
|
|
|
|
tlv::decode::bool(payload).unwrap_or(false),
|
|
|
|
|
)),
|
2025-09-03 05:04:56 +09:00
|
|
|
2 => tlv::decode::i32(payload).map(|v| crate::backend::vm::VMValue::Integer(v as i64)),
|
|
|
|
|
3 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
if payload.len() == 8 {
|
|
|
|
|
let mut b = [0u8; 8];
|
|
|
|
|
b.copy_from_slice(payload);
|
|
|
|
|
Some(crate::backend::vm::VMValue::Integer(i64::from_le_bytes(b)))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
}
|
|
|
|
|
5 => tlv::decode::f64(payload).map(crate::backend::vm::VMValue::Float),
|
2025-09-17 07:43:07 +09:00
|
|
|
6 | 7 => Some(crate::backend::vm::VMValue::String(tlv::decode::string(
|
|
|
|
|
payload,
|
|
|
|
|
))),
|
2025-09-03 05:04:56 +09:00
|
|
|
8 => {
|
|
|
|
|
// PluginHandle(type_id, instance_id) → reconstruct PluginBoxV2 (when plugins enabled)
|
|
|
|
|
if let Some((type_id, instance_id)) = tlv::decode::plugin_handle(payload) {
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(arc) = plugin_box_from_handle(type_id, instance_id) {
|
|
|
|
|
return Some(crate::backend::vm::VMValue::BoxRef(arc));
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
}
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
9 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(h) = tlv::decode::u64(payload) {
|
|
|
|
|
crate::runtime::host_handles::get(h).map(crate::backend::vm::VMValue::BoxRef)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
}
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-17 07:43:07 +09:00
|
|
|
unsafe fn slice_from_raw<'a>(ptr: *const u8, len: usize) -> &'a [u8] {
|
|
|
|
|
std::slice::from_raw_parts(ptr, len)
|
|
|
|
|
}
|
|
|
|
|
unsafe fn slice_from_raw_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut [u8] {
|
|
|
|
|
std::slice::from_raw_parts_mut(ptr, len)
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
fn encode_out(out_ptr: *mut u8, out_len: *mut usize, buf: &[u8]) -> i32 {
|
|
|
|
|
unsafe {
|
2025-09-17 07:43:07 +09:00
|
|
|
if out_ptr.is_null() || out_len.is_null() {
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let cap = *out_len;
|
2025-09-17 07:43:07 +09:00
|
|
|
if cap < buf.len() {
|
|
|
|
|
return -3;
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let out = slice_from_raw_mut(out_ptr, cap);
|
|
|
|
|
out[..buf.len()].copy_from_slice(buf);
|
|
|
|
|
*out_len = buf.len();
|
|
|
|
|
0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 09:12:39 +09:00
|
|
|
#[cfg_attr(all(not(test), feature = "c-abi-export"), no_mangle)]
|
2025-09-17 07:43:07 +09:00
|
|
|
pub extern "C" fn nyrt_host_call_name(
|
|
|
|
|
handle: u64,
|
|
|
|
|
method_ptr: *const u8,
|
|
|
|
|
method_len: usize,
|
|
|
|
|
args_ptr: *const u8,
|
|
|
|
|
args_len: usize,
|
|
|
|
|
out_ptr: *mut u8,
|
|
|
|
|
out_len: *mut usize,
|
|
|
|
|
) -> i32 {
|
2025-09-03 05:04:56 +09:00
|
|
|
// Resolve receiver
|
2025-09-17 07:43:07 +09:00
|
|
|
let recv_arc = match crate::runtime::host_handles::get(handle) {
|
|
|
|
|
Some(a) => a,
|
|
|
|
|
None => return -1,
|
|
|
|
|
};
|
|
|
|
|
let method =
|
|
|
|
|
unsafe { std::str::from_utf8(slice_from_raw(method_ptr, method_len)).unwrap_or("") }
|
|
|
|
|
.to_string();
|
2025-09-03 05:04:56 +09:00
|
|
|
// Parse TLV args (header + entries)
|
|
|
|
|
let mut argv: Vec<crate::backend::vm::VMValue> = Vec::new();
|
2025-09-17 07:43:07 +09:00
|
|
|
if args_ptr.is_null() || args_len < 4 { /* no args */
|
|
|
|
|
} else {
|
2025-09-03 05:04:56 +09:00
|
|
|
let buf = unsafe { slice_from_raw(args_ptr, args_len) };
|
|
|
|
|
// Iterate entries
|
|
|
|
|
let mut off = 4usize;
|
|
|
|
|
while buf.len() >= off + 4 {
|
2025-09-17 07:43:07 +09:00
|
|
|
let tag = buf[off];
|
|
|
|
|
let _rsv = buf[off + 1];
|
|
|
|
|
let sz = u16::from_le_bytes([buf[off + 2], buf[off + 3]]) as usize;
|
|
|
|
|
if buf.len() < off + 4 + sz {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
let payload = &buf[off + 4..off + 4 + sz];
|
|
|
|
|
if let Some(v) = vmvalue_from_tlv(tag, payload) {
|
|
|
|
|
argv.push(v);
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
off += 4 + sz;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Dispatch minimal supported methods
|
|
|
|
|
// InstanceBox getField/setField
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(inst) = recv_arc
|
|
|
|
|
.as_any()
|
|
|
|
|
.downcast_ref::<crate::instance_v2::InstanceBox>()
|
|
|
|
|
{
|
2025-09-03 05:04:56 +09:00
|
|
|
match method.as_str() {
|
|
|
|
|
"getField" if argv.len() >= 1 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
let field = match &argv[0] {
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => s.clone(),
|
|
|
|
|
v => v.to_string(),
|
|
|
|
|
};
|
|
|
|
|
let out = inst
|
|
|
|
|
.get_field_unified(&field)
|
|
|
|
|
.map(|nv| match nv {
|
|
|
|
|
crate::value::NyashValue::Integer(i) => {
|
|
|
|
|
crate::backend::vm::VMValue::Integer(i)
|
|
|
|
|
}
|
|
|
|
|
crate::value::NyashValue::Float(f) => crate::backend::vm::VMValue::Float(f),
|
|
|
|
|
crate::value::NyashValue::Bool(b) => crate::backend::vm::VMValue::Bool(b),
|
|
|
|
|
crate::value::NyashValue::String(s) => {
|
|
|
|
|
crate::backend::vm::VMValue::String(s)
|
|
|
|
|
}
|
|
|
|
|
crate::value::NyashValue::Void | crate::value::NyashValue::Null => {
|
|
|
|
|
crate::backend::vm::VMValue::String("".to_string())
|
|
|
|
|
}
|
|
|
|
|
crate::value::NyashValue::Box(b) => {
|
|
|
|
|
if let Ok(g) = b.lock() {
|
|
|
|
|
crate::backend::vm::VMValue::BoxRef(std::sync::Arc::from(
|
|
|
|
|
g.share_box(),
|
|
|
|
|
))
|
|
|
|
|
} else {
|
|
|
|
|
crate::backend::vm::VMValue::String("".to_string())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => crate::backend::vm::VMValue::String("".to_string()),
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(crate::backend::vm::VMValue::String("".to_string()));
|
2025-09-03 05:04:56 +09:00
|
|
|
let buf = tlv_encode_one(&out);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
"setField" if argv.len() >= 2 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
let field = match &argv[0] {
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => s.clone(),
|
|
|
|
|
v => v.to_string(),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
// Barrier: use current VM runtime if available
|
2025-09-17 16:11:01 +09:00
|
|
|
#[cfg(feature = "vm-legacy")]
|
|
|
|
|
{
|
|
|
|
|
let _ = with_current_vm_mut(|vm| {
|
|
|
|
|
crate::backend::gc_helpers::gc_write_barrier_site(
|
|
|
|
|
vm.runtime_ref(),
|
|
|
|
|
"HostAPI.setField",
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
// Accept primitives only for now
|
|
|
|
|
let nv_opt = match argv[1].clone() {
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Integer(i) => {
|
|
|
|
|
Some(crate::value::NyashValue::Integer(i))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => {
|
|
|
|
|
Some(crate::value::NyashValue::Float(f))
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
crate::backend::vm::VMValue::Bool(b) => Some(crate::value::NyashValue::Bool(b)),
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::String(s) => {
|
|
|
|
|
Some(crate::value::NyashValue::String(s))
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
crate::backend::vm::VMValue::BoxRef(_) => None,
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(nv) = nv_opt {
|
|
|
|
|
let _ = inst.set_field_unified(field, nv);
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let buf = tlv_encode_one(&crate::backend::vm::VMValue::Bool(true));
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// ArrayBox get/set
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(arr) = recv_arc
|
|
|
|
|
.as_any()
|
|
|
|
|
.downcast_ref::<crate::boxes::array::ArrayBox>()
|
|
|
|
|
{
|
2025-09-03 05:04:56 +09:00
|
|
|
match method.as_str() {
|
|
|
|
|
"get" if argv.len() >= 1 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
let idx = match argv[0].clone() {
|
|
|
|
|
crate::backend::vm::VMValue::Integer(i) => i,
|
|
|
|
|
v => v.to_string().parse::<i64>().unwrap_or(0),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
let out = arr.get(Box::new(crate::box_trait::IntegerBox::new(idx)));
|
|
|
|
|
let vmv = crate::backend::vm::VMValue::from_nyash_box(out);
|
|
|
|
|
let buf = tlv_encode_one(&vmv);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
"set" if argv.len() >= 2 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
let idx = match argv[0].clone() {
|
|
|
|
|
crate::backend::vm::VMValue::Integer(i) => i,
|
|
|
|
|
v => v.to_string().parse::<i64>().unwrap_or(0),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
let vb = match argv[1].clone() {
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Integer(i) => {
|
|
|
|
|
Box::new(crate::box_trait::IntegerBox::new(i)) as Box<dyn NyashBox>
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => {
|
|
|
|
|
Box::new(crate::boxes::math_box::FloatBox::new(f))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b) => {
|
|
|
|
|
Box::new(crate::box_trait::BoolBox::new(b))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => {
|
|
|
|
|
Box::new(crate::box_trait::StringBox::new(s))
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
crate::backend::vm::VMValue::BoxRef(b) => b.share_box(),
|
|
|
|
|
_ => Box::new(crate::box_trait::VoidBox::new()),
|
|
|
|
|
};
|
2025-09-17 16:11:01 +09:00
|
|
|
#[cfg(feature = "vm-legacy")]
|
|
|
|
|
{
|
|
|
|
|
let _ = with_current_vm_mut(|vm| {
|
|
|
|
|
crate::backend::gc_helpers::gc_write_barrier_site(
|
|
|
|
|
vm.runtime_ref(),
|
|
|
|
|
"HostAPI.Array.set",
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let out = arr.set(Box::new(crate::box_trait::IntegerBox::new(idx)), vb);
|
|
|
|
|
let vmv = crate::backend::vm::VMValue::from_nyash_box(out);
|
|
|
|
|
let buf = tlv_encode_one(&vmv);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Unsupported
|
|
|
|
|
-10
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Helper: reconstruct PluginBoxV2 from (type_id, instance_id) when plugins are enabled
|
|
|
|
|
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
|
|
|
|
fn plugin_box_from_handle(type_id: u32, instance_id: u32) -> Option<std::sync::Arc<dyn NyashBox>> {
|
|
|
|
|
let loader = crate::runtime::plugin_loader_v2::get_global_loader_v2();
|
|
|
|
|
let loader = loader.read().ok()?;
|
|
|
|
|
let bx = loader.construct_existing_instance(type_id, instance_id)?;
|
|
|
|
|
Some(std::sync::Arc::from(bx))
|
|
|
|
|
}
|
|
|
|
|
#[cfg(any(not(feature = "plugins"), target_arch = "wasm32"))]
|
2025-09-17 07:43:07 +09:00
|
|
|
fn plugin_box_from_handle(
|
|
|
|
|
_type_id: u32,
|
|
|
|
|
_instance_id: u32,
|
|
|
|
|
) -> Option<std::sync::Arc<dyn NyashBox>> {
|
|
|
|
|
None
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// ---- by-slot variant (selector_id: u64) ----
|
|
|
|
|
// Minimal slot mapping (subject to consolidation with TypeRegistry):
|
|
|
|
|
// 1: InstanceBox.getField(name: string) -> any
|
|
|
|
|
// 2: InstanceBox.setField(name: string, value: any-primitive) -> bool
|
2025-09-03 09:12:39 +09:00
|
|
|
// 3: InstanceBox.has(name: string) -> bool
|
|
|
|
|
// 4: InstanceBox.size() -> i64
|
2025-09-03 05:04:56 +09:00
|
|
|
// 100: ArrayBox.get(index: i64) -> any
|
|
|
|
|
// 101: ArrayBox.set(index: i64, value: any) -> any
|
|
|
|
|
// 102: ArrayBox.len() -> i64
|
2025-09-03 05:41:33 +09:00
|
|
|
// 200: MapBox.size() -> i64
|
|
|
|
|
// 201: MapBox.len() -> i64
|
|
|
|
|
// 202: MapBox.has(key:any) -> bool
|
|
|
|
|
// 203: MapBox.get(key:any) -> any
|
|
|
|
|
// 204: MapBox.set(key:any, value:any) -> any
|
|
|
|
|
// 300: StringBox.len() -> i64
|
2025-09-03 09:12:39 +09:00
|
|
|
#[cfg_attr(all(not(test), feature = "c-abi-export"), no_mangle)]
|
2025-09-17 07:43:07 +09:00
|
|
|
pub extern "C" fn nyrt_host_call_slot(
|
|
|
|
|
handle: u64,
|
|
|
|
|
selector_id: u64,
|
|
|
|
|
args_ptr: *const u8,
|
|
|
|
|
args_len: usize,
|
|
|
|
|
out_ptr: *mut u8,
|
|
|
|
|
out_len: *mut usize,
|
|
|
|
|
) -> i32 {
|
|
|
|
|
let recv_arc = match crate::runtime::host_handles::get(handle) {
|
|
|
|
|
Some(a) => a,
|
|
|
|
|
None => return -1,
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
// Parse TLV args
|
|
|
|
|
let mut argv: Vec<crate::backend::vm::VMValue> = Vec::new();
|
|
|
|
|
if !args_ptr.is_null() && args_len >= 4 {
|
|
|
|
|
let buf = unsafe { slice_from_raw(args_ptr, args_len) };
|
|
|
|
|
let mut off = 4usize;
|
|
|
|
|
while buf.len() >= off + 4 {
|
2025-09-17 07:43:07 +09:00
|
|
|
let tag = buf[off];
|
|
|
|
|
let sz = u16::from_le_bytes([buf[off + 2], buf[off + 3]]) as usize;
|
|
|
|
|
if buf.len() < off + 4 + sz {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
let payload = &buf[off + 4..off + 4 + sz];
|
|
|
|
|
if let Some(v) = vmvalue_from_tlv(tag, payload) {
|
|
|
|
|
argv.push(v);
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
off += 4 + sz;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match selector_id {
|
2025-09-03 09:12:39 +09:00
|
|
|
1 | 2 | 3 | 4 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(inst) = recv_arc
|
|
|
|
|
.as_any()
|
|
|
|
|
.downcast_ref::<crate::instance_v2::InstanceBox>()
|
|
|
|
|
{
|
2025-09-03 05:04:56 +09:00
|
|
|
if selector_id == 1 {
|
|
|
|
|
// getField(name)
|
|
|
|
|
if argv.len() >= 1 {
|
2025-09-17 07:43:07 +09:00
|
|
|
let field = match &argv[0] {
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => s.clone(),
|
|
|
|
|
v => v.to_string(),
|
|
|
|
|
};
|
|
|
|
|
let out = inst
|
|
|
|
|
.get_field_unified(&field)
|
|
|
|
|
.map(|nv| match nv {
|
|
|
|
|
crate::value::NyashValue::Integer(i) => {
|
|
|
|
|
crate::backend::vm::VMValue::Integer(i)
|
|
|
|
|
}
|
|
|
|
|
crate::value::NyashValue::Float(f) => {
|
|
|
|
|
crate::backend::vm::VMValue::Float(f)
|
|
|
|
|
}
|
|
|
|
|
crate::value::NyashValue::Bool(b) => {
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b)
|
|
|
|
|
}
|
|
|
|
|
crate::value::NyashValue::String(s) => {
|
|
|
|
|
crate::backend::vm::VMValue::String(s)
|
|
|
|
|
}
|
|
|
|
|
crate::value::NyashValue::Void | crate::value::NyashValue::Null => {
|
|
|
|
|
crate::backend::vm::VMValue::String("".to_string())
|
|
|
|
|
}
|
|
|
|
|
crate::value::NyashValue::Box(b) => {
|
|
|
|
|
if let Ok(g) = b.lock() {
|
|
|
|
|
crate::backend::vm::VMValue::BoxRef(std::sync::Arc::from(
|
|
|
|
|
g.share_box(),
|
|
|
|
|
))
|
|
|
|
|
} else {
|
|
|
|
|
crate::backend::vm::VMValue::String("".to_string())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => crate::backend::vm::VMValue::String("".to_string()),
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(crate::backend::vm::VMValue::String("".to_string()));
|
2025-09-03 05:04:56 +09:00
|
|
|
let buf = tlv_encode_one(&out);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
2025-09-03 09:12:39 +09:00
|
|
|
} else if selector_id == 2 {
|
2025-09-03 05:04:56 +09:00
|
|
|
// setField(name, value)
|
|
|
|
|
if argv.len() >= 2 {
|
2025-09-17 07:43:07 +09:00
|
|
|
let field = match &argv[0] {
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => s.clone(),
|
|
|
|
|
v => v.to_string(),
|
|
|
|
|
};
|
2025-09-17 16:11:01 +09:00
|
|
|
#[cfg(feature = "vm-legacy")]
|
|
|
|
|
{
|
|
|
|
|
let _ = with_current_vm_mut(|vm| {
|
|
|
|
|
crate::backend::gc_helpers::gc_write_barrier_site(
|
|
|
|
|
vm.runtime_ref(),
|
|
|
|
|
"HostAPI.setField",
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let nv_opt = match argv[1].clone() {
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Integer(i) => {
|
|
|
|
|
Some(crate::value::NyashValue::Integer(i))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => {
|
|
|
|
|
Some(crate::value::NyashValue::Float(f))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b) => {
|
|
|
|
|
Some(crate::value::NyashValue::Bool(b))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => {
|
|
|
|
|
Some(crate::value::NyashValue::String(s))
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
crate::backend::vm::VMValue::BoxRef(_) => None,
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(nv) = nv_opt {
|
|
|
|
|
let _ = inst.set_field_unified(field, nv);
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let buf = tlv_encode_one(&crate::backend::vm::VMValue::Bool(true));
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
2025-09-03 09:12:39 +09:00
|
|
|
} else if selector_id == 3 {
|
|
|
|
|
// has(name)
|
|
|
|
|
if argv.len() >= 1 {
|
2025-09-17 07:43:07 +09:00
|
|
|
let field = match &argv[0] {
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => s.clone(),
|
|
|
|
|
v => v.to_string(),
|
|
|
|
|
};
|
2025-09-03 09:12:39 +09:00
|
|
|
let has = inst.get_field_unified(&field).is_some();
|
|
|
|
|
let buf = tlv_encode_one(&crate::backend::vm::VMValue::Bool(has));
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
} else if selector_id == 4 {
|
|
|
|
|
// size()
|
|
|
|
|
let sz = inst.fields_ng.lock().map(|m| m.len() as i64).unwrap_or(0);
|
|
|
|
|
let buf = tlv_encode_one(&crate::backend::vm::VMValue::Integer(sz));
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
2025-09-03 05:04:56 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
100 | 101 | 102 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(arr) = recv_arc
|
|
|
|
|
.as_any()
|
|
|
|
|
.downcast_ref::<crate::boxes::array::ArrayBox>()
|
|
|
|
|
{
|
2025-09-03 05:04:56 +09:00
|
|
|
match selector_id {
|
2025-09-17 07:43:07 +09:00
|
|
|
100 => {
|
|
|
|
|
// get(index)
|
2025-09-03 05:04:56 +09:00
|
|
|
if argv.len() >= 1 {
|
2025-09-17 07:43:07 +09:00
|
|
|
let idx = match argv[0].clone() {
|
|
|
|
|
crate::backend::vm::VMValue::Integer(i) => i,
|
|
|
|
|
v => v.to_string().parse::<i64>().unwrap_or(0),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
let out = arr.get(Box::new(crate::box_trait::IntegerBox::new(idx)));
|
|
|
|
|
let vmv = crate::backend::vm::VMValue::from_nyash_box(out);
|
|
|
|
|
let buf = tlv_encode_one(&vmv);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
101 => {
|
|
|
|
|
// set(index, value)
|
2025-09-03 05:04:56 +09:00
|
|
|
if argv.len() >= 2 {
|
2025-09-17 07:43:07 +09:00
|
|
|
let idx = match argv[0].clone() {
|
|
|
|
|
crate::backend::vm::VMValue::Integer(i) => i,
|
|
|
|
|
v => v.to_string().parse::<i64>().unwrap_or(0),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
let vb = match argv[1].clone() {
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Integer(i) => {
|
|
|
|
|
Box::new(crate::box_trait::IntegerBox::new(i))
|
|
|
|
|
as Box<dyn NyashBox>
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => {
|
|
|
|
|
Box::new(crate::boxes::math_box::FloatBox::new(f))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b) => {
|
|
|
|
|
Box::new(crate::box_trait::BoolBox::new(b))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => {
|
|
|
|
|
Box::new(crate::box_trait::StringBox::new(s))
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
crate::backend::vm::VMValue::BoxRef(b) => b.share_box(),
|
|
|
|
|
_ => Box::new(crate::box_trait::VoidBox::new()),
|
|
|
|
|
};
|
2025-09-17 16:11:01 +09:00
|
|
|
#[cfg(feature = "vm-legacy")]
|
|
|
|
|
{
|
|
|
|
|
let _ = with_current_vm_mut(|vm| {
|
|
|
|
|
crate::backend::gc_helpers::gc_write_barrier_site(
|
|
|
|
|
vm.runtime_ref(),
|
|
|
|
|
"HostAPI.Array.set",
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let out = arr.set(Box::new(crate::box_trait::IntegerBox::new(idx)), vb);
|
|
|
|
|
let vmv = crate::backend::vm::VMValue::from_nyash_box(out);
|
|
|
|
|
let buf = tlv_encode_one(&vmv);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
102 => {
|
|
|
|
|
// len()
|
2025-09-03 05:04:56 +09:00
|
|
|
let len = arr.len();
|
|
|
|
|
let buf = tlv_encode_one(&crate::backend::vm::VMValue::Integer(len as i64));
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
200 | 201 | 202 | 203 | 204 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(map) = recv_arc
|
|
|
|
|
.as_any()
|
|
|
|
|
.downcast_ref::<crate::boxes::map_box::MapBox>()
|
|
|
|
|
{
|
2025-09-03 05:41:33 +09:00
|
|
|
match selector_id {
|
|
|
|
|
200 | 201 => {
|
|
|
|
|
let out = map.size();
|
|
|
|
|
let vmv = crate::backend::vm::VMValue::from_nyash_box(out);
|
|
|
|
|
let buf = tlv_encode_one(&vmv);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
202 => {
|
|
|
|
|
// has(key)
|
2025-09-03 05:41:33 +09:00
|
|
|
if argv.len() >= 1 {
|
|
|
|
|
let key_box: Box<dyn NyashBox> = match argv[0].clone() {
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Integer(i) => {
|
|
|
|
|
Box::new(crate::box_trait::IntegerBox::new(i))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => {
|
|
|
|
|
Box::new(crate::boxes::math_box::FloatBox::new(f))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b) => {
|
|
|
|
|
Box::new(crate::box_trait::BoolBox::new(b))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => {
|
|
|
|
|
Box::new(crate::box_trait::StringBox::new(s))
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
crate::backend::vm::VMValue::BoxRef(b) => b.share_box(),
|
|
|
|
|
crate::backend::vm::VMValue::Future(fu) => Box::new(fu),
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Void => {
|
|
|
|
|
Box::new(crate::box_trait::VoidBox::new())
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
};
|
|
|
|
|
let out = map.has(key_box);
|
|
|
|
|
let vmv = crate::backend::vm::VMValue::from_nyash_box(out);
|
|
|
|
|
let buf = tlv_encode_one(&vmv);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
203 => {
|
|
|
|
|
// get(key)
|
2025-09-03 05:41:33 +09:00
|
|
|
if argv.len() >= 1 {
|
|
|
|
|
let key_box: Box<dyn NyashBox> = match argv[0].clone() {
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Integer(i) => {
|
|
|
|
|
Box::new(crate::box_trait::IntegerBox::new(i))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => {
|
|
|
|
|
Box::new(crate::boxes::math_box::FloatBox::new(f))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b) => {
|
|
|
|
|
Box::new(crate::box_trait::BoolBox::new(b))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => {
|
|
|
|
|
Box::new(crate::box_trait::StringBox::new(s))
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
crate::backend::vm::VMValue::BoxRef(b) => b.share_box(),
|
|
|
|
|
crate::backend::vm::VMValue::Future(fu) => Box::new(fu),
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Void => {
|
|
|
|
|
Box::new(crate::box_trait::VoidBox::new())
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
};
|
|
|
|
|
let out = map.get(key_box);
|
|
|
|
|
let vmv = crate::backend::vm::VMValue::from_nyash_box(out);
|
|
|
|
|
let buf = tlv_encode_one(&vmv);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
204 => {
|
|
|
|
|
// set(key, value)
|
2025-09-03 05:41:33 +09:00
|
|
|
if argv.len() >= 2 {
|
|
|
|
|
let key_box: Box<dyn NyashBox> = match argv[0].clone() {
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Integer(i) => {
|
|
|
|
|
Box::new(crate::box_trait::IntegerBox::new(i))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => {
|
|
|
|
|
Box::new(crate::boxes::math_box::FloatBox::new(f))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b) => {
|
|
|
|
|
Box::new(crate::box_trait::BoolBox::new(b))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => {
|
|
|
|
|
Box::new(crate::box_trait::StringBox::new(s))
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
crate::backend::vm::VMValue::BoxRef(b) => b.share_box(),
|
|
|
|
|
crate::backend::vm::VMValue::Future(fu) => Box::new(fu),
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Void => {
|
|
|
|
|
Box::new(crate::box_trait::VoidBox::new())
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
};
|
|
|
|
|
let val_box: Box<dyn NyashBox> = match argv[1].clone() {
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Integer(i) => {
|
|
|
|
|
Box::new(crate::box_trait::IntegerBox::new(i))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Float(f) => {
|
|
|
|
|
Box::new(crate::boxes::math_box::FloatBox::new(f))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::Bool(b) => {
|
|
|
|
|
Box::new(crate::box_trait::BoolBox::new(b))
|
|
|
|
|
}
|
|
|
|
|
crate::backend::vm::VMValue::String(s) => {
|
|
|
|
|
Box::new(crate::box_trait::StringBox::new(s))
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
crate::backend::vm::VMValue::BoxRef(b) => b.share_box(),
|
|
|
|
|
crate::backend::vm::VMValue::Future(fu) => Box::new(fu),
|
2025-09-17 07:43:07 +09:00
|
|
|
crate::backend::vm::VMValue::Void => {
|
|
|
|
|
Box::new(crate::box_trait::VoidBox::new())
|
|
|
|
|
}
|
2025-09-03 05:41:33 +09:00
|
|
|
};
|
|
|
|
|
let out = map.set(key_box, val_box);
|
|
|
|
|
let vmv = crate::backend::vm::VMValue::from_nyash_box(out);
|
|
|
|
|
let buf = tlv_encode_one(&vmv);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
300 => {
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(sb) = recv_arc
|
|
|
|
|
.as_any()
|
|
|
|
|
.downcast_ref::<crate::box_trait::StringBox>()
|
|
|
|
|
{
|
2025-09-03 05:41:33 +09:00
|
|
|
let out = crate::backend::vm::VMValue::Integer(sb.value.len() as i64);
|
|
|
|
|
let buf = tlv_encode_one(&out);
|
|
|
|
|
return encode_out(out_ptr, out_len, &buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
-10
|
|
|
|
|
}
|