new implementation using Arc<UnsafeCell>

This commit is contained in:
Sander Hautvast 2023-10-01 22:22:17 +02:00
parent 1bef6d6caa
commit 2b50279c07
3 changed files with 81 additions and 74 deletions

View file

@ -1,10 +1,11 @@
use std::cell::RefCell; use std::cell::{RefCell, UnsafeCell};
use crate::classloader::CpEntry; use crate::classloader::CpEntry;
use crate::heap::Object; use crate::heap::Object;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use crate::io::read_u16; use crate::io::read_u16;
@ -264,7 +265,7 @@ pub enum Value {
F64(f64), F64(f64),
BOOL(bool), BOOL(bool),
CHAR(char), CHAR(char),
Ref(Rc<RefCell<Object>>), Ref(Arc<UnsafeCell<Object>>),
} }
unsafe impl Send for Value {} unsafe impl Send for Value {}

View file

@ -1,15 +1,16 @@
use std::cell::RefCell; use std::cell::{RefCell, UnsafeCell};
use crate::class::{Class, Value}; use crate::class::{Class, Value};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use crate::classloader::CpEntry; use crate::classloader::CpEntry;
pub struct Object { pub struct Object {
// locked: bool, // locked: bool,
// hashcode: i32, // hashcode: i32,
pub class: Rc<Class>, pub class: Rc<Class>,
pub data: HashMap<u16, Rc<RefCell<Value>>>, //TODO optimize pub data: HashMap<u16, Arc<UnsafeCell<Value>>>, //TODO optimize
} }
unsafe impl Send for Object {} unsafe impl Send for Object {}
@ -17,7 +18,7 @@ unsafe impl Send for Object {}
unsafe impl Sync for Object {} unsafe impl Sync for Object {}
impl Object { impl Object {
pub fn new(class: Rc<Class>, data: HashMap<u16, Rc<RefCell<Value>>>) -> Self { pub fn new(class: Rc<Class>, data: HashMap<u16, Arc<UnsafeCell<Value>>>) -> Self {
Self { class, data } Self { class, data }
} }
@ -27,6 +28,10 @@ impl Object {
} }
panic!() panic!()
} }
unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
unsafe { &mut *ptr.get() }
}
} }
impl fmt::Debug for Object { impl fmt::Debug for Object {
@ -47,7 +52,7 @@ impl fmt::Debug for Object {
} }
pub(crate) struct Heap { pub(crate) struct Heap {
objects: Vec<Rc<RefCell<Object>>>, objects: Vec<Arc<UnsafeCell<Object>>>,
} }
impl Heap { impl Heap {
@ -55,7 +60,7 @@ impl Heap {
Self { objects: vec![] } Self { objects: vec![] }
} }
pub(crate) fn new_object(&mut self, object: Rc<RefCell<Object>>) { pub(crate) fn new_object(&mut self, object: Arc<UnsafeCell<Object>>) {
self.objects.push(object); self.objects.push(object);
} }
} }

135
src/vm.rs
View file

