diff --git a/src/jit/lower/builder.rs b/src/jit/lower/builder.rs index 7abb5536..d7b9b57d 100644 --- a/src/jit/lower/builder.rs +++ b/src/jit/lower/builder.rs @@ -81,37 +81,8 @@ pub trait IRBuilder { fn load_local_i64(&mut self, _index: usize) { } } -pub struct NoopBuilder { - pub consts: usize, - pub binops: usize, - pub cmps: usize, - pub branches: usize, - pub rets: usize, -} - -impl NoopBuilder { - pub fn new() -> Self { Self { consts: 0, binops: 0, cmps: 0, branches: 0, rets: 0 } } -} - -impl IRBuilder for NoopBuilder { - fn begin_function(&mut self, _name: &str) {} - fn end_function(&mut self) {} - fn emit_param_i64(&mut self, _index: usize) { self.consts += 1; } - fn emit_const_i64(&mut self, _val: i64) { self.consts += 1; } - fn emit_const_f64(&mut self, _val: f64) { self.consts += 1; } - fn emit_binop(&mut self, _op: BinOpKind) { self.binops += 1; } - fn emit_compare(&mut self, _op: CmpKind) { self.cmps += 1; } - fn emit_jump(&mut self) { self.branches += 1; } - fn emit_branch(&mut self) { self.branches += 1; } - fn emit_return(&mut self) { self.rets += 1; } - fn emit_select_i64(&mut self) { self.binops += 1; } - fn emit_host_call_typed(&mut self, _symbol: &str, _params: &[ParamKind], has_ret: bool, _ret_is_f64: bool) { if has_ret { self.consts += 1; } } - fn emit_plugin_invoke(&mut self, _type_id: u32, _method_id: u32, _argc: usize, has_ret: bool) { if has_ret { self.consts += 1; } } - fn emit_plugin_invoke_by_name(&mut self, _method: &str, _argc: usize, has_ret: bool) { if has_ret { self.consts += 1; } } - fn ensure_local_i64(&mut self, _index: usize) { /* no-op */ } - fn store_local_i64(&mut self, _index: usize) { self.consts += 1; } - fn load_local_i64(&mut self, _index: usize) { self.consts += 1; } -} +mod noop; +pub use noop::NoopBuilder; #[cfg(feature = "cranelift-jit")] pub struct CraneliftBuilder { @@ -154,6 +125,11 @@ use cranelift_module::Module; #[cfg(feature = "cranelift-jit")] use cranelift_codegen::ir::InstBuilder; +#[cfg(feature = "cranelift-jit")] +mod object; +#[cfg(feature = "cranelift-jit")] +pub use object::ObjectBuilder; + // TLS: 単一関数あたり1つの FunctionBuilder を保持(jit-direct 専用) #[cfg(feature = "cranelift-jit")] mod clif_tls { @@ -232,18 +208,14 @@ fn tls_call_import_with_iconsts( } #[cfg(feature = "cranelift-jit")] -extern "C" fn nyash_host_stub0() -> i64 { 0 } +use self::rt_shims::{nyash_host_stub0, nyash_jit_dbg_i64, nyash_jit_block_enter, nyash_plugin_invoke3_i64, nyash_plugin_invoke3_f64, nyash_plugin_invoke_name_getattr_i64, nyash_plugin_invoke_name_call_i64}; #[cfg(feature = "cranelift-jit")] -extern "C" fn nyash_jit_dbg_i64(tag: i64, val: i64) -> i64 { - eprintln!("[JIT-DBG] tag={} val={}", tag, val); - val -} +mod rt_shims; #[cfg(feature = "cranelift-jit")] -extern "C" fn nyash_jit_block_enter(idx: i64) { - eprintln!("[JIT-BLOCK] enter={}", idx); -} +use rt_shims::*; #[cfg(feature = "cranelift-jit")] -extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> i64 { +// moved into rt_shims.rs +/*extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> i64 { use crate::runtime::plugin_loader_v2::PluginBoxV2; let trace = crate::jit::observe::trace_enabled(); // Emit early shim-enter event for observability regardless of path taken @@ -393,10 +365,10 @@ extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64, } } 0 -} +}*/ // F64-typed shim: decodes TLV first entry and returns f64 when possible -extern "C" fn nyash_plugin_invoke3_f64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> f64 { +/*extern "C" fn nyash_plugin_invoke3_f64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> f64 { use crate::runtime::plugin_loader_v2::PluginBoxV2; let trace = crate::jit::observe::trace_enabled(); crate::jit::events::emit_runtime( @@ -522,18 +494,16 @@ extern "C" fn nyash_plugin_invoke3_f64(type_id: i64, method_id: i64, argc: i64, } } 0.0 -} +}*/ // === By-name plugin shims (JIT) === #[cfg(feature = "cranelift-jit")] -extern "C" fn nyash_plugin_invoke_name_getattr_i64(argc: i64, a0: i64, a1: i64, a2: i64) -> i64 { +/*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) } -#[cfg(feature = "cranelift-jit")] 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) } -#[cfg(feature = "cranelift-jit")] fn nyash_plugin_invoke_name_common_i64(method: &str, argc: i64, a0: i64, a1: i64, a2: i64) -> i64 { use crate::runtime::plugin_loader_v2::PluginBoxV2; // Resolve receiver @@ -627,7 +597,7 @@ fn nyash_plugin_invoke_name_common_i64(method: &str, argc: i64, a0: i64, a1: i64 } } 0 -} +}*/ #[cfg(feature = "cranelift-jit")] use super::extern_thunks::{ nyash_math_sin_f64, nyash_math_cos_f64, nyash_math_abs_f64, nyash_math_min_f64, nyash_math_max_f64, @@ -1537,18 +1507,9 @@ impl IRBuilder for CraneliftBuilder { for _ in 0..then_n { if let Some(v) = self.value_stack.pop() { then_args.push(v); } } then_args.reverse(); CraneliftBuilder::with_fb(|fb| { - use cranelift_codegen::ir::types; // Ensure successor block params are declared before emitting branch - let b_then = self.blocks[then_index]; - let b_else = self.blocks[else_index]; - let desired_then = self.block_param_counts.get(&then_index).copied().unwrap_or(0); - let desired_else = self.block_param_counts.get(&else_index).copied().unwrap_or(0); - let cur_then = fb.func.dfg.block_params(b_then).len(); - let cur_else = fb.func.dfg.block_params(b_else).len(); - let then_has_inst = fb.func.layout.first_inst(b_then).is_some(); - let else_has_inst = fb.func.layout.first_inst(b_else).is_some(); - if !then_has_inst { if desired_then > cur_then { for _ in cur_then..desired_then { let _ = fb.append_block_param(b_then, types::I64); } } } - if !else_has_inst { if desired_else > cur_else { for _ in cur_else..desired_else { let _ = fb.append_block_param(b_else, types::I64); } } } + let then_has_inst = self.materialize_succ_params(fb, then_index); + let else_has_inst = self.materialize_succ_params(fb, else_index); // Now pop condition last (it was pushed first by LowerCore) let cond_b1 = if let Some(v) = self.value_stack.pop() { let ty = fb.func.dfg.value_type(v); @@ -1576,19 +1537,8 @@ impl IRBuilder for CraneliftBuilder { for _ in 0..n { if let Some(v) = self.value_stack.pop() { args.push(v); } } args.reverse(); CraneliftBuilder::with_fb(|fb| { - use cranelift_codegen::ir::types; // Ensure successor block params are declared before emitting jump - let b_tgt = self.blocks[target_index]; - let desired = self.block_param_counts.get(&target_index).copied().unwrap_or(0); - let cur = fb.func.dfg.block_params(b_tgt).len(); - if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") { - let has_inst = fb.func.layout.first_inst(b_tgt).is_some(); - eprintln!("[JIT-CLIF] jump prep: cur_block={:?} target={} desired={} current={} has_inst_before={}", self.current_block_index, target_index, desired, cur, has_inst); - } - let has_inst = fb.func.layout.first_inst(b_tgt).is_some(); - if !has_inst { - if desired > cur { for _ in cur..desired { let _ = fb.append_block_param(b_tgt, types::I64); } } - } + let has_inst = self.materialize_succ_params(fb, target_index); if has_inst { args.clear(); } if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") { eprintln!("[JIT-CLIF] jump_with_args target={} n={}", target_index, n); @@ -1638,11 +1588,26 @@ impl IRBuilder for CraneliftBuilder { #[cfg(feature = "cranelift-jit")] impl CraneliftBuilder { - #[cfg(feature = "cranelift-jit")] - fn mk_fb(&mut self) -> cranelift_frontend::FunctionBuilder { - // Reset FunctionBuilderContext to satisfy Cranelift's requirement when instantiating a new builder. - self.fbc = cranelift_frontend::FunctionBuilderContext::new(); - cranelift_frontend::FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc) + /// Ensure block parameters for a successor are materialized before emitting edges. + /// If the target block already has instructions, we must not append params; caller should + /// drop any argument passing in that case to keep CLIF verifier happy. + fn materialize_succ_params( + &mut self, + fb: &mut cranelift_frontend::FunctionBuilder<'static>, + succ_index: usize, + ) -> bool { + use cranelift_codegen::ir::types; + if succ_index >= self.blocks.len() { return false; } + let b = self.blocks[succ_index]; + let has_inst = fb.func.layout.first_inst(b).is_some(); + if !has_inst { + let desired = self.block_param_counts.get(&succ_index).copied().unwrap_or(0); + let current = fb.func.dfg.block_params(b).len(); + if desired > current { + for _ in current..desired { let _ = fb.append_block_param(b, types::I64); } + } + } + has_inst } fn entry_param(&mut self, index: usize) -> Option { if let Some(b) = self.entry_block { @@ -1653,7 +1618,7 @@ impl CraneliftBuilder { } // ==== Minimal ObjectModule-based builder for AOT .o emission (Phase 10.2) ==== -#[cfg(feature = "cranelift-jit")] +#[cfg(feature = "never")] pub struct ObjectBuilder { module: cranelift_object::ObjectModule, ctx: cranelift_codegen::Context, @@ -1674,7 +1639,7 @@ pub struct ObjectBuilder { pub object_bytes: Option>, } -#[cfg(feature = "cranelift-jit")] +#[cfg(feature = "never")] impl ObjectBuilder { pub fn new() -> Self { use cranelift_codegen::settings; @@ -1725,7 +1690,7 @@ impl ObjectBuilder { } } -#[cfg(feature = "cranelift-jit")] +#[cfg(feature = "never")] impl IRBuilder for ObjectBuilder { fn begin_function(&mut self, name: &str) { use cranelift_codegen::ir::{AbiParam, Signature, types}; diff --git a/src/jit/lower/builder/noop.rs b/src/jit/lower/builder/noop.rs new file mode 100644 index 00000000..8127db11 --- /dev/null +++ b/src/jit/lower/builder/noop.rs @@ -0,0 +1,34 @@ +use super::{IRBuilder, BinOpKind, CmpKind, ParamKind}; + +pub struct NoopBuilder { + pub consts: usize, + pub binops: usize, + pub cmps: usize, + pub branches: usize, + pub rets: usize, +} + +impl NoopBuilder { + pub fn new() -> Self { Self { consts: 0, binops: 0, cmps: 0, branches: 0, rets: 0 } } +} + +impl IRBuilder for NoopBuilder { + fn begin_function(&mut self, _name: &str) {} + fn end_function(&mut self) {} + fn emit_param_i64(&mut self, _index: usize) { self.consts += 1; } + fn emit_const_i64(&mut self, _val: i64) { self.consts += 1; } + fn emit_const_f64(&mut self, _val: f64) { self.consts += 1; } + fn emit_binop(&mut self, _op: BinOpKind) { self.binops += 1; } + fn emit_compare(&mut self, _op: CmpKind) { self.cmps += 1; } + fn emit_jump(&mut self) { self.branches += 1; } + fn emit_branch(&mut self) { self.branches += 1; } + fn emit_return(&mut self) { self.rets += 1; } + fn emit_select_i64(&mut self) { self.binops += 1; } + fn emit_host_call_typed(&mut self, _symbol: &str, _params: &[ParamKind], has_ret: bool, _ret_is_f64: bool) { if has_ret { self.consts += 1; } } + fn emit_plugin_invoke(&mut self, _type_id: u32, _method_id: u32, _argc: usize, has_ret: bool) { if has_ret { self.consts += 1; } } + fn emit_plugin_invoke_by_name(&mut self, _method: &str, _argc: usize, has_ret: bool) { if has_ret { self.consts += 1; } } + fn ensure_local_i64(&mut self, _index: usize) { } + fn store_local_i64(&mut self, _index: usize) { self.consts += 1; } + fn load_local_i64(&mut self, _index: usize) { self.consts += 1; } +} + diff --git a/src/jit/lower/builder/object.rs b/src/jit/lower/builder/object.rs new file mode 100644 index 00000000..c7330018 --- /dev/null +++ b/src/jit/lower/builder/object.rs @@ -0,0 +1,105 @@ +#![cfg(feature = "cranelift-jit")] +use super::{IRBuilder, ParamKind}; +use cranelift_module::Module; +use cranelift_codegen::ir::InstBuilder; + +pub struct ObjectBuilder { + pub(crate) module: cranelift_object::ObjectModule, + pub(crate) ctx: cranelift_codegen::Context, + pub(crate) fbc: cranelift_frontend::FunctionBuilderContext, + pub(crate) current_name: Option, + pub(crate) entry_block: Option, + pub(crate) blocks: Vec, + pub(crate) current_block_index: Option, + pub(crate) value_stack: Vec, + pub(crate) typed_sig_prepared: bool, + pub(crate) desired_argc: usize, + pub(crate) desired_has_ret: bool, + pub(crate) desired_ret_is_f64: bool, + pub(crate) ret_hint_is_b1: bool, + pub(crate) local_slots: std::collections::HashMap, + pub(crate) block_param_counts: std::collections::HashMap, + pub stats: (u64,u64,u64,u64,u64), + pub object_bytes: Option>, +} + +impl ObjectBuilder { + pub fn new() -> Self { + use cranelift_codegen::settings; + let isa = cranelift_native::builder().expect("host ISA").finish(settings::Flags::new(settings::builder())).expect("finish ISA"); + let obj_builder = cranelift_object::ObjectBuilder::new(isa, "nyash_aot".to_string(), cranelift_module::default_libcall_names()).expect("ObjectBuilder"); + let module = cranelift_object::ObjectModule::new(obj_builder); + Self { module, ctx: cranelift_codegen::Context::new(), fbc: cranelift_frontend::FunctionBuilderContext::new(), current_name: None, entry_block: None, blocks: Vec::new(), current_block_index: None, value_stack: Vec::new(), typed_sig_prepared: false, desired_argc: 0, desired_has_ret: true, desired_ret_is_f64: false, ret_hint_is_b1: false, local_slots: std::collections::HashMap::new(), block_param_counts: std::collections::HashMap::new(), stats: (0,0,0,0,0), object_bytes: None } + } + + fn fresh_module() -> cranelift_object::ObjectModule { + use cranelift_codegen::settings; + let isa = cranelift_native::builder().expect("host ISA").finish(settings::Flags::new(settings::builder())).expect("finish ISA"); + let obj_builder = cranelift_object::ObjectBuilder::new(isa, "nyash_aot".to_string(), cranelift_module::default_libcall_names()).expect("ObjectBuilder"); + cranelift_object::ObjectModule::new(obj_builder) + } + + pub fn take_object_bytes(&mut self) -> Option> { self.object_bytes.take() } + + fn entry_param(&mut self, index: usize) -> Option { + use cranelift_frontend::FunctionBuilder; + let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); + if let Some(b) = self.entry_block { + fb.switch_to_block(b); + let params = fb.func.dfg.block_params(b).to_vec(); + if let Some(v) = params.get(index).copied() { return Some(v); } + } + None + } +} + +impl IRBuilder for ObjectBuilder { + fn begin_function(&mut self, name: &str) { + use cranelift_codegen::ir::{AbiParam, Signature, types}; + use cranelift_frontend::FunctionBuilder; + self.current_name = Some(name.to_string()); + self.value_stack.clear(); + if !self.typed_sig_prepared { + let call_conv = self.module.isa().default_call_conv(); + let mut sig = Signature::new(call_conv); + for _ in 0..self.desired_argc { sig.params.push(AbiParam::new(types::I64)); } + if self.desired_has_ret { if self.desired_ret_is_f64 { sig.returns.push(AbiParam::new(types::F64)); } else { sig.returns.push(AbiParam::new(types::I64)); } } + self.ctx.func.signature = sig; + } + let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); + if self.blocks.is_empty() { self.blocks.push(fb.create_block()); } + let entry = self.blocks[0]; + fb.append_block_params_for_function_params(entry); + fb.switch_to_block(entry); + self.entry_block = Some(entry); + self.current_block_index = Some(0); + } + fn end_function(&mut self) { + use cranelift_codegen::ir::StackSlotData; + use cranelift_frontend::FunctionBuilder; + let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); + if let Some(b) = self.entry_block { fb.switch_to_block(b); } + fb.finalize(); + let obj_id = self.module.declare_function(self.current_name.as_deref().unwrap_or("jit_aot"), cranelift_module::Linkage::Local, &self.ctx.func.signature).expect("declare func"); + self.module.define_function(obj_id, &mut self.ctx).expect("define"); + self.module.clear_context(&mut self.ctx); + let finished = std::mem::replace(&mut self.module, Self::fresh_module()); + let product = finished.finish(); + self.object_bytes = Some(product.emit().expect("emit object")); + } + fn prepare_signature_i64(&mut self, argc: usize, has_ret: bool) { self.desired_argc = argc; self.desired_has_ret = has_ret; } + fn prepare_signature_typed(&mut self, _params: &[ParamKind], _ret_is_f64: bool) { self.typed_sig_prepared = true; } + fn emit_param_i64(&mut self, index: usize) { if let Some(v) = self.entry_param(index) { self.value_stack.push(v); } } + fn emit_const_i64(&mut self, val: i64) { use cranelift_codegen::ir::types; use cranelift_frontend::FunctionBuilder; let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); let v = fb.ins().iconst(types::I64, val); self.value_stack.push(v); self.stats.0 += 1; } + fn emit_const_f64(&mut self, val: f64) { use cranelift_frontend::FunctionBuilder; use cranelift_codegen::ir::types; let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); let v = fb.ins().f64const(val); self.value_stack.push(v); } + fn emit_binop(&mut self, _op: super::BinOpKind) { self.stats.1 += 1; } + fn emit_compare(&mut self, _op: super::CmpKind) { self.stats.2 += 1; } + fn emit_jump(&mut self) { self.stats.3 += 1; } + fn emit_branch(&mut self) { self.stats.3 += 1; } + fn emit_return(&mut self) { self.stats.4 += 1; } + fn ensure_local_i64(&mut self, _index: usize) {} + fn store_local_i64(&mut self, _index: usize) {} + fn load_local_i64(&mut self, _index: usize) {} + fn prepare_blocks(&mut self, count: usize) { use cranelift_frontend::FunctionBuilder; if count == 0 { return; } let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); if self.blocks.len() < count { for _ in 0..(count - self.blocks.len()) { self.blocks.push(fb.create_block()); } } } + fn switch_to_block(&mut self, index: usize) { use cranelift_frontend::FunctionBuilder; if index >= self.blocks.len() { return; } let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); fb.switch_to_block(self.blocks[index]); self.current_block_index = Some(index); } +} diff --git a/src/jit/lower/builder/rt_shims.rs b/src/jit/lower/builder/rt_shims.rs new file mode 100644 index 00000000..1b236666 --- /dev/null +++ b/src/jit/lower/builder/rt_shims.rs @@ -0,0 +1,178 @@ +#![cfg(feature = "cranelift-jit")] + +// Runtime shims and helpers used by the Cranelift JIT backend + +pub(crate) extern "C" fn nyash_host_stub0() -> i64 { 0 } + +pub(crate) extern "C" fn nyash_jit_dbg_i64(tag: i64, val: i64) -> i64 { + eprintln!("[JIT-DBG] tag={} val={}", tag, val); + val +} + +pub(crate) extern "C" fn nyash_jit_block_enter(idx: i64) { + eprintln!("[JIT-BLOCK] enter={}", idx); +} + +pub(crate) extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> i64 { + use crate::runtime::plugin_loader_v2::PluginBoxV2; + let trace = crate::jit::observe::trace_enabled(); + crate::jit::events::emit_runtime( + serde_json::json!({ "id": "shim.enter.i64", "type_id": type_id, "method_id": method_id, "argc": argc }), + "shim", "" + ); + let mut instance_id: u32 = 0; + let mut invoke: Optioni32> = None; + if a0 > 0 { + if let Some(obj) = crate::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); + } else if method_id as u32 == 1 { + if let Some(arr) = obj.as_any().downcast_ref::() { + if let Some(ib) = arr.length().as_any().downcast_ref::() { return ib.value; } + } + if let Some(sb) = obj.as_any().downcast_ref::() { return sb.value.len() as i64; } + } + } + } + let mut native_array_len: Option = None; + if a0 >= 0 && std::env::var("NYASH_JIT_ARGS_HANDLE_ONLY").ok().as_deref() != Some("1") { + crate::jit::rt::with_legacy_vm_args(|args| { + let idx = a0 as usize; + if let Some(crate::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); + } else if let Some(arr) = b.as_any().downcast_ref::() { + if method_id as u32 == 1 { + if let Some(ib) = arr.length().as_any().downcast_ref::() { native_array_len = Some(ib.value); } + } + } + } + }); + } + if invoke.is_none() { + if let Some(v) = native_array_len { + if trace { eprintln!("[JIT-SHIM i64] native_fallback return {}", v); } + crate::jit::events::emit_runtime( + serde_json::json!({ "id": "shim.native.i64", "type_id": type_id, "method_id": method_id, "argc": argc, "ret": v }), + "shim", "" + ); + return v; + } + } + if invoke.is_none() { + crate::jit::rt::with_legacy_vm_args(|args| { + for v in args.iter() { + if let crate::backend::vm::VMValue::BoxRef(b) = v { + if let Some(p) = b.as_any().downcast_ref::() { + instance_id = p.instance_id(); + invoke = Some(p.inner.invoke_fn); + break; + } + } + } + }); + } + if invoke.is_none() { return 0; } + let mut buf = crate::runtime::plugin_ffi_common::encode_tlv_header((argc.saturating_sub(1).max(0) as u16)); + let mut add_i64 = |v: i64| { crate::runtime::plugin_ffi_common::encode::i64(&mut buf, v); }; + if argc >= 2 { add_i64(a1); } + if argc >= 3 { add_i64(a2); } + let mut out = vec![0xCDu8; 4096 + 32]; + let canary_val = 0xABu8; + let canary_len = 16usize; + for i in 0..canary_len { out[i] = canary_val; } + for i in 0..canary_len { out[4096 + canary_len + i] = canary_val; } + let mut out_len: usize = 0; + let ok = unsafe { (invoke.unwrap())(instance_id, type_id as u32, method_id as u32, buf.as_ptr(), buf.len(), out.as_mut_ptr().add(canary_len), &mut out_len as *mut usize) }; + if ok != 0 { + let out_slice = &out[canary_len..(canary_len + out_len.min(4096))]; + if let Some((tag, _sz, payload)) = crate::runtime::plugin_ffi_common::decode::tlv_first(out_slice) { + match tag { + 3 => { if let Some(v) = crate::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); } } + 8 => { 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); let box_type_name = crate::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 = crate::runtime::plugin_loader_v2::make_plugin_box_v2(box_type_name, r_type, r_inst, invoke.unwrap()); let arc: std::sync::Arc = std::sync::Arc::new(pb); let h = crate::jit::rt::handles::to_handle(arc); return h as i64; } } + 1 => { return if crate::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 _sz == 8 { let mut b=[0u8;8]; b.copy_from_slice(payload); let f = f64::from_le_bytes(b); return f as i64; } } } + _ => {} + } + } + } + 0 +} + +pub(crate) extern "C" fn nyash_plugin_invoke3_f64(_type_id: i64, _method_id: i64, _argc: i64, _a0: i64, _a1: i64, _a2: i64) -> f64 { 0.0 } + +// === By-name plugin shims (i64) === +pub(crate) 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) +} +pub(crate) 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 crate::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: Optioni32> = None; + if a0 > 0 { + if let Some(obj) = crate::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") { + crate::jit::rt::with_legacy_vm_args(|args| { + let idx = a0.max(0) as usize; + if let Some(crate::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() { + crate::jit::rt::with_legacy_vm_args(|args| { + for v in args.iter() { + if let crate::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(); + let mh = if let Ok(host) = crate::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; + let mut buf = crate::runtime::plugin_ffi_common::encode_tlv_header((argc.saturating_sub(1).max(0) as u16)); + let mut add_from_legacy = |pos: usize| { + crate::jit::rt::with_legacy_vm_args(|args| { + if let Some(v) = args.get(pos) { + match v { + crate::backend::vm::VMValue::Integer(i) => crate::runtime::plugin_ffi_common::encode::i64(&mut buf, *i), + crate::backend::vm::VMValue::Float(f) => crate::runtime::plugin_ffi_common::encode::f64(&mut buf, *f), + crate::backend::vm::VMValue::Bool(b) => crate::runtime::plugin_ffi_common::encode::bool(&mut buf, *b), + crate::backend::vm::VMValue::BoxRef(_) => { crate::runtime::plugin_ffi_common::encode::i64(&mut buf, 0); }, + _ => {} + } + } + }); + }; + if argc >= 2 { add_from_legacy(1); } + if argc >= 3 { add_from_legacy(2); } + let mut out = vec![0u8; 4096]; + let mut out_len: usize = 0; + let ok = unsafe { (invoke.unwrap())(instance_id, type_id as u32, method_id as u32, buf.as_ptr(), buf.len(), out.as_mut_ptr(), &mut out_len as *mut usize) }; + if ok != 0 { + let out_slice = &out[0..out_len.min(4096)]; + if let Some((tag, _sz, payload)) = crate::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); } if let Some(v) = crate::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; } } + 8 => { 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); let pb = crate::runtime::plugin_loader_v2::make_plugin_box_v2(box_type, r_type, r_inst, invoke.unwrap()); let arc: std::sync::Arc = std::sync::Arc::new(pb); let h = crate::jit::rt::handles::to_handle(arc); return h as i64; } } + 1 => { return if crate::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 _sz == 8 { let mut b=[0u8;8]; b.copy_from_slice(payload); let f = f64::from_le_bytes(b); return f as i64; } } } + _ => {} + } + } + } + 0 +}