use crate::class::RuntimeClass; use crate::error::VmError; use crate::objects::object::{Reference, ReferenceKind}; use crate::prim::Primitive; use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort}; use parking_lot::Mutex; use std::ops::{Deref, DerefMut}; use std::sync::Arc; #[derive(Debug, Clone)] pub enum ArrayReference { Int(PrimitiveArrayReference), Byte(PrimitiveArrayReference), Short(PrimitiveArrayReference), Long(PrimitiveArrayReference), Float(PrimitiveArrayReference), Double(PrimitiveArrayReference), Char(PrimitiveArrayReference), Boolean(PrimitiveArrayReference), Object(ObjectArrayReference), } impl ArrayReference { pub fn len(&self) -> jint { match self { ArrayReference::Int(x) => x.lock().len(), ArrayReference::Byte(x) => x.lock().len(), ArrayReference::Short(x) => x.lock().len(), ArrayReference::Long(x) => x.lock().len(), ArrayReference::Float(x) => x.lock().len(), ArrayReference::Double(x) => x.lock().len(), ArrayReference::Char(x) => x.lock().len(), ArrayReference::Boolean(x) => x.lock().len(), ArrayReference::Object(x) => x.lock().len(), } } pub fn id(&self) -> u32 { match self { ArrayReference::Int(x) => x.lock().id, ArrayReference::Byte(x) => x.lock().id, ArrayReference::Short(x) => x.lock().id, ArrayReference::Long(x) => x.lock().id, ArrayReference::Float(x) => x.lock().id, ArrayReference::Double(x) => x.lock().id, ArrayReference::Char(x) => x.lock().id, ArrayReference::Boolean(x) => x.lock().id, ArrayReference::Object(x) => x.lock().id, } } pub fn class(&self) -> Arc { match self { ArrayReference::Int(x) => x.lock().class.clone(), ArrayReference::Byte(x) => x.lock().class.clone(), ArrayReference::Short(x) => x.lock().class.clone(), ArrayReference::Long(x) => x.lock().class.clone(), ArrayReference::Float(x) => x.lock().class.clone(), ArrayReference::Double(x) => x.lock().class.clone(), ArrayReference::Char(x) => x.lock().class.clone(), ArrayReference::Boolean(x) => x.lock().class.clone(), ArrayReference::Object(x) => x.lock().class.clone(), } } /// Returns the size in bytes of the array's backing storage pub fn size_bytes(&self) -> usize { match self { ArrayReference::Int(x) => x.lock().backing.len() * size_of::(), ArrayReference::Byte(x) => x.lock().backing.len() * size_of::(), ArrayReference::Short(x) => x.lock().backing.len() * size_of::(), ArrayReference::Long(x) => x.lock().backing.len() * size_of::(), ArrayReference::Float(x) => x.lock().backing.len() * size_of::(), ArrayReference::Double(x) => x.lock().backing.len() * size_of::(), ArrayReference::Char(x) => x.lock().backing.len() * size_of::(), ArrayReference::Boolean(x) => x.lock().backing.len() * size_of::(), ArrayReference::Object(x) => x.lock().backing.len() * size_of::(), } } } pub type PrimitiveArrayReference = Arc>>; pub type ObjectArrayReference = Arc>>>; #[derive(Debug)] pub struct Array { pub(crate) id: u32, pub(crate) class: Arc, pub backing: Box<[T]>, } impl Array where T: ArrayValue + Clone + Default, { pub fn set(&mut self, index: i32, value: T) { self.backing[index as usize] = value } pub fn get(&self, index: i32) -> T { self.backing[index as usize].clone() } pub fn new(id: u32, class: Arc, length: i32) -> Self { Self { id, class, backing: vec![T::default(); length as usize].into_boxed_slice(), } } pub fn len(&self) -> jint { self.backing.len() as jint } // fn from(value: (u32, Arc, Box<[T]>)) -> Self { // let (id, class, vector) = value; // Self { // id, // class, // backing: vector, // } // } } impl From<(u32, Arc, Box<[T]>)> for Array { fn from(value: (u32, Arc, Box<[T]>)) -> Self { let (id, class, values) = value; Self { id, class, backing: values, } } } impl Deref for Array { type Target = [T]; fn deref(&self) -> &Self::Target { &self.backing } } impl DerefMut for Array { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.backing } } pub trait ArrayValue {} impl ArrayValue for Reference {} impl ArrayValue for jbyte {} impl ArrayValue for jshort {} impl ArrayValue for jint {} impl ArrayValue for jlong {} impl ArrayValue for jchar {} impl ArrayValue for jfloat {} impl ArrayValue for jdouble {} impl ArrayValue for jboolean {} impl ArrayReference { pub fn copy_from( &self, src: &ArrayReference, src_pos: jint, dst_pos: jint, length: jint, ) -> Result<(), VmError> { macro_rules! copy { ($src_arr:expr, $dst_arr:expr) => {{ let src_guard = $src_arr.lock(); let mut dst_guard = $dst_arr.lock(); let src_start = src_pos as usize; let dst_start = dst_pos as usize; let len = length as usize; // Bounds check if src_pos < 0 || dst_pos < 0 || length < 0 || src_start + len > src_guard.backing.len() || dst_start + len > dst_guard.backing.len() { return Err(VmError::InvariantError("Index oob".to_string())); } if Arc::ptr_eq($src_arr, $dst_arr) { drop(src_guard); dst_guard .backing .copy_within(src_start..src_start + len, dst_start); } else { dst_guard.backing[dst_start..dst_start + len] .copy_from_slice(&src_guard.backing[src_start..src_start + len]); } Ok(()) }}; } use ArrayReference::*; match (src, self) { (Int(s), Int(d)) => copy!(s, d), (Byte(s), Byte(d)) => copy!(s, d), (Short(s), Short(d)) => copy!(s, d), (Long(s), Long(d)) => copy!(s, d), (Float(s), Float(d)) => copy!(s, d), (Double(s), Double(d)) => copy!(s, d), (Char(s), Char(d)) => copy!(s, d), (Boolean(s), Boolean(d)) => copy!(s, d), (Object(s), Object(d)) => { // Object arrays need clone, not copy let src_guard = s.lock(); let mut dst_guard = d.lock(); let src_start = src_pos as usize; let dst_start = dst_pos as usize; let len = length as usize; if src_pos < 0 || dst_pos < 0 || length < 0 || src_start + len > src_guard.backing.len() || dst_start + len > dst_guard.backing.len() { return Err(VmError::InvariantError("Index oob".to_string())); } if Arc::ptr_eq(s, d) { drop(src_guard); for i in if src_start < dst_start { (0..len).rev().collect::>() } else { (0..len).collect() } { dst_guard.backing[dst_start + i] = dst_guard.backing[src_start + i].clone(); } } else { for i in 0..len { dst_guard.backing[dst_start + i] = src_guard.backing[src_start + i].clone(); } } Ok(()) } _ => Err(VmError::InvariantError("Array type mismatch".to_string())), } } }