Skip to content

Commit

Permalink
Rework heap to make it a thread-safe singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Oct 6, 2024
1 parent 46b9204 commit 1d11224
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 62 deletions.
91 changes: 48 additions & 43 deletions vm/src/execution_engine/engine.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::Error;
use crate::execution_engine::opcode::*;
use crate::execution_engine::system_native_table::invoke_native_method;
use crate::heap::heap::Heap;
use crate::heap::heap::{with_heap_read_lock, with_heap_write_lock};
use crate::method_area::java_method::JavaMethod;
use crate::method_area::method_area::MethodArea;
use crate::stack::stack_frame::{i32toi64, StackFrame};
Expand All @@ -11,12 +11,11 @@ use std::rc::Rc;

pub(crate) struct Engine {
method_area: Rc<RefCell<MethodArea>>,
heap: Rc<RefCell<Heap>>,
}

impl Engine {
pub fn new(method_area: Rc<RefCell<MethodArea>>, heap: Rc<RefCell<Heap>>) -> Self {
Self { method_area, heap }
pub fn new(method_area: Rc<RefCell<MethodArea>>) -> Self {
Self { method_area }
}

pub(crate) fn execute(
Expand Down Expand Up @@ -269,8 +268,9 @@ impl Engine {
IALOAD => {
let index = stack_frame.pop();
let arrayref = stack_frame.pop();
let heap = self.heap.borrow();
let value = heap.get_array_value(arrayref, index)?;
let value = with_heap_read_lock(|heap| {
heap.get_array_value(arrayref, index).cloned()
})?;

stack_frame.push(value[0]);
stack_frame.incr_pc();
Expand All @@ -282,8 +282,9 @@ impl Engine {
LALOAD => {
let index = stack_frame.pop();
let arrayref = stack_frame.pop();
let heap = self.heap.borrow();
let value = heap.get_array_value(arrayref, index)?;
let value = with_heap_read_lock(|heap| {
heap.get_array_value(arrayref, index).cloned()
})?;

let high = value[0];
let low = value[1];
Expand All @@ -296,8 +297,9 @@ impl Engine {
AALOAD => {
let index = stack_frame.pop();
let arrayref = stack_frame.pop();
let heap = self.heap.borrow();
let objref = heap.get_array_value(arrayref, index)?;
let objref = with_heap_read_lock(|heap| {
heap.get_array_value(arrayref, index).cloned()
})?;

stack_frame.push(objref[0]);
stack_frame.incr_pc();
Expand Down Expand Up @@ -433,9 +435,9 @@ impl Engine {
let index = stack_frame.pop();
let arrayref = stack_frame.pop();

self.heap
.borrow_mut()
.set_array_value(arrayref, index, vec![value])?;
with_heap_write_lock(|heap| {
heap.set_array_value(arrayref, index, vec![value])
})?;

stack_frame.incr_pc();
println!("IASTORE -> arrayref={arrayref}, index={index}, value={value}");
Expand All @@ -448,9 +450,9 @@ impl Engine {
let index = stack_frame.pop();
let arrayref = stack_frame.pop();

self.heap
.borrow_mut()
.set_array_value(arrayref, index, value.clone())?;
with_heap_write_lock(|heap| {
heap.set_array_value(arrayref, index, value.clone())
})?;

stack_frame.incr_pc();
println!("LASTORE -> arrayref={arrayref}, index={index}, value={value:?}");
Expand All @@ -460,9 +462,9 @@ impl Engine {
let index = stack_frame.pop();
let arrayref = stack_frame.pop();

self.heap
.borrow_mut()
.set_array_value(arrayref, index, vec![objref])?;
with_heap_write_lock(|heap| {
heap.set_array_value(arrayref, index, vec![objref])
})?;

stack_frame.incr_pc();
println!("AASTORE -> arrayref={arrayref}, index={index}, objref={objref}");
Expand Down Expand Up @@ -823,12 +825,14 @@ impl Engine {
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting full field info by index {fieldref_constpool_index}")))?;
let field_name_type = format!("{field_name}:{field_descriptor}");

let mut heap = self.heap.borrow_mut();
let value = heap.get_object_field_value(
objectref,
class_name.as_str(),
field_name_type.as_str(),
)?;
let value = with_heap_write_lock(|heap| {
heap.get_object_field_value(
objectref,
class_name.as_str(),
field_name_type.as_str(),
)
.cloned()
})?;

value.iter().rev().for_each(|x| stack_frame.push(*x));

Expand Down Expand Up @@ -863,12 +867,14 @@ impl Engine {

let objectref = stack_frame.pop();

self.heap.borrow_mut().set_object_field_value(
objectref,
class_name.as_str(),
field_name_type.as_str(),
value.clone(),
)?;
with_heap_write_lock(|heap| {
heap.set_object_field_value(
objectref,
class_name.as_str(),
field_name_type.as_str(),
value.clone(),
)
})?;

println!("PUTFIELD -> objectref={objectref}, class_name={class_name}, field_name_type={field_name_type} value={value:?}");
stack_frame.incr_pc();
Expand Down Expand Up @@ -902,8 +908,8 @@ impl Engine {
method_args.push(reference);
method_args.reverse();

let heap = self.heap.borrow();
let instance_type_class_name = heap.get_instance_name(reference)?;
let instance_type_class_name =
with_heap_read_lock(|heap| heap.get_instance_name(reference))?;

let virtual_method = method_area.lookup_for_implementation(&instance_type_class_name, &full_signature)
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting instance type JavaMethod by class name {instance_type_class_name} and full signature {full_signature} invoking virtual")))?;
Expand Down Expand Up @@ -1040,11 +1046,11 @@ impl Engine {
.get_full_interfacemethodref_info(interfacemethodref_constpool_index)
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting full interfacemethodref info by index {interfacemethodref_constpool_index}")))?;

let heap = self.heap.borrow();
let instance_name = heap.get_instance_name(reference)?;
let instance_name =
with_heap_read_lock(|heap| heap.get_instance_name(reference))?;

let full_method_signature = format!("{method_name}:{method_descriptor}");
let interface_implementation_method = method_area.lookup_for_implementation(instance_name, &full_method_signature)
let interface_implementation_method = method_area.lookup_for_implementation(&instance_name, &full_method_signature)
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting implementaion of {interface_class_name}.{method_name}{method_descriptor} in {instance_name}")))?;

let mut next_frame = interface_implementation_method.new_stack_frame()?;
Expand Down Expand Up @@ -1076,10 +1082,9 @@ impl Engine {
.borrow()
.create_instance_with_default_fields(&class_to_invoke_new_for);

let instanceref = self
.heap
.borrow_mut()
.create_instance(instance_with_default_fields);
let instanceref = with_heap_write_lock(|heap| {
heap.create_instance(instance_with_default_fields)
});
stack_frame.push(instanceref);

println!("NEW -> class={class_to_invoke_new_for}, reference={instanceref}");
Expand All @@ -1091,7 +1096,7 @@ impl Engine {

let length = stack_frame.pop();

let arrayref = self.heap.borrow_mut().create_array(length);
let arrayref = with_heap_write_lock(|heap| heap.create_array(length));
stack_frame.push(arrayref);

stack_frame.incr_pc();
Expand All @@ -1111,7 +1116,7 @@ impl Engine {
"Error getting class name by index {class_constpool_index}"
))
})?;
let arrayref = self.heap.borrow_mut().create_array(length);
let arrayref = with_heap_write_lock(|heap| heap.create_array(length));
stack_frame.push(arrayref);

stack_frame.incr_pc();
Expand All @@ -1120,7 +1125,7 @@ impl Engine {
ARRAYLENGTH => {
let arrayref = stack_frame.pop();

let len = self.heap.borrow().get_array_len(arrayref)?;
let len = with_heap_read_lock(|heap| heap.get_array_len(arrayref))?;
stack_frame.push(len);

stack_frame.incr_pc();
Expand Down
26 changes: 23 additions & 3 deletions vm/src/heap/heap.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
use crate::error::Error;
use crate::heap::java_instance::HeapValue::{Arr, Object};
use crate::heap::java_instance::{Array, HeapValue, JavaInstance};
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::sync::RwLock;

static HEAP: Lazy<RwLock<Heap>> = Lazy::new(|| RwLock::new(Heap::new()));

pub(crate) fn with_heap_read_lock<F, R>(f: F) -> R
where
F: FnOnce(&Heap) -> R,
{
let heap = HEAP.read().expect("error getting heap read lock");
f(&heap)
}

pub(crate) fn with_heap_write_lock<F, R>(f: F) -> R
where
F: FnOnce(&mut Heap) -> R,
{
let mut heap = HEAP.write().expect("error getting heap write lock");
f(&mut heap)
}

#[derive(Debug)]
pub(crate) struct Heap {
Expand All @@ -10,7 +30,7 @@ pub(crate) struct Heap {
}

impl Heap {
pub fn new() -> Self {
fn new() -> Self {
Self {
data: HashMap::new(),
next_id: 0,
Expand Down Expand Up @@ -53,9 +73,9 @@ impl Heap {
}
}

pub fn get_instance_name(&self, objectref: i32) -> crate::error::Result<&str> {
pub fn get_instance_name(&self, objectref: i32) -> crate::error::Result<String> {
if let Some(Object(java_instance)) = self.data.get(&objectref) {
Ok(java_instance.instance_name())
Ok(java_instance.instance_name().to_string())
} else {
Err(Error::new_execution(&format!(
"error getting object from heap by ref {objectref}"
Expand Down
6 changes: 1 addition & 5 deletions vm/src/method_area/java_class.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::error::Error;
use crate::execution_engine::engine::Engine;
use crate::heap::heap::Heap;
use crate::heap::java_instance::FieldNameType;
use crate::method_area::cpool_helper::CPoolHelper;
use crate::method_area::field::Field;
Expand All @@ -23,7 +22,6 @@ pub(crate) struct JavaClass {
_interfaces: Vec<String>,

static_fields_initialized: AtomicBool,
heap: Rc<RefCell<Heap>>,
method_area: Rc<RefCell<MethodArea>>,
}

Expand Down Expand Up @@ -65,7 +63,6 @@ impl JavaClass {
this_class_name: String,
parent: Option<String>,
interfaces: Vec<String>,
heap: Rc<RefCell<Heap>>,
method_area: Rc<RefCell<MethodArea>>,
) -> Self {
Self {
Expand All @@ -77,7 +74,6 @@ impl JavaClass {
parent,
_interfaces: interfaces,
static_fields_initialized: AtomicBool::new(false),
heap,
method_area,
}
}
Expand Down Expand Up @@ -122,7 +118,7 @@ impl JavaClass {
self.this_class_name,
Self::STATIC_INIT_METHOD
);
let mut engine = Engine::new(Rc::clone(&self.method_area), Rc::clone(&self.heap));
let mut engine = Engine::new(Rc::clone(&self.method_area));
engine.execute(static_init_method)?;
println!(
"<RETURN> -> {}.{}",
Expand Down
6 changes: 1 addition & 5 deletions vm/src/method_area/method_area.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::error::{Error, ErrorKind};
use crate::heap::heap::Heap;
use crate::heap::java_instance::{ClassName, FieldNameType, JavaInstance};
use crate::method_area::attributes_helper::AttributesHelper;
use crate::method_area::cpool_helper::CPoolHelper;
Expand All @@ -22,16 +21,14 @@ use std::rc::{Rc, Weak};
pub(crate) struct MethodArea {
std_dir: String,
pub(crate) loaded_classes: RefCell<HashMap<String, Rc<JavaClass>>>,
heap: Rc<RefCell<Heap>>,
self_ref: RefCell<Weak<RefCell<MethodArea>>>,
}

impl MethodArea {
pub fn new(std_dir: &str, heap: Rc<RefCell<Heap>>) -> Rc<RefCell<Self>> {
pub fn new(std_dir: &str) -> Rc<RefCell<Self>> {
let method_area = Rc::new(RefCell::new(MethodArea {
std_dir: std_dir.to_string(),
loaded_classes: RefCell::new(HashMap::new()),
heap,
self_ref: RefCell::new(Weak::new()),
}));

Expand Down Expand Up @@ -148,7 +145,6 @@ impl MethodArea {
class_name,
super_class_name,
interface_names,
Rc::clone(&self.heap),
Rc::clone(&method_area),
)),
))
Expand Down
8 changes: 2 additions & 6 deletions vm/src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
use crate::error::Error;
use crate::execution_engine::engine::Engine;
use crate::heap::heap::Heap;
use crate::method_area::method_area::MethodArea;
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Debug)]
pub struct VM {
method_area: Rc<RefCell<MethodArea>>,
heap: Rc<RefCell<Heap>>,
}

impl VM {
const ENTRY_POINT: &'static str = "main:([Ljava/lang/String;)V";

pub fn new(std_dir: &str) -> Self {
let heap = Rc::new(RefCell::new(Heap::new()));
Self {
method_area: MethodArea::new(std_dir, Rc::clone(&heap)),
heap,
method_area: MethodArea::new(std_dir),
}
}

Expand All @@ -34,7 +30,7 @@ impl VM {
format!("main method not found in {main_class_name}").as_str(),
))?;

let mut engine = Engine::new(Rc::clone(&self.method_area), Rc::clone(&self.heap));
let mut engine = Engine::new(Rc::clone(&self.method_area));

engine.execute(java_method)
}
Expand Down

0 comments on commit 1d11224

Please sign in to comment.