252 lines
6.9 KiB
Rust
252 lines
6.9 KiB
Rust
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<jint>),
|
|
Byte(PrimitiveArrayReference<jbyte>),
|
|
Short(PrimitiveArrayReference<jshort>),
|
|
Long(PrimitiveArrayReference<jlong>),
|
|
Float(PrimitiveArrayReference<jfloat>),
|
|
Double(PrimitiveArrayReference<jdouble>),
|
|
Char(PrimitiveArrayReference<jchar>),
|
|
Boolean(PrimitiveArrayReference<jboolean>),
|
|
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<RuntimeClass> {
|
|
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::<jint>(),
|
|
ArrayReference::Byte(x) => x.lock().backing.len() * size_of::<jbyte>(),
|
|
ArrayReference::Short(x) => x.lock().backing.len() * size_of::<jshort>(),
|
|
ArrayReference::Long(x) => x.lock().backing.len() * size_of::<jlong>(),
|
|
ArrayReference::Float(x) => x.lock().backing.len() * size_of::<jfloat>(),
|
|
ArrayReference::Double(x) => x.lock().backing.len() * size_of::<jdouble>(),
|
|
ArrayReference::Char(x) => x.lock().backing.len() * size_of::<jchar>(),
|
|
ArrayReference::Boolean(x) => x.lock().backing.len() * size_of::<jboolean>(),
|
|
ArrayReference::Object(x) => x.lock().backing.len() * size_of::<Reference>(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type PrimitiveArrayReference<T: Primitive> = Arc<Mutex<Array<T>>>;
|
|
|
|
pub type ObjectArrayReference = Arc<Mutex<Array<Option<ReferenceKind>>>>;
|
|
|
|
#[derive(Debug)]
|
|
pub struct Array<T: ArrayValue> {
|
|
pub(crate) id: u32,
|
|
pub(crate) class: Arc<RuntimeClass>,
|
|
pub backing: Box<[T]>,
|
|
}
|
|
|
|
impl<T> Array<T>
|
|
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<RuntimeClass>, 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<RuntimeClass>, Box<[T]>)) -> Self {
|
|
// let (id, class, vector) = value;
|
|
// Self {
|
|
// id,
|
|
// class,
|
|
// backing: vector,
|
|
// }
|
|
// }
|
|
}
|
|
|
|
impl<T: ArrayValue> From<(u32, Arc<RuntimeClass>, Box<[T]>)> for Array<T> {
|
|
fn from(value: (u32, Arc<RuntimeClass>, Box<[T]>)) -> Self {
|
|
let (id, class, values) = value;
|
|
Self {
|
|
id,
|
|
class,
|
|
backing: values,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ArrayValue> Deref for Array<T> {
|
|
type Target = [T];
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.backing
|
|
}
|
|
}
|
|
|
|
impl<T: ArrayValue> DerefMut for Array<T> {
|
|
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::<Vec<_>>()
|
|
} 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())),
|
|
}
|
|
}
|
|
}
|