use crate::encode::{nyrt_encode_arg_or_legacy, nyrt_encode_from_legacy_at}; #[no_mangle] pub extern "C" fn nyash_plugin_invoke3_i64( type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64, ) -> i64 { use nyash_rust::runtime::plugin_loader_v2::PluginBoxV2; // Resolve receiver instance from handle first; fallback to legacy VM args (param index) let mut instance_id: u32 = 0; let mut real_type_id: u32 = 0; let mut invoke: Option< unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32, > = None; if a0 > 0 { if let Some(obj) = nyash_rust::jit::rt::handles::get(a0 as u64) { if let Some(p) = obj.as_any().downcast_ref::() { instance_id = p.instance_id(); real_type_id = p.inner.type_id; invoke = Some(p.inner.invoke_fn); } } } if invoke.is_none() && a0 >= 0 && std::env::var("NYASH_JIT_ARGS_HANDLE_ONLY").ok().as_deref() != Some("1") { nyash_rust::jit::rt::with_legacy_vm_args(|args| { let idx = a0 as usize; if let Some(nyash_rust::backend::vm::VMValue::BoxRef(b)) = args.get(idx) { if let Some(p) = b.as_any().downcast_ref::() { instance_id = p.instance_id(); invoke = Some(p.inner.invoke_fn); } } }); } if invoke.is_none() { return 0; } // Build TLV args from a1/a2 if present. Prefer handles/StringBox/IntegerBox via runtime host. use nyash_rust::{backend::vm::VMValue, jit::rt::handles}; // argc from LLVM lowering is explicit arg count (excludes receiver) let nargs = argc.max(0) as usize; let mut buf = nyash_rust::runtime::plugin_ffi_common::encode_tlv_header(nargs as u16); // Encode legacy VM arg at position into provided buffer (avoid capturing &mut buf) let mut encode_from_legacy_into = |dst: &mut Vec, arg_pos: usize| { nyash_rust::jit::rt::with_legacy_vm_args(|args| { if let Some(v) = args.get(arg_pos) { match v { VMValue::String(s) => { nyash_rust::runtime::plugin_ffi_common::encode::string(dst, s) } VMValue::Integer(i) => { nyash_rust::runtime::plugin_ffi_common::encode::i64(dst, *i) } VMValue::Float(f) => { nyash_rust::runtime::plugin_ffi_common::encode::f64(dst, *f) } VMValue::Bool(b) => { nyash_rust::runtime::plugin_ffi_common::encode::bool(dst, *b) } VMValue::BoxRef(b) => { // BufferBox → TLV bytes if let Some(bufbox) = b .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::bytes( dst, &bufbox.to_vec(), ); return; } if let Some(p) = b.as_any().downcast_ref::() { // Prefer StringBox/IntegerBox primitives when possible let host = nyash_rust::runtime::get_global_plugin_host(); if let Ok(hg) = host.read() { if p.box_type == "StringBox" { if let Ok(Some(sb)) = hg.invoke_instance_method( "StringBox", "toUtf8", p.instance_id(), &[], ) { if let Some(s) = sb .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::string( dst, &s.value, ); return; } } } else if p.box_type == "IntegerBox" { if let Ok(Some(ibx)) = hg.invoke_instance_method( "IntegerBox", "get", p.instance_id(), &[], ) { if let Some(i) = ibx.as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::i64( dst, i.value, ); return; } } } } // Fallback: pass handle as plugin-handle TLV nyash_rust::runtime::plugin_ffi_common::encode::plugin_handle( dst, p.inner.type_id, p.instance_id(), ); } else { // Stringify unknown boxes let s = b.to_string_box().value; nyash_rust::runtime::plugin_ffi_common::encode::string(dst, &s) } } _ => {} } } }); }; // Encode argument value or fallback to legacy slot (avoid capturing &mut buf) let mut encode_arg_into = |dst: &mut Vec, val: i64, pos: usize| { let mut appended = false; // Try handle first if val > 0 { if let Some(obj) = handles::get(val as u64) { // BufferBox handle → TLV bytes if let Some(bufbox) = obj .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::bytes(dst, &bufbox.to_vec()); appended = true; return; } if let Some(p) = obj.as_any().downcast_ref::() { let host = nyash_rust::runtime::get_global_plugin_host(); if let Ok(hg) = host.read() { if p.box_type == "StringBox" { if let Ok(Some(sb)) = hg.invoke_instance_method( "StringBox", "toUtf8", p.instance_id(), &[], ) { if let Some(s) = sb .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::string( dst, &s.value, ); appended = true; return; } } } else if p.box_type == "IntegerBox" { if let Ok(Some(ibx)) = hg.invoke_instance_method("IntegerBox", "get", p.instance_id(), &[]) { if let Some(i) = ibx .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::i64( dst, i.value, ); appended = true; return; } } } } // Otherwise, pass as handle TLV nyash_rust::runtime::plugin_ffi_common::encode::plugin_handle( dst, p.inner.type_id, p.instance_id(), ); appended = true; return; } } } // Legacy VM args by positional index (1-based for a1) let before = dst.len(); encode_from_legacy_into(dst, pos); if dst.len() != before { appended = true; } // If still nothing appended (no-op), fallback to raw i64 if !appended { nyash_rust::runtime::plugin_ffi_common::encode::i64(dst, val); } }; if nargs >= 1 { encode_arg_into(&mut buf, a1, 1); } if nargs >= 2 { encode_arg_into(&mut buf, a2, 2); } // Extra args from legacy VM args (positions 3..nargs) if nargs > 2 && std::env::var("NYASH_JIT_ARGS_HANDLE_ONLY").ok().as_deref() != Some("1") { for pos in 3..=nargs { encode_from_legacy_into(&mut buf, pos); } } // Prepare output buffer (dynamic growth on short buffer) let mut cap: usize = 256; let (mut tag_ret, mut sz_ret, mut payload_ret): (u8, usize, Vec) = (0, 0, Vec::new()); loop { let mut out = vec![0u8; cap]; let mut out_len: usize = out.len(); let rc = unsafe { invoke.unwrap()( type_id as u32, method_id as u32, instance_id, buf.as_ptr(), buf.len(), out.as_mut_ptr(), &mut out_len, ) }; if rc != 0 { // Retry on short buffer hint (-1) or when plugin wrote beyond capacity (len > cap) if rc == -1 || out_len > cap { cap = cap.saturating_mul(2).max(out_len + 16); if cap > 1 << 20 { break; } continue; } return 0; } let slice = &out[..out_len]; if let Some((t, s, p)) = nyash_rust::runtime::plugin_ffi_common::decode::tlv_first(slice) { tag_ret = t; sz_ret = s; payload_ret = p.to_vec(); } break; } if payload_ret.is_empty() { return 0; } if let Some((tag, sz, payload)) = Some((tag_ret, sz_ret, payload_ret.as_slice())) { match tag { 2 => { // I32 if let Some(v) = nyash_rust::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; } } 3 => { // I64 if let Some(v) = nyash_rust::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; } if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); return i64::from_le_bytes(b); } } 6 | 7 => { // String/Bytes -> register StringBox handle use nyash_rust::box_trait::{NyashBox, StringBox}; let s = nyash_rust::runtime::plugin_ffi_common::decode::string(payload); let arc: std::sync::Arc = std::sync::Arc::new(StringBox::new(s)); let h = nyash_rust::jit::rt::handles::to_handle(arc); return h as i64; } 8 => { // Handle(tag=8) -> register and return handle id (i64) if sz == 8 { let mut t = [0u8; 4]; t.copy_from_slice(&payload[0..4]); let mut i = [0u8; 4]; i.copy_from_slice(&payload[4..8]); let r_type = u32::from_le_bytes(t); let r_inst = u32::from_le_bytes(i); // Build PluginBoxV2 and register into handle-registry let box_type_name = nyash_rust::runtime::plugin_loader_unified::get_global_plugin_host() .read() .ok() .and_then(|h| h.config_ref().map(|cfg| cfg.box_types.clone())) .and_then(|m| { m.into_iter().find(|(_k, v)| *v == r_type).map(|(k, _v)| k) }) .unwrap_or_else(|| "PluginBox".to_string()); let pb = nyash_rust::runtime::plugin_loader_v2::make_plugin_box_v2( box_type_name.clone(), r_type, r_inst, invoke.unwrap(), ); let arc: std::sync::Arc = std::sync::Arc::new(pb); let h = nyash_rust::jit::rt::handles::to_handle(arc); return h as i64; } } 1 => { // Bool return if nyash_rust::runtime::plugin_ffi_common::decode::bool(payload) .unwrap_or(false) { 1 } else { 0 }; } 5 => { // F64 → optional conversion to i64 if std::env::var("NYASH_JIT_NATIVE_F64").ok().as_deref() == Some("1") { if sz == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); let f = f64::from_le_bytes(b); return f as i64; } } } _ => {} } } 0 } // F64-typed shim: decode TLV first entry and return f64 when possible #[no_mangle] pub extern "C" fn nyash_plugin_invoke3_f64( type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64, ) -> f64 { use nyash_rust::runtime::plugin_loader_v2::PluginBoxV2; // Resolve receiver from legacy VM args or handle registry let mut instance_id: u32 = 0; let mut invoke: Option< unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32, > = None; if a0 > 0 { if let Some(obj) = nyash_rust::jit::rt::handles::get(a0 as u64) { if let Some(p) = obj.as_any().downcast_ref::() { instance_id = p.instance_id(); invoke = Some(p.inner.invoke_fn); } } } if a0 >= 0 && std::env::var("NYASH_JIT_ARGS_HANDLE_ONLY").ok().as_deref() != Some("1") { nyash_rust::jit::rt::with_legacy_vm_args(|args| { let idx = a0 as usize; if let Some(nyash_rust::backend::vm::VMValue::BoxRef(b)) = args.get(idx) { if let Some(p) = b.as_any().downcast_ref::() { instance_id = p.instance_id(); invoke = Some(p.inner.invoke_fn); } } }); } if invoke.is_none() { // Fallback scan for any PluginBoxV2 in args to pick invoke_fn nyash_rust::jit::rt::with_legacy_vm_args(|args| { for v in args.iter() { if let nyash_rust::backend::vm::VMValue::BoxRef(b) = v { if let Some(p) = b.as_any().downcast_ref::() { if p.inner.type_id == (type_id as u32) || invoke.is_none() { instance_id = p.instance_id(); invoke = Some(p.inner.invoke_fn); if p.inner.type_id == (type_id as u32) { break; } } } } } }); } if invoke.is_none() { return 0.0; } // Build TLV args from a1/a2 with String/Integer support use nyash_rust::{backend::vm::VMValue, jit::rt::handles}; // argc from LLVM lowering is explicit arg count (excludes receiver) let nargs = argc.max(0) as usize; let mut buf = nyash_rust::runtime::plugin_ffi_common::encode_tlv_header(nargs as u16); let mut encode_from_legacy = |arg_pos: usize| { nyash_rust::jit::rt::with_legacy_vm_args(|args| { if let Some(v) = args.get(arg_pos) { match v { VMValue::String(s) => { nyash_rust::runtime::plugin_ffi_common::encode::string(&mut buf, s) } VMValue::Integer(i) => { nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, *i) } VMValue::Float(f) => { nyash_rust::runtime::plugin_ffi_common::encode::f64(&mut buf, *f) } VMValue::Bool(b) => { nyash_rust::runtime::plugin_ffi_common::encode::bool(&mut buf, *b) } VMValue::BoxRef(b) => { if let Some(bufbox) = b .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::bytes( &mut buf, &bufbox.to_vec(), ); return; } if let Some(p) = b.as_any().downcast_ref::() { let host = nyash_rust::runtime::get_global_plugin_host(); if let Ok(hg) = host.read() { if p.box_type == "StringBox" { if let Ok(Some(sb)) = hg.invoke_instance_method( "StringBox", "toUtf8", p.instance_id(), &[], ) { if let Some(s) = sb .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::string( &mut buf, &s.value, ); return; } } } else if p.box_type == "IntegerBox" { if let Ok(Some(ibx)) = hg.invoke_instance_method( "IntegerBox", "get", p.instance_id(), &[], ) { if let Some(i) = ibx.as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::i64( &mut buf, i.value, ); return; } } } } nyash_rust::runtime::plugin_ffi_common::encode::plugin_handle( &mut buf, p.inner.type_id, p.instance_id(), ); } else { let s = b.to_string_box().value; nyash_rust::runtime::plugin_ffi_common::encode::string(&mut buf, &s) } } _ => {} } } }); }; let mut encode_arg = |val: i64, pos: usize| { let mut appended = false; if val > 0 { if let Some(obj) = handles::get(val as u64) { if let Some(bufbox) = obj .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::bytes( &mut buf, &bufbox.to_vec(), ); appended = true; return; } if let Some(p) = obj.as_any().downcast_ref::() { let host = nyash_rust::runtime::get_global_plugin_host(); if let Ok(hg) = host.read() { if p.box_type == "StringBox" { if let Ok(Some(sb)) = hg.invoke_instance_method( "StringBox", "toUtf8", p.instance_id(), &[], ) { if let Some(s) = sb .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::string( &mut buf, &s.value, ); appended = true; return; } } } else if p.box_type == "IntegerBox" { if let Ok(Some(ibx)) = hg.invoke_instance_method("IntegerBox", "get", p.instance_id(), &[]) { if let Some(i) = ibx .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::i64( &mut buf, i.value, ); appended = true; return; } } } } nyash_rust::runtime::plugin_ffi_common::encode::plugin_handle( &mut buf, p.inner.type_id, p.instance_id(), ); appended = true; return; } } } let before = buf.len(); // Use global helper to avoid nested mutable borrows on buf nyrt_encode_from_legacy_at(&mut buf, pos); if buf.len() != before { appended = true; } if !appended { nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, val); } }; if nargs >= 1 { encode_arg(a1, 1); } if nargs >= 2 { encode_arg(a2, 2); } if nargs > 2 && std::env::var("NYASH_JIT_ARGS_HANDLE_ONLY").ok().as_deref() != Some("1") { for pos in 3..=nargs { nyrt_encode_from_legacy_at(&mut buf, pos); } } // Prepare output buffer (dynamic growth on short buffer) let mut cap: usize = 256; let (mut tag_ret, mut sz_ret, mut payload_ret): (u8, usize, Vec) = (0, 0, Vec::new()); loop { let mut out = vec![0u8; cap]; let mut out_len: usize = out.len(); let rc = unsafe { invoke.unwrap()( type_id as u32, method_id as u32, instance_id, buf.as_ptr(), buf.len(), out.as_mut_ptr(), &mut out_len, ) }; if rc != 0 { // Retry on short buffer (-1) or when plugin wrote beyond capacity if rc == -1 || out_len > cap { cap = cap.saturating_mul(2).max(out_len + 16); if cap > 1 << 20 { break; } continue; } return 0.0; } let slice = &out[..out_len]; if let Some((t, s, p)) = nyash_rust::runtime::plugin_ffi_common::decode::tlv_first(slice) { tag_ret = t; sz_ret = s; payload_ret = p.to_vec(); } break; } if payload_ret.is_empty() { return 0.0; } if let Some((tag, sz, payload)) = Some((tag_ret, sz_ret, payload_ret.as_slice())) { match tag { 5 => { // F64 if sz == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); return f64::from_le_bytes(b); } } 3 => { // I64 -> f64 if let Some(v) = nyash_rust::runtime::plugin_ffi_common::decode::i32(payload) { return v as f64; } if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); return (i64::from_le_bytes(b)) as f64; } } 1 => { // Bool -> f64 return if nyash_rust::runtime::plugin_ffi_common::decode::bool(payload) .unwrap_or(false) { 1.0 } else { 0.0 }; } _ => {} } } 0.0 } // By-name shims for common method names (getattr/call) #[no_mangle] pub extern "C" fn nyash_plugin_invoke_name_getattr_i64( argc: i64, a0: i64, a1: i64, a2: i64, ) -> i64 { nyash_plugin_invoke_name_common_i64("getattr", argc, a0, a1, a2) } #[no_mangle] pub extern "C" fn nyash_plugin_invoke_name_call_i64(argc: i64, a0: i64, a1: i64, a2: i64) -> i64 { nyash_plugin_invoke_name_common_i64("call", argc, a0, a1, a2) } fn nyash_plugin_invoke_name_common_i64(method: &str, argc: i64, a0: i64, a1: i64, a2: i64) -> i64 { use nyash_rust::runtime::plugin_loader_v2::PluginBoxV2; // Resolve receiver let mut instance_id: u32 = 0; let mut type_id: u32 = 0; let mut box_type: Option = None; let mut invoke: Option< unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32, > = None; if a0 > 0 { if let Some(obj) = nyash_rust::jit::rt::handles::get(a0 as u64) { if let Some(p) = obj.as_any().downcast_ref::() { instance_id = p.instance_id(); type_id = p.inner.type_id; box_type = Some(p.box_type.clone()); invoke = Some(p.inner.invoke_fn); } } } if invoke.is_none() && std::env::var("NYASH_JIT_ARGS_HANDLE_ONLY").ok().as_deref() != Some("1") { nyash_rust::jit::rt::with_legacy_vm_args(|args| { let idx = a0.max(0) as usize; if let Some(nyash_rust::backend::vm::VMValue::BoxRef(b)) = args.get(idx) { if let Some(p) = b.as_any().downcast_ref::() { instance_id = p.instance_id(); type_id = p.inner.type_id; box_type = Some(p.box_type.clone()); invoke = Some(p.inner.invoke_fn); } } }); } if invoke.is_none() { nyash_rust::jit::rt::with_legacy_vm_args(|args| { for v in args.iter() { if let nyash_rust::backend::vm::VMValue::BoxRef(b) = v { if let Some(p) = b.as_any().downcast_ref::() { instance_id = p.instance_id(); type_id = p.inner.type_id; box_type = Some(p.box_type.clone()); invoke = Some(p.inner.invoke_fn); break; } } } }); } if invoke.is_none() { return 0; } let box_type = box_type.unwrap_or_default(); // Resolve method_id via PluginHost by name let mh = if let Ok(host) = nyash_rust::runtime::plugin_loader_unified::get_global_plugin_host().read() { host.resolve_method(&box_type, method) } else { return 0; }; let method_id = match mh { Ok(h) => h.method_id, Err(_) => return 0, } as u32; // Build TLV args from legacy VM args (skip receiver slot) let mut buf = nyash_rust::runtime::plugin_ffi_common::encode_tlv_header( argc.saturating_sub(1).max(0) as u16, ); let mut add_from_legacy = |pos: usize| { nyash_rust::jit::rt::with_legacy_vm_args(|args| { if let Some(v) = args.get(pos) { use nyash_rust::backend::vm::VMValue as V; match v { V::String(s) => { nyash_rust::runtime::plugin_ffi_common::encode::string(&mut buf, s) } V::Integer(i) => { nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, *i) } V::Float(f) => { nyash_rust::runtime::plugin_ffi_common::encode::f64(&mut buf, *f) } V::Bool(b) => { nyash_rust::runtime::plugin_ffi_common::encode::bool(&mut buf, *b) } V::BoxRef(b) => { if let Some(bufbox) = b .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::bytes( &mut buf, &bufbox.to_vec(), ); return; } if let Some(p) = b.as_any().downcast_ref::() { let host = nyash_rust::runtime::get_global_plugin_host(); if let Ok(hg) = host.read() { if p.box_type == "StringBox" { if let Ok(Some(sb)) = hg.invoke_instance_method( "StringBox", "toUtf8", p.instance_id(), &[], ) { if let Some(s) = sb .as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::string( &mut buf, &s.value, ); return; } } } else if p.box_type == "IntegerBox" { if let Ok(Some(ibx)) = hg.invoke_instance_method( "IntegerBox", "get", p.instance_id(), &[], ) { if let Some(i) = ibx.as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::i64( &mut buf, i.value, ); return; } } } } nyash_rust::runtime::plugin_ffi_common::encode::plugin_handle( &mut buf, p.inner.type_id, p.instance_id(), ); } else { let s = b.to_string_box().value; nyash_rust::runtime::plugin_ffi_common::encode::string(&mut buf, &s) } } _ => {} } } }); }; if argc >= 2 { add_from_legacy(1); } if argc >= 3 { add_from_legacy(2); } if argc > 3 { for pos in 3..(argc as usize) { add_from_legacy(pos); } } let mut out = vec![0u8; 4096]; let mut out_len: usize = out.len(); let rc = unsafe { invoke.unwrap()( type_id as u32, method_id, instance_id, buf.as_ptr(), buf.len(), out.as_mut_ptr(), &mut out_len, ) }; if rc != 0 { return 0; } let out_slice = &out[..out_len]; if let Some((tag, _sz, payload)) = nyash_rust::runtime::plugin_ffi_common::decode::tlv_first(out_slice) { match tag { 3 => { if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); return i64::from_le_bytes(b); } } 1 => { return if nyash_rust::runtime::plugin_ffi_common::decode::bool(payload) .unwrap_or(false) { 1 } else { 0 }; } 5 => { if std::env::var("NYASH_JIT_NATIVE_F64").ok().as_deref() == Some("1") { if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); let f = f64::from_le_bytes(b); return f as i64; } } } _ => {} } } 0 } // General by-name invoke: (recv_handle, method_cstr, argc, a1, a2) -> i64 // Export name: nyash.plugin.invoke_by_name_i64 #[export_name = "nyash.plugin.invoke_by_name_i64"] pub extern "C" fn nyash_plugin_invoke_by_name_i64( recv_handle: i64, method: *const i8, argc: i64, a1: i64, a2: i64, ) -> i64 { if method.is_null() { return 0; } let mname = unsafe { std::ffi::CStr::from_ptr(method) }; let Ok(method_str) = mname.to_str() else { return 0; }; use nyash_rust::runtime::plugin_loader_v2::PluginBoxV2; let mut instance_id: u32 = 0; let mut type_id: u32 = 0; let mut box_type: Option = None; let mut invoke: Option< unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32, > = None; if recv_handle > 0 { if let Some(obj) = nyash_rust::jit::rt::handles::get(recv_handle as u64) { if let Some(p) = obj.as_any().downcast_ref::() { instance_id = p.instance_id(); type_id = p.inner.type_id; box_type = Some(p.box_type.clone()); invoke = Some(p.inner.invoke_fn); } } } if invoke.is_none() { return 0; } let box_type = box_type.unwrap_or_default(); // Resolve method_id via PluginHost by name let mh = if let Ok(host) = nyash_rust::runtime::plugin_loader_unified::get_global_plugin_host().read() { host.resolve_method(&box_type, method_str) } else { return 0; }; let method_id = match mh { Ok(h) => h.method_id, Err(_) => return 0, } as u32; // Build TLV args from a1/a2 (no legacy in LLVM path) // argc is the number of explicit arguments (receiver excluded) let nargs = argc.max(0) as usize; let mut buf = nyash_rust::runtime::plugin_ffi_common::encode_tlv_header(nargs as u16); nyrt_encode_arg_or_legacy(&mut buf, a1, 1); if nargs >= 2 { nyrt_encode_arg_or_legacy(&mut buf, a2, 2); } // Execute let mut out = vec![0u8; 512]; let mut out_len: usize = out.len(); let rc = unsafe { invoke.unwrap()( type_id as u32, method_id, instance_id, buf.as_ptr(), buf.len(), out.as_mut_ptr(), &mut out_len, ) }; if rc != 0 { return 0; } if let Some((tag, _sz, payload)) = nyash_rust::runtime::plugin_ffi_common::decode::tlv_first(&out[..out_len]) { match tag { 3 => { if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); return i64::from_le_bytes(b); } } 1 => { return if nyash_rust::runtime::plugin_ffi_common::decode::bool(payload) .unwrap_or(false) { 1 } else { 0 }; } 8 => { if payload.len() == 8 { let mut t = [0u8; 4]; t.copy_from_slice(&payload[0..4]); let mut i = [0u8; 4]; i.copy_from_slice(&payload[4..8]); let r_type = u32::from_le_bytes(t); let r_inst = u32::from_le_bytes(i); let pb = nyash_rust::runtime::plugin_loader_v2::make_plugin_box_v2( box_type.clone(), r_type, r_inst, invoke.unwrap(), ); let arc: std::sync::Arc = std::sync::Arc::new(pb); let h = nyash_rust::jit::rt::handles::to_handle(arc); return h as i64; } } 5 => { if std::env::var("NYASH_JIT_NATIVE_F64").ok().as_deref() == Some("1") { if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); let f = f64::from_le_bytes(b); return f as i64; } } } _ => {} } } 0 } // Tagged by-id invoke (supports f64/int/handle for first two args) // tag: 3=I64, 5=F64(bits), 8=Handle #[export_name = "nyash_plugin_invoke3_tagged_i64"] pub extern "C" fn nyash_plugin_invoke3_tagged_i64( type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, tag1: i64, a2: i64, tag2: i64, a3: i64, tag3: i64, a4: i64, tag4: i64, ) -> i64 { use nyash_rust::runtime::plugin_loader_v2::PluginBoxV2; // Resolve receiver invoke and actual plugin type_id let mut instance_id: u32 = 0; let mut real_type_id: u32 = type_id as u32; let mut invoke: Option< unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32, > = None; if a0 > 0 { if let Some(obj) = nyash_rust::jit::rt::handles::get(a0 as u64) { if let Some(p) = obj.as_any().downcast_ref::() { instance_id = p.instance_id(); real_type_id = p.inner.type_id; invoke = Some(p.inner.invoke_fn); } } } if invoke.is_none() { return 0; } // Build TLV from tags // argc is the number of explicit arguments (receiver excluded) let nargs = argc.max(0) as usize; let mut buf = nyash_rust::runtime::plugin_ffi_common::encode_tlv_header(nargs as u16); let mut enc = |val: i64, tag: i64| match tag { 3 => nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, val), 5 => { let bits = val as u64; let f = f64::from_bits(bits); nyash_rust::runtime::plugin_ffi_common::encode::f64(&mut buf, f); } 8 => { if val > 0 { if let Some(obj) = nyash_rust::jit::rt::handles::get(val as u64) { if let Some(p) = obj.as_any().downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::plugin_handle( &mut buf, p.inner.type_id, p.instance_id(), ); } else { let s = obj.to_string_box().value; nyash_rust::runtime::plugin_ffi_common::encode::string(&mut buf, &s); } } } else { nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, 0); } } _ => nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, val), }; if nargs >= 1 { enc(a1, tag1); } if nargs >= 2 { enc(a2, tag2); } if nargs >= 3 { enc(a3, tag3); } if nargs >= 4 { enc(a4, tag4); } // Invoke let mut out = vec![0u8; 512]; let mut out_len: usize = out.len(); let rc = unsafe { invoke.unwrap()( real_type_id, method_id as u32, instance_id, buf.as_ptr(), buf.len(), out.as_mut_ptr(), &mut out_len, ) }; if rc != 0 { return 0; } if let Some((tag, _sz, payload)) = nyash_rust::runtime::plugin_ffi_common::decode::tlv_first(&out[..out_len]) { match tag { 2 => { if let Some(v) = nyash_rust::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; } } 3 => { if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); return i64::from_le_bytes(b); } if let Some(v) = nyash_rust::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; } } 6 | 7 => { use nyash_rust::box_trait::{NyashBox, StringBox}; let s = nyash_rust::runtime::plugin_ffi_common::decode::string(payload); let arc: std::sync::Arc = std::sync::Arc::new(StringBox::new(s)); let h = nyash_rust::jit::rt::handles::to_handle(arc); return h as i64; } 1 => { return if nyash_rust::runtime::plugin_ffi_common::decode::bool(payload) .unwrap_or(false) { 1 } else { 0 }; } 8 => { if payload.len() == 8 { let mut t = [0u8; 4]; t.copy_from_slice(&payload[0..4]); let mut i = [0u8; 4]; i.copy_from_slice(&payload[4..8]); let r_type = u32::from_le_bytes(t); let r_inst = u32::from_le_bytes(i); let pb = nyash_rust::runtime::plugin_loader_v2::make_plugin_box_v2( "PluginBox".into(), r_type, r_inst, invoke.unwrap(), ); let arc: std::sync::Arc = std::sync::Arc::new(pb); let h = nyash_rust::jit::rt::handles::to_handle(arc); return h as i64; } } 5 => { if std::env::var("NYASH_JIT_NATIVE_F64").ok().as_deref() == Some("1") { if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); let f = f64::from_le_bytes(b); return f as i64; } } } _ => {} } } 0 } // Variable-length tagged invoke by-id // Exported as: nyash.plugin.invoke_tagged_v_i64(i64 type_id, i64 method_id, i64 argc, i64 recv_h, i64* vals, i64* tags) -> i64 #[export_name = "nyash.plugin.invoke_tagged_v_i64"] pub extern "C" fn nyash_plugin_invoke_tagged_v_i64( type_id: i64, method_id: i64, argc: i64, recv_h: i64, vals: *const i64, tags: *const i64, ) -> i64 { use nyash_rust::runtime::plugin_loader_v2::PluginBoxV2; if recv_h <= 0 { return 0; } // Resolve receiver invoke let mut instance_id: u32 = 0; let mut real_type_id: u32 = 0; let mut invoke: Option< unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32, > = None; if let Some(obj) = nyash_rust::jit::rt::handles::get(recv_h as u64) { if let Some(p) = obj.as_any().downcast_ref::() { instance_id = p.instance_id(); real_type_id = p.inner.type_id; invoke = Some(p.inner.invoke_fn); } } if invoke.is_none() { return 0; } let nargs = argc.saturating_sub(1).max(0) as usize; let (vals, tags) = if nargs > 0 && !vals.is_null() && !tags.is_null() { unsafe { ( std::slice::from_raw_parts(vals, nargs), std::slice::from_raw_parts(tags, nargs), ) } } else { (&[][..], &[][..]) }; let mut buf = nyash_rust::runtime::plugin_ffi_common::encode_tlv_header(nargs as u16); for i in 0..nargs { match tags[i] { 3 => nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, vals[i]), 5 => { let f = f64::from_bits(vals[i] as u64); nyash_rust::runtime::plugin_ffi_common::encode::f64(&mut buf, f); } 8 => { if let Some(obj) = nyash_rust::jit::rt::handles::get(vals[i] as u64) { if let Some(p) = obj.as_any().downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::plugin_handle( &mut buf, p.inner.type_id, p.instance_id(), ); } else { let s = obj.to_string_box().value; nyash_rust::runtime::plugin_ffi_common::encode::string(&mut buf, &s); } } else { nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, 0); } } _ => nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, vals[i]), } } let mut out = vec![0u8; 1024]; let mut out_len: usize = out.len(); let rc = unsafe { invoke.unwrap()( real_type_id, method_id as u32, instance_id, buf.as_ptr(), buf.len(), out.as_mut_ptr(), &mut out_len, ) }; if rc != 0 { return 0; } if let Some((tag, _sz, payload)) = nyash_rust::runtime::plugin_ffi_common::decode::tlv_first(&out[..out_len]) { match tag { 2 => { if let Some(v) = nyash_rust::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; } } 3 => { if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); return i64::from_le_bytes(b); } if let Some(v) = nyash_rust::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; } } 6 | 7 => { use nyash_rust::box_trait::{NyashBox, StringBox}; let s = nyash_rust::runtime::plugin_ffi_common::decode::string(payload); let arc: std::sync::Arc = std::sync::Arc::new(StringBox::new(s)); let h = nyash_rust::jit::rt::handles::to_handle(arc); return h as i64; } 1 => { return if nyash_rust::runtime::plugin_ffi_common::decode::bool(payload) .unwrap_or(false) { 1 } else { 0 }; } 8 => { if payload.len() == 8 { let mut t = [0u8; 4]; t.copy_from_slice(&payload[0..4]); let mut i = [0u8; 4]; i.copy_from_slice(&payload[4..8]); let r_type = u32::from_le_bytes(t); let r_inst = u32::from_le_bytes(i); let pb = nyash_rust::runtime::plugin_loader_v2::make_plugin_box_v2( "PluginBox".into(), r_type, r_inst, invoke.unwrap(), ); let arc: std::sync::Arc = std::sync::Arc::new(pb); let h = nyash_rust::jit::rt::handles::to_handle(arc); return h as i64; } } 5 => { if std::env::var("NYASH_JIT_NATIVE_F64").ok().as_deref() == Some("1") { if payload.len() == 8 { let mut b = [0u8; 8]; b.copy_from_slice(payload); let f = f64::from_le_bytes(b); return f as i64; } } } _ => {} } } 0 }