// ---- Handle-based birth shims for AOT/JIT object linkage ---- // These resolve symbols like "nyash.string.birth_h" referenced by ObjectModule. // Generic birth by type_id -> handle (no args). Exported as nyash.box.birth_h #[export_name = "nyash.box.birth_h"] pub extern "C" fn nyash_box_birth_h_export(type_id: i64) -> i64 { if type_id <= 0 { return 0; } let tid = type_id as u32; // Map type_id back to type name let name_opt = 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 == tid).map(|(k, _v)| k)); if let Some(box_type) = name_opt { if let Ok(host_g) = nyash_rust::runtime::get_global_plugin_host().read() { if let Ok(b) = host_g.create_box(&box_type, &[]) { let arc: std::sync::Arc = std::sync::Arc::from(b); let h = nyash_rust::jit::rt::handles::to_handle(arc); if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { println!( "nyrt: birth_h {} (type_id={}) -> handle={}", box_type, tid, h ); } return h as i64; } else if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { eprintln!( "nyrt: birth_h {} (type_id={}) FAILED: create_box", box_type, tid ); } } } else if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { eprintln!("nyrt: birth_h (type_id={}) FAILED: type map not found", tid); } 0 } // Generic birth with args: (type_id, argc, a1, a2) -> handle // Export name: nyash.box.birth_i64 #[export_name = "nyash.box.birth_i64"] pub extern "C" fn nyash_box_birth_i64_export(type_id: i64, argc: i64, a1: i64, a2: i64) -> i64 { use nyash_rust::runtime::plugin_loader_v2::PluginBoxV2; if type_id <= 0 { return 0; } let mut invoke: Option< unsafe extern "C" fn(u32, u32, u32, *const u8, usize, *mut u8, *mut usize) -> i32, > = None; // Resolve invoke_fn via temporary instance 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 == (type_id as u32)) .map(|(k, _v)| k) }) .unwrap_or_else(|| "PluginBox".to_string()); if let Ok(host_g) = nyash_rust::runtime::get_global_plugin_host().read() { if let Ok(b) = host_g.create_box(&box_type_name, &[]) { if let Some(p) = b.as_any().downcast_ref::() { invoke = Some(p.inner.invoke_fn); } } } if invoke.is_none() { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { eprintln!("nyrt: birth_i64 (type_id={}) FAILED: no invoke", type_id); } return 0; } let method_id: u32 = 0; // birth let instance_id: u32 = 0; // static // Build TLV args use nyash_rust::jit::rt::handles; 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_handle = |h: i64| { if h > 0 { if let Some(obj) = handles::get(h as u64) { 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, ); 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(), ); return; } } } nyash_rust::runtime::plugin_ffi_common::encode::i64(&mut buf, h); }; if nargs >= 1 { encode_handle(a1); } if nargs >= 2 { encode_handle(a2); } // Extra birth args from legacy VM when present if nargs > 2 && std::env::var("NYASH_JIT_ARGS_HANDLE_ONLY").ok().as_deref() != Some("1") { for pos in 3..=nargs { 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(bx) => { if let Some(pb) = bx.as_any().downcast_ref::() { if let Some(bufbox) = bx.as_any() .downcast_ref::() { nyash_rust::runtime::plugin_ffi_common::encode::bytes( &mut buf, &bufbox.to_vec(), ); } else { nyash_rust::runtime::plugin_ffi_common::encode::plugin_handle( &mut buf, pb.inner.type_id, pb.instance_id(), ); } } else { let s = bx.to_string_box().value; nyash_rust::runtime::plugin_ffi_common::encode::string(&mut buf, &s) } } _ => {} } } }); } } let mut out = vec![0u8; 1024]; 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 { if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { eprintln!( "nyrt: birth_i64 (type_id={}) FAILED: invoke rc={}", type_id, rc ); } return 0; } if let Some((tag, _sz, payload)) = nyash_rust::runtime::plugin_ffi_common::decode::tlv_first(&out[..out_len]) { if tag == 8 && 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_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); if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { println!( "nyrt: birth_i64 {} (type_id={}) argc={} -> handle={}", box_type_name, type_id, nargs, h ); } return h as i64; } } if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") { eprintln!("nyrt: birth_i64 (type_id={}) FAILED: decode", type_id); } 0 }