@ -1,7 +1,8 @@
use std::cell::RefCell; use std::cell::{RefCell, UnsafeCell};
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
@ -15,7 +16,7 @@ use crate::opcodes::*;
#[derive(Debug)] #[derive(Debug)]
struct StackFrame { struct StackFrame {
at: String, at: String,
data: Vec<Rc<RefCell<Value>>>, data: Vec<Arc<UnsafeCell<Value>>>,
} }
impl StackFrame { impl StackFrame {
@ -26,11 +27,11 @@ impl StackFrame {
Self { at, data: vec![] } Self { at, data: vec![] }
} }
fn push(&mut self, val: Rc<RefCell<Value>>) { fn push(&mut self, val: Arc<UnsafeCell<Value>>) {
self.data.push(val); self.data.push(val);
} }
fn pop(&mut self) -> Result<Rc<RefCell<Value>>, Error> { fn pop(&mut self) -> Result<Arc<UnsafeCell<Value>>, Error> {
Ok(self.data.pop().unwrap()) Ok(self.data.pop().unwrap())
} }
} }
@ -92,7 +93,7 @@ impl Vm {
"L" => Value::Null, "L" => Value::Null,
_ => Value::Void, _ => Value::Void,
}; };
data.insert(f.name_index, Rc::new(RefCell::new(value))); data.insert(f.name_index, Arc::new(UnsafeCell::new(value)));
} }
Object::new(class.clone(), data) Object::new(class.clone(), data)
} }
@ -102,8 +103,8 @@ impl Vm {
&mut self, &mut self,
class_name: &str, class_name: &str,
method_name: &str, method_name: &str,
args: Vec<Rc<RefCell<Value>>>, args: Vec<Arc<UnsafeCell<Value>>>,
) -> Result<Rc<RefCell<Value>>, Error> { ) -> Result<Arc<UnsafeCell<Value>>, Error> {
println!("execute {}.{}", class_name, method_name); println!("execute {}.{}", class_name, method_name);
let class = self.get_class(class_name)?; let class = self.get_class(class_name)?;
let method = class.get_method(method_name)?; let method = class.get_method(method_name)?;
@ -120,7 +121,7 @@ impl Vm {
BIPUSH => { BIPUSH => {
println!("BISPUSH"); println!("BISPUSH");
let c = code.opcodes[pc] as i32; let c = code.opcodes[pc] as i32;
self.local_stack().push(Rc::new(RefCell::new(Value::I32(c)))); self.local_stack().push(Arc::new(UnsafeCell::new(Value::I32(c))));
pc += 1; pc += 1;
} }
LDC => { LDC => {
@ -128,10 +129,10 @@ impl Vm {
let cp_index = read_u8(&code.opcodes, pc) as u16; let cp_index = read_u8(&code.opcodes, pc) as u16;
match method.constant_pool.get(&cp_index).unwrap() { match method.constant_pool.get(&cp_index).unwrap() {
CpEntry::Integer(i) => { CpEntry::Integer(i) => {
self.local_stack().push(Rc::new(RefCell::new(Value::I32(*i)))); self.local_stack().push(Arc::new(UnsafeCell::new(Value::I32(*i))));
} }
CpEntry::Float(f) => { CpEntry::Float(f) => {
self.local_stack().push(Rc::new(RefCell::new(Value::F32(*f)))); self.local_stack().push(Arc::new(UnsafeCell::new(Value::F32(*f))));
} }
_ => {} _ => {}
} }
@ -141,10 +142,10 @@ impl Vm {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
match method.constant_pool.get(&cp_index).unwrap() { match method.constant_pool.get(&cp_index).unwrap() {
CpEntry::Integer(i) => { CpEntry::Integer(i) => {
self.local_stack().push(Rc::new(RefCell::new(Value::I32(*i)))); self.local_stack().push(Arc::new(UnsafeCell::new(Value::I32(*i))));
} }
CpEntry::Float(f) => { CpEntry::Float(f) => {
self.local_stack().push(Rc::new(RefCell::new(Value::F32(*f)))); self.local_stack().push(Arc::new(UnsafeCell::new(Value::F32(*f))));
} }
_ => { _ => {
panic!("unexpected") panic!("unexpected")
@ -156,10 +157,10 @@ impl Vm {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
match method.constant_pool.get(&cp_index).unwrap() { match method.constant_pool.get(&cp_index).unwrap() {
CpEntry::Double(d) => { CpEntry::Double(d) => {
self.local_stack().push(Rc::new(RefCell::new(Value::F64(*d)))); self.local_stack().push(Arc::new(UnsafeCell::new(Value::F64(*d))));
} }
CpEntry::Long(l) => { CpEntry::Long(l) => {
self.local_stack().push(Rc::new(RefCell::new(Value::I64(*l)))); self.local_stack().push(Arc::new(UnsafeCell::new(Value::I64(*l))));
} }
_ => { _ => {
panic!("unexpected") panic!("unexpected")
@ -222,22 +223,22 @@ impl Vm {
RETURN_VOID => { RETURN_VOID => {
println!("return"); println!("return");
self.stack.pop(); self.stack.pop();
return Ok(Rc::new(RefCell::new(Void))); return Ok(Arc::new(UnsafeCell::new(Void)));
} }
GETFIELD => { GETFIELD => {
println!("GETFIELD"); println!("GETFIELD");
let cp_index = read_u16(&code.opcodes, pc); unsafe {
if let CpEntry::Fieldref(_class_index, name_and_type_index) = let cp_index = read_u16(&code.opcodes, pc);
method.constant_pool.get(&cp_index).unwrap() if let CpEntry::Fieldref(_class_index, name_and_type_index) =
{ method.constant_pool.get(&cp_index).unwrap()
if let Value::Ref(instance) = self.local_stack().pop()?.borrow().deref() { {
//TODO smell? if let Value::Ref(instance) = &*self.local_stack().pop()?.get() {
if let CpEntry::NameAndType(name, _) = if let CpEntry::NameAndType(name, _) =
method.constant_pool.get(name_and_type_index).unwrap() method.constant_pool.get(name_and_type_index).unwrap()
{ {
let borrow = instance.borrow(); let value = (*(instance.deref()).get()).data.get(name).unwrap();
let value = borrow.data.get(name).unwrap(); self.local_stack().push(Arc::clone(value));
self.local_stack().push(Rc::clone(value)); }
} }
} }
} }
@ -245,17 +246,17 @@ impl Vm {
} }
PUTFIELD => { PUTFIELD => {
println!("PUTFIELD"); println!("PUTFIELD");
let cp_index = read_u16(&code.opcodes, pc); unsafe {
if let CpEntry::Fieldref(_class_index, name_and_type_index) = let cp_index = read_u16(&code.opcodes, pc);
method.constant_pool.get(&cp_index).unwrap() if let CpEntry::Fieldref(_class_index, name_and_type_index) =
{ method.constant_pool.get(&cp_index).unwrap()
if let CpEntry::NameAndType(name_index, _) = method.constant_pool.get(name_and_type_index).unwrap() { {
let value = self.local_stack().pop()?; if let CpEntry::NameAndType(name_index, _) = method.constant_pool.get(name_and_type_index).unwrap() {
let objectref = self.local_stack().pop()?; let value = self.local_stack().pop()?;
let mut b = objectref.borrow_mut(); let mut objectref = &*self.local_stack().pop()?.get();
let b = b.deref_mut(); if let Value::Ref(instance) = objectref {
if let Value::Ref(object) = b { (*(instance.deref()).get()).data.insert(*name_index, value);
object.borrow_mut().data.insert(*name_index, value); }
} }
} }
} }
@ -263,43 +264,43 @@ impl Vm {
} }
INVOKEVIRTUAL => { INVOKEVIRTUAL => {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
if let Some((class, method)) = get_signature_for_invoke(Rc::clone(&method.constant_pool), cp_index) { unsafe {
let signature = method.0.as_str(); if let Some((class, method)) = get_signature_for_invoke(Rc::clone(&method.constant_pool), cp_index) {
let num_args = method.1; let signature = method.0.as_str();
let mut args = Vec::with_capacity(num_args); let num_args = method.1;
for _ in 0..num_args { let mut args = Vec::with_capacity(num_args);
for _ in 0..num_args {
args.insert(0, self.local_stack().pop()?);
}
args.insert(0, self.local_stack().pop()?); args.insert(0, self.local_stack().pop()?);
} let mut returnvalue = self.execute(class.as_str(), signature, args)?;
args.insert(0, self.local_stack().pop()?); match *returnvalue.get() {
let return_value = self.execute(class.as_str(), signature, args)?; Void => {}
let borrow = return_value.borrow(); _ => { self.local_stack().push(returnvalue.clone()); }
match borrow.deref() { }
&Void => {}
_ => { self.local_stack().push(return_value.clone()); }
} }
} }
pc += 2; pc += 2;
} }
INVOKESPECIAL => { INVOKESPECIAL => {
println!("INVOKESPECIAL"); println!("INVOKESPECIAL");
let cp_index = read_u16(&code.opcodes, pc); unsafe {
if let Some((class, method)) = get_signature_for_invoke(Rc::clone(&method.constant_pool), cp_index) { let cp_index = read_u16(&code.opcodes, pc);
let signature = method.0.as_str(); if let Some((class, method)) = get_signature_for_invoke(Rc::clone(&method.constant_pool), cp_index) {
let num_args = method.1; let signature = method.0.as_str();
let mut args = vec![]; let num_args = method.1;
for _ in 0..num_args { let mut args = vec![];
for _ in 0..num_args {
args.insert(0, self.local_stack().pop()?);
}
args.insert(0, self.local_stack().pop()?); args.insert(0, self.local_stack().pop()?);
} let mut returnvalue = self.execute(class.as_str(), signature, args)?;
args.insert(0, self.local_stack().pop()?); match *returnvalue.get() {
let return_value = self.execute(class.as_str(), signature, args)?; Void => {}
let borrow = return_value.borrow(); _ => { self.local_stack().push(returnvalue.clone()); }
match borrow.deref() { }
&Void => {}
_ => { self.local_stack().push(return_value.clone()); }
} }
} }
pc += 2; pc += 2;
} }
NEW => { NEW => {
@ -313,8 +314,8 @@ impl Vm {
{ {
println!("new {}", new_class); println!("new {}", new_class);
let class = self.get_class(new_class)?; let class = self.get_class(new_class)?;
let object = Rc::new(RefCell::new(self.new_instance(class))); let object = Arc::new(UnsafeCell::new(self.new_instance(class)));
self.local_stack().push(Rc::new(RefCell::new(Value::Ref(Rc::clone(&object))))); self.local_stack().push(Arc::new(UnsafeCell::new(Value::Ref(Arc::clone(&object)))));
self.heap.new_object(object); self.heap.new_object(object);
} }
} }