/*! * VM Instruction Handlers - Extracted from execute_instruction for better modularity */ use crate::mir::{ConstValue, BinaryOp, CompareOp, UnaryOp, ValueId, BasicBlockId, TypeOpKind, MirType}; use crate::box_trait::{NyashBox, BoolBox, VoidBox}; use crate::boxes::ArrayBox; use std::sync::Arc; use super::{VM, VMValue, VMError}; use super::vm::ControlFlow; impl VM { /// Execute a constant instruction pub(super) fn execute_const(&mut self, dst: ValueId, value: &ConstValue) -> Result { let vm_value = VMValue::from(value); self.set_value(dst, vm_value); Ok(ControlFlow::Continue) } /// Execute a binary operation instruction pub(super) fn execute_binop(&mut self, dst: ValueId, op: &BinaryOp, lhs: ValueId, rhs: ValueId) -> Result { let left = self.get_value(lhs)?; let right = self.get_value(rhs)?; let result = self.execute_binary_op(op, &left, &right)?; self.set_value(dst, result); Ok(ControlFlow::Continue) } /// Execute a unary operation instruction pub(super) fn execute_unaryop(&mut self, dst: ValueId, op: &UnaryOp, operand: ValueId) -> Result { let operand_val = self.get_value(operand)?; let result = self.execute_unary_op(op, &operand_val)?; self.set_value(dst, result); Ok(ControlFlow::Continue) } /// Execute a comparison instruction pub(super) fn execute_compare(&mut self, dst: ValueId, op: &CompareOp, lhs: ValueId, rhs: ValueId) -> Result { let left = self.get_value(lhs)?; let right = self.get_value(rhs)?; let result = self.execute_compare_op(op, &left, &right)?; self.set_value(dst, VMValue::Bool(result)); Ok(ControlFlow::Continue) } /// Execute a print instruction pub(super) fn execute_print(&self, value: ValueId) -> Result { let val = self.get_value(value)?; println!("{}", val.to_string()); Ok(ControlFlow::Continue) } /// Execute control flow instructions (Jump, Branch, Return) pub(super) fn execute_jump(&self, target: BasicBlockId) -> Result { Ok(ControlFlow::Jump(target)) } pub(super) fn execute_branch(&self, condition: ValueId, then_bb: BasicBlockId, else_bb: BasicBlockId) -> Result { let cond_val = self.get_value(condition)?; let should_branch = match &cond_val { VMValue::Bool(b) => *b, VMValue::Void => false, VMValue::Integer(i) => *i != 0, VMValue::BoxRef(b) => { if let Some(bool_box) = b.as_any().downcast_ref::() { bool_box.value } else if b.as_any().downcast_ref::().is_some() { false } else { return Err(VMError::TypeError( format!("Branch condition must be bool, void, or integer, got BoxRef({})", b.type_name()) )); } } _ => return Err(VMError::TypeError( format!("Branch condition must be bool, void, or integer, got {:?}", cond_val) )), }; Ok(ControlFlow::Jump(if should_branch { then_bb } else { else_bb })) } pub(super) fn execute_return(&self, value: Option) -> Result { if let Some(val_id) = value { let return_val = self.get_value(val_id)?; Ok(ControlFlow::Return(return_val)) } else { Ok(ControlFlow::Return(VMValue::Void)) } } /// Execute TypeOp instruction pub(super) fn execute_typeop(&mut self, dst: ValueId, op: &TypeOpKind, value: ValueId, ty: &MirType) -> Result { let val = self.get_value(value)?; match op { TypeOpKind::Check => { let is_type = match (&val, ty) { (VMValue::Integer(_), MirType::Integer) => true, (VMValue::Float(_), MirType::Float) => true, (VMValue::Bool(_), MirType::Bool) => true, (VMValue::String(_), MirType::String) => true, (VMValue::Void, MirType::Void) => true, (VMValue::BoxRef(arc_box), MirType::Box(box_name)) => { arc_box.type_name() == box_name } _ => false, }; self.set_value(dst, VMValue::Bool(is_type)); Ok(ControlFlow::Continue) } TypeOpKind::Cast => { let result = match (&val, ty) { // Integer to Float (VMValue::Integer(i), MirType::Float) => VMValue::Float(*i as f64), // Float to Integer (VMValue::Float(f), MirType::Integer) => VMValue::Integer(*f as i64), // Identity casts (VMValue::Integer(_), MirType::Integer) => val.clone(), (VMValue::Float(_), MirType::Float) => val.clone(), (VMValue::Bool(_), MirType::Bool) => val.clone(), (VMValue::String(_), MirType::String) => val.clone(), // BoxRef identity cast (VMValue::BoxRef(arc_box), MirType::Box(box_name)) if arc_box.type_name() == box_name => { val.clone() } // Invalid cast _ => { return Err(VMError::TypeError( format!("Cannot cast {:?} to {:?}", val, ty) )); } }; self.set_value(dst, result); Ok(ControlFlow::Continue) } } } /// Execute Phi instruction pub(super) fn execute_phi(&mut self, dst: ValueId, inputs: &[(BasicBlockId, ValueId)]) -> Result { // For now, just use the first input since we don't track previous BB in this refactored version // TODO: Track previous basic block for proper phi node resolution if let Some((_, val_id)) = inputs.first() { let value = self.get_value(*val_id)?; self.set_value(dst, value); Ok(ControlFlow::Continue) } else { Err(VMError::InvalidInstruction("Phi node has no inputs".to_string())) } } /// Execute Load/Store instructions pub(super) fn execute_load(&mut self, dst: ValueId, ptr: ValueId) -> Result { let loaded_value = self.get_value(ptr)?; self.set_value(dst, loaded_value); Ok(ControlFlow::Continue) } pub(super) fn execute_store(&mut self, value: ValueId, ptr: ValueId) -> Result { let val = self.get_value(value)?; self.set_value(ptr, val); Ok(ControlFlow::Continue) } /// Execute Copy instruction pub(super) fn execute_copy(&mut self, dst: ValueId, src: ValueId) -> Result { let value = self.get_value(src)?; let cloned = match &value { VMValue::BoxRef(arc_box) => { // Use clone_or_share to handle cloning properly let cloned_box = arc_box.clone_or_share(); VMValue::BoxRef(Arc::from(cloned_box)) } other => other.clone(), }; self.set_value(dst, cloned); Ok(ControlFlow::Continue) } /// Execute Call instruction pub(super) fn execute_call(&mut self, dst: Option, func: ValueId, args: &[ValueId]) -> Result { // Get the function name from the ValueId let func_name = match self.get_value(func)? { VMValue::String(s) => s, _ => return Err(VMError::TypeError("Function name must be a string".to_string())), }; let arg_values: Vec = args.iter() .map(|arg| self.get_value(*arg)) .collect::, _>>()?; let result = self.call_function_by_name(&func_name, arg_values)?; if let Some(dst_id) = dst { self.set_value(dst_id, result); } Ok(ControlFlow::Continue) } /// Execute NewBox instruction pub(super) fn execute_newbox(&mut self, dst: ValueId, box_type: &str, args: &[ValueId]) -> Result { // Convert args to NyashBox values let arg_values: Vec> = args.iter() .map(|arg| { let val = self.get_value(*arg)?; Ok(val.to_nyash_box()) }) .collect::, VMError>>()?; // Create new box using runtime's registry let new_box = { let registry = self.runtime.box_registry.lock() .map_err(|_| VMError::InvalidInstruction("Failed to lock box registry".to_string()))?; registry.create_box(box_type, &arg_values) .map_err(|e| VMError::InvalidInstruction(format!("Failed to create {}: {}", box_type, e)))? }; self.set_value(dst, VMValue::BoxRef(Arc::from(new_box))); Ok(ControlFlow::Continue) } /// Execute ArrayGet instruction pub(super) fn execute_array_get(&mut self, dst: ValueId, array: ValueId, index: ValueId) -> Result { let array_val = self.get_value(array)?; let index_val = self.get_value(index)?; if let VMValue::BoxRef(array_box) = &array_val { if let Some(array) = array_box.as_any().downcast_ref::() { // ArrayBox expects Box for index let index_box = index_val.to_nyash_box(); let result = array.get(index_box); self.set_value(dst, VMValue::BoxRef(Arc::from(result))); Ok(ControlFlow::Continue) } else { Err(VMError::TypeError("ArrayGet requires an ArrayBox".to_string())) } } else { Err(VMError::TypeError("ArrayGet requires array and integer index".to_string())) } } /// Execute ArraySet instruction pub(super) fn execute_array_set(&mut self, array: ValueId, index: ValueId, value: ValueId) -> Result { let array_val = self.get_value(array)?; let index_val = self.get_value(index)?; let value_val = self.get_value(value)?; if let VMValue::BoxRef(array_box) = &array_val { if let Some(array) = array_box.as_any().downcast_ref::() { // ArrayBox expects Box for index let index_box = index_val.to_nyash_box(); let box_value = value_val.to_nyash_box(); array.set(index_box, box_value); Ok(ControlFlow::Continue) } else { Err(VMError::TypeError("ArraySet requires an ArrayBox".to_string())) } } else { Err(VMError::TypeError("ArraySet requires array and integer index".to_string())) } } /// Execute RefNew instruction pub(super) fn execute_ref_new(&mut self, dst: ValueId, box_val: ValueId) -> Result { // For now, a reference is just the same as the box value // In a real implementation, this would create a proper reference let box_value = self.get_value(box_val)?; self.set_value(dst, box_value); Ok(ControlFlow::Continue) } /// Execute RefGet instruction pub(super) fn execute_ref_get(&mut self, dst: ValueId, reference: ValueId, field: &str) -> Result { // Visibility check (if class known and visibility declared). Skip for internal refs. let is_internal = self.object_internal.contains(&reference); if !is_internal { if let Some(class_name) = self.object_class.get(&reference) { if let Ok(decls) = self.runtime.box_declarations.read() { if let Some(decl) = decls.get(class_name) { let has_vis = !decl.public_fields.is_empty() || !decl.private_fields.is_empty(); if has_vis && !decl.public_fields.iter().any(|f| f == field) { return Err(VMError::TypeError(format!("Field '{}' is private in {}", field, class_name))); } } } } } // Get field value from object let field_value = if let Some(fields) = self.object_fields.get(&reference) { if let Some(value) = fields.get(field) { value.clone() } else { // Field not set yet, return default VMValue::Integer(0) } } else { // Object has no fields yet, return default VMValue::Integer(0) }; self.set_value(dst, field_value); Ok(ControlFlow::Continue) } /// Execute RefSet instruction pub(super) fn execute_ref_set(&mut self, reference: ValueId, field: &str, value: ValueId) -> Result { // Get the value to set let new_value = self.get_value(value)?; // Visibility check (Skip for internal refs; otherwise enforce public) let is_internal = self.object_internal.contains(&reference); if !is_internal { if let Some(class_name) = self.object_class.get(&reference) { if let Ok(decls) = self.runtime.box_declarations.read() { if let Some(decl) = decls.get(class_name) { let has_vis = !decl.public_fields.is_empty() || !decl.private_fields.is_empty(); if has_vis && !decl.public_fields.iter().any(|f| f == field) { return Err(VMError::TypeError(format!("Field '{}' is private in {}", field, class_name))); } } } } } // Ensure object has field storage if !self.object_fields.contains_key(&reference) { self.object_fields.insert(reference, std::collections::HashMap::new()); } // Set the field if let Some(fields) = self.object_fields.get_mut(&reference) { fields.insert(field.to_string(), new_value); } Ok(ControlFlow::Continue) } /// Execute WeakNew instruction pub(super) fn execute_weak_new(&mut self, dst: ValueId, box_val: ValueId) -> Result { // For now, a weak reference is just a copy of the value // In a real implementation, this would create a proper weak reference let box_value = self.get_value(box_val)?; self.set_value(dst, box_value); Ok(ControlFlow::Continue) } /// Execute WeakLoad instruction pub(super) fn execute_weak_load(&mut self, dst: ValueId, weak_ref: ValueId) -> Result { // For now, loading from weak ref is the same as getting the value // In a real implementation, this would check if the weak ref is still valid let weak_value = self.get_value(weak_ref)?; self.set_value(dst, weak_value); Ok(ControlFlow::Continue) } /// Execute BarrierRead instruction pub(super) fn execute_barrier_read(&mut self, dst: ValueId, value: ValueId) -> Result { // Memory barrier read is currently a simple value copy // In a real implementation, this would ensure memory ordering let val = self.get_value(value)?; self.set_value(dst, val); Ok(ControlFlow::Continue) } /// Execute BarrierWrite instruction pub(super) fn execute_barrier_write(&mut self, _value: ValueId) -> Result { // Memory barrier write is a no-op for now // In a real implementation, this would ensure memory ordering Ok(ControlFlow::Continue) } /// Execute Throw instruction pub(super) fn execute_throw(&mut self, exception: ValueId) -> Result { let exc_value = self.get_value(exception)?; Err(VMError::InvalidInstruction(format!("Exception thrown: {:?}", exc_value))) } /// Execute Catch instruction pub(super) fn execute_catch(&mut self, exception_value: ValueId) -> Result { // For now, catch is a no-op // In a real implementation, this would handle exception catching self.set_value(exception_value, VMValue::Void); Ok(ControlFlow::Continue) } /// Execute Await instruction pub(super) fn execute_await(&mut self, dst: ValueId, future: ValueId) -> Result { let future_val = self.get_value(future)?; if let VMValue::Future(ref future_box) = future_val { // This blocks until the future is ready let result = future_box.get(); // Convert NyashBox back to VMValue let vm_value = VMValue::from_nyash_box(result); self.set_value(dst, vm_value); Ok(ControlFlow::Continue) } else { Err(VMError::TypeError(format!("Expected Future, got {:?}", future_val))) } } /// Execute ExternCall instruction pub(super) fn execute_extern_call(&mut self, dst: Option, iface_name: &str, method_name: &str, args: &[ValueId]) -> Result { // Evaluate arguments as NyashBox for loader let mut nyash_args: Vec> = Vec::new(); for arg_id in args { let arg_value = self.get_value(*arg_id)?; nyash_args.push(arg_value.to_nyash_box()); } // Route through plugin loader v2 (also handles env.* stubs) let loader = crate::runtime::get_global_loader_v2(); let loader = loader.read().map_err(|_| VMError::InvalidInstruction("Plugin loader lock poisoned".into()))?; match loader.extern_call(iface_name, method_name, &nyash_args) { Ok(Some(result_box)) => { if let Some(dst_id) = dst { self.set_value(dst_id, VMValue::from_nyash_box(result_box)); } } Ok(None) => { if let Some(dst_id) = dst { self.set_value(dst_id, VMValue::Void); } } Err(_) => { return Err(VMError::InvalidInstruction(format!("ExternCall failed: {}.{}", iface_name, method_name))); } } Ok(ControlFlow::Continue) } /// Execute BoxCall instruction pub(super) fn execute_boxcall(&mut self, dst: Option, box_val: ValueId, method: &str, args: &[ValueId]) -> Result { let recv = self.get_value(box_val)?; // Debug logging if enabled let debug_boxcall = std::env::var("NYASH_VM_DEBUG_BOXCALL").is_ok(); // Convert args to NyashBox let nyash_args: Vec> = args.iter() .map(|arg| { let val = self.get_value(*arg)?; Ok(val.to_nyash_box()) }) .collect::, VMError>>()?; if debug_boxcall { self.debug_log_boxcall(&recv, method, &nyash_args, "START", None); } // Call the method based on receiver type let result = match &recv { VMValue::BoxRef(arc_box) => { // Direct box method call if debug_boxcall { eprintln!("[BoxCall] Taking BoxRef path for method '{}'", method); } let cloned_box = arc_box.share_box(); self.call_box_method(cloned_box, method, nyash_args)? } _ => { // Convert primitive to box and call if debug_boxcall { eprintln!("[BoxCall] Converting primitive to box for method '{}'", method); } let box_value = recv.to_nyash_box(); self.call_box_method(box_value, method, nyash_args)? } }; // Convert result back to VMValue let result_val = VMValue::from_nyash_box(result); if debug_boxcall { self.debug_log_boxcall(&recv, method, &[], "END", Some(&result_val)); } if let Some(dst_id) = dst { self.set_value(dst_id, result_val); } Ok(ControlFlow::Continue) } }