172 lines
5.2 KiB
Rust
172 lines
5.2 KiB
Rust
use std::cell::{RefCell, UnsafeCell};
|
|
use std::fmt;
|
|
use std::fmt::{Debug, Formatter};
|
|
use std::sync::Arc;
|
|
|
|
use crate::class::{Class, Type, UnsafeValue, Value};
|
|
use crate::heap::ObjectRef::{ByteArray, IntArray, ObjectArray};
|
|
|
|
// can contain object or array
|
|
pub enum ObjectRef {
|
|
ByteArray(Vec<i8>),
|
|
ShortArray(Vec<i16>),
|
|
IntArray(Vec<i32>),
|
|
LongArray(Vec<i64>),
|
|
FloatArray(Vec<f32>),
|
|
DoubleArray(Vec<f64>),
|
|
BooleanArray(Vec<bool>),
|
|
CharArray(Vec<char>),
|
|
ObjectArray(Type, Vec<Arc<UnsafeCell<ObjectRef>>>),
|
|
Object(Box<Object>),
|
|
}
|
|
|
|
fn into_vec_i8(v: Vec<u8>) -> Vec<i8> {
|
|
// ideally we'd use Vec::into_raw_parts, but it's unstable,
|
|
// so we have to do it manually:
|
|
|
|
// first, make sure v's destructor doesn't free the data
|
|
// it thinks it owns when it goes out of scope
|
|
let mut v = std::mem::ManuallyDrop::new(v);
|
|
|
|
// then, pick apart the existing Vec
|
|
let p = v.as_mut_ptr();
|
|
let len = v.len();
|
|
let cap = v.capacity();
|
|
|
|
// finally, adopt the data into a new Vec
|
|
unsafe { Vec::from_raw_parts(p as *mut i8, len, cap) }
|
|
}
|
|
|
|
impl ObjectRef {
|
|
pub fn new_object_array(class: Type, size: usize) -> Self {
|
|
ObjectArray(class, Vec::with_capacity(size))
|
|
}
|
|
|
|
pub fn new_int_array(size: usize) -> Self {
|
|
IntArray(Vec::with_capacity(size))
|
|
}
|
|
|
|
pub fn new_byte_array(d: Vec<u8>) -> Arc<UnsafeCell<Self>> {
|
|
Arc::new(UnsafeCell::new(ByteArray(into_vec_i8(d))))
|
|
}
|
|
}
|
|
|
|
impl Debug for ObjectRef{
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
ObjectRef::BooleanArray(d) => write!(f, "[Z;{}]", d.len()),
|
|
ObjectRef::ByteArray(d) => write!(f, "[B;{}]", d.len()),
|
|
ObjectRef::CharArray(d) => write!(f, "[C;{}]", d.len()),
|
|
ObjectRef::DoubleArray(d) => write!(f, "[D;{}]", d.len()),
|
|
ObjectRef::FloatArray(d) => write!(f, "[F;{}]", d.len()),
|
|
ObjectRef::IntArray(d) => write!(f, "[I;{}]", d.len()),
|
|
ObjectRef::LongArray(d) => write!(f, "[J;{}]", d.len()),
|
|
ObjectRef::ObjectArray(t, d) => write!(f,"[L{};{}]", t.borrow().name,d.len()),
|
|
ObjectRef::ShortArray( d) => write!(f, "[S;{}]", d.len()),
|
|
ObjectRef::Object( r) => write!(f,"{}{{ {:?} }}", r.class.borrow().name, r.data),
|
|
}
|
|
}
|
|
}
|
|
|
|
// trying to implement efficient object instance storage
|
|
pub struct Object {
|
|
// locked: bool,
|
|
// hashcode: i32,
|
|
pub class: Arc<RefCell<Class>>,
|
|
pub data: Vec<UnsafeValue>,
|
|
} //arrays
|
|
|
|
unsafe impl Send for Object {}
|
|
|
|
unsafe impl Sync for Object {}
|
|
|
|
// object, not array
|
|
impl Object {
|
|
pub fn new(class: Arc<RefCell<Class>>) -> Self {
|
|
let instance_data = Object::init_fields(class.clone());
|
|
Self {
|
|
class,
|
|
data: instance_data,
|
|
}
|
|
}
|
|
|
|
// initializes all non-static fields to their default values
|
|
pub(crate) fn init_fields(class: Arc<RefCell<Class>>) -> Vec<UnsafeValue> {
|
|
let mut field_data = Vec::with_capacity(class.borrow().n_object_fields());
|
|
|
|
for (_, fields) in &class.borrow().object_field_mapping {
|
|
for (_, (fieldtype, _)) in fields {
|
|
let value = match fieldtype.as_str() {
|
|
"Z" => Value::BOOL(false),
|
|
"B" => Value::I32(0),
|
|
"S" => Value::I32(0),
|
|
"I" => Value::I32(0),
|
|
"J" => Value::I64(0),
|
|
"F" => Value::F32(0.0),
|
|
"D" => Value::F64(0.0),
|
|
_ => Value::Null,
|
|
};
|
|
field_data.push(value.into());
|
|
}
|
|
}
|
|
|
|
field_data
|
|
}
|
|
|
|
pub fn set(&mut self, class_name: &String, field_name: &String, value: UnsafeValue) {
|
|
let borrow = self.class.borrow();
|
|
let (_type, index) = borrow
|
|
.object_field_mapping
|
|
.get(class_name)
|
|
.unwrap()
|
|
.get(field_name)
|
|
.unwrap();
|
|
self.data[*index] = value;
|
|
}
|
|
|
|
pub fn get(&mut self, class_name: &String, field_name: &String) -> &UnsafeValue {
|
|
let borrow = self.class.borrow();
|
|
let (_type, index) = borrow
|
|
.object_field_mapping
|
|
.get(class_name)
|
|
.unwrap()
|
|
.get(field_name)
|
|
.unwrap();
|
|
&self.data[*index]
|
|
}
|
|
|
|
// fn get_field_name(&self, cp_index: &u16) -> &str {
|
|
// if let CpEntry::Utf8(name) = self.class.constant_pool.get(cp_index).unwrap() {
|
|
// return name;
|
|
// }
|
|
// panic!()
|
|
// }
|
|
}
|
|
|
|
impl fmt::Debug for Object {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
// let fields: Vec<String> = self.data.unwrap().iter().map(|(k)| {
|
|
// // let mut r: String = self.get_field_name(k).into();
|
|
// // r.push(':');
|
|
// // r.push_str(format!("{:?}").as_str());
|
|
// // r
|
|
// }
|
|
// ).collect();
|
|
write!(f, "{}", self.class.borrow().name)
|
|
}
|
|
}
|
|
|
|
// will using Arc's enable a GC-less heap????
|
|
pub(crate) struct Heap {
|
|
objects: Vec<Arc<UnsafeCell<ObjectRef>>>,
|
|
}
|
|
|
|
impl Heap {
|
|
pub fn new() -> Self {
|
|
Self { objects: vec![] }
|
|
}
|
|
|
|
pub(crate) fn new_object(&mut self, object: Arc<UnsafeCell<ObjectRef>>) {
|
|
self.objects.push(object);
|
|
}
|
|
}
|