Skip to content

Commit

Permalink
Rework method area to make it a singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Oct 7, 2024
1 parent c2712fc commit e5ea3d2
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 136 deletions.
130 changes: 76 additions & 54 deletions vm/src/execution_engine/engine.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion vm/src/heap/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl Heap {
objectref: i32,
class_name: &str,
field_name_type: &str,
) -> crate::error::Result<&Vec<i32>> {
) -> crate::error::Result<Vec<i32>> {
if let Some(Object(java_instance)) = self.data.get(&objectref) {
java_instance.get_field_value(class_name, field_name_type)
} else {
Expand Down
2 changes: 1 addition & 1 deletion vm/src/heap/java_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl<'a> JavaInstance {
&self,
class_name: &str,
field_name_type: &str,
) -> crate::error::Result<&Vec<i32>> {
) -> crate::error::Result<Vec<i32>> {
self.lookup_for_field(class_name, field_name_type)
.and_then(|v| Some(v.raw_value()))
.ok_or(Error::new_execution(&format!(
Expand Down
21 changes: 15 additions & 6 deletions vm/src/method_area/field.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
use jdescriptor::{default_value, TypeDescriptor};
use std::sync::RwLock;

#[derive(Debug)]
pub(crate) struct Field {
type_descriptor: TypeDescriptor,
value: Vec<i32>,
value: RwLock<Vec<i32>>,
}

impl Field {
pub fn new(type_descriptor: TypeDescriptor) -> Self {
let value = default_value(&type_descriptor);
Self {
type_descriptor,
value,
value: RwLock::new(value),
}
}

pub fn set_raw_value(&mut self, value: Vec<i32>) {
self.value = value;
pub fn set_raw_value(&self, value: Vec<i32>) {
let mut guard = self
.value
.write()
.expect("error getting lock to set field value");
*guard = value;
}

pub fn raw_value(&self) -> &Vec<i32> {
&self.value
pub fn raw_value(&self) -> Vec<i32> {
let guard = self
.value
.read()
.expect("error getting lock to get field value");
guard.clone()
}

pub fn type_descriptor(&self) -> &TypeDescriptor {
Expand Down
21 changes: 8 additions & 13 deletions vm/src/method_area/java_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ use crate::heap::java_instance::FieldNameType;
use crate::method_area::cpool_helper::CPoolHelper;
use crate::method_area::field::Field;
use crate::method_area::java_method::JavaMethod;
use crate::method_area::method_area::MethodArea;
use jdescriptor::TypeDescriptor;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

#[derive(Debug)]
pub(crate) struct JavaClass {
Expand All @@ -22,17 +20,16 @@ pub(crate) struct JavaClass {
_interfaces: Vec<String>,

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

#[derive(Debug)]
pub(crate) struct Methods {
pub(crate) method_by_signature: HashMap<String, Rc<JavaMethod>>,
pub(crate) method_by_signature: HashMap<String, Arc<JavaMethod>>,
}

#[derive(Debug)]
pub(crate) struct Fields {
pub(crate) field_by_name: HashMap<String, Rc<RefCell<Field>>>,
pub(crate) field_by_name: HashMap<String, Arc<Field>>,
}

#[derive(Debug)]
Expand All @@ -47,7 +44,7 @@ impl FieldDescriptors {
}

impl Fields {
pub fn new(field_by_name: HashMap<String, Rc<RefCell<Field>>>) -> Self {
pub fn new(field_by_name: HashMap<String, Arc<Field>>) -> Self {
Self { field_by_name }
}
}
Expand All @@ -63,7 +60,6 @@ impl JavaClass {
this_class_name: String,
parent: Option<String>,
interfaces: Vec<String>,
method_area: Rc<RefCell<MethodArea>>,
) -> Self {
Self {
methods,
Expand All @@ -74,7 +70,6 @@ impl JavaClass {
parent,
_interfaces: interfaces,
static_fields_initialized: AtomicBool::new(false),
method_area,
}
}

Expand All @@ -90,14 +85,14 @@ impl JavaClass {
&self._interfaces
}

pub fn static_field(&self, field_name: &str) -> crate::error::Result<Rc<RefCell<Field>>> {
pub fn static_field(&self, field_name: &str) -> crate::error::Result<Arc<Field>> {
if !self.static_fields_initialized.load(Ordering::SeqCst) {
self.static_fields_initialized.store(true, Ordering::SeqCst);
self.do_static_fields_initialization()?;
}

match self.static_fields.field_by_name.get(field_name) {
Some(field) => Ok(Rc::clone(field)),
Some(field) => Ok(Arc::clone(field)),
None => Err(Error::new_constant_pool(&format!(
"Error getting field: {}.{field_name}",
self.this_class_name
Expand All @@ -118,7 +113,7 @@ impl JavaClass {
self.this_class_name,
Self::STATIC_INIT_METHOD
);
let mut engine = Engine::new(Rc::clone(&self.method_area));
let mut engine = Engine::new();
engine.execute(static_init_method)?;
println!(
"<RETURN> -> {}.{}",
Expand Down Expand Up @@ -153,7 +148,7 @@ impl JavaClass {
}

impl Methods {
pub fn new(method_by_signature: HashMap<String, Rc<JavaMethod>>) -> Self {
pub fn new(method_by_signature: HashMap<String, Arc<JavaMethod>>) -> Self {
Self {
method_by_signature,
}
Expand Down
105 changes: 55 additions & 50 deletions vm/src/method_area/method_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,59 @@ use jclass::class_file::{parse, ClassFile};
use jclass::fields::{FieldFlags, FieldInfo};
use jclass::methods::{MethodFlags, MethodInfo};
use jdescriptor::TypeDescriptor;
use std::cell::RefCell;
use once_cell::sync::OnceCell;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak};
use std::sync::{Arc, RwLock};

static METHOD_AREA: OnceCell<MethodArea> = OnceCell::new();

pub(crate) fn with_method_area<F, R>(f: F) -> R
where
F: FnOnce(&MethodArea) -> R,
{
let method_area = METHOD_AREA.get().expect("error getting method area");

f(&method_area)
}

#[derive(Debug)]
pub(crate) struct MethodArea {
std_dir: String,
pub(crate) loaded_classes: RefCell<HashMap<String, Rc<JavaClass>>>,
self_ref: RefCell<Weak<RefCell<MethodArea>>>,
pub(crate) loaded_classes: RwLock<HashMap<String, Arc<JavaClass>>>,
}

impl MethodArea {
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()),
self_ref: RefCell::new(Weak::new()),
}));

method_area
.borrow_mut()
.self_ref
.replace(Rc::downgrade(&method_area));
method_area
pub(crate) fn init_method_area(std_dir: &str) {
match METHOD_AREA.set(MethodArea {
std_dir: std_dir.to_string(),
loaded_classes: RwLock::new(HashMap::new()),
}) {
Ok(_) => (),
Err(_) => (),
}
}

impl MethodArea {
pub(crate) fn get(
&self,
fully_qualified_class_name: &str,
) -> crate::error::Result<Rc<JavaClass>> {
if let Some(java_class) = self.loaded_classes.borrow().get(fully_qualified_class_name) {
return Ok(Rc::clone(java_class));
) -> crate::error::Result<Arc<JavaClass>> {
if let Some(java_class) = self
.loaded_classes
.read()
.unwrap()
.get(fully_qualified_class_name)
{
return Ok(Arc::clone(java_class));
}

//todo: make me thread-safe if move to multithreaded jvm
let java_class = self.load_class_file(fully_qualified_class_name)?;
self.loaded_classes.borrow_mut().insert(
self.loaded_classes.write().unwrap().insert(
fully_qualified_class_name.to_string(),
Rc::clone(&java_class),
Arc::clone(&java_class),
);
println!("<CLASS LOADED> -> {}", java_class.this_class_name());

Expand All @@ -61,7 +72,7 @@ impl MethodArea {
fn load_class_file(
&self,
fully_qualified_class_name: &str,
) -> crate::error::Result<Rc<JavaClass>> {
) -> crate::error::Result<Arc<JavaClass>> {
let paths = vec![
Path::new(&self.std_dir)
.join(fully_qualified_class_name)
Expand All @@ -77,7 +88,7 @@ impl MethodArea {
})
}

fn try_open_and_parse(&self, path: &PathBuf) -> Option<Rc<JavaClass>> {
fn try_open_and_parse(&self, path: &PathBuf) -> Option<Arc<JavaClass>> {
let mut file = File::open(path).ok()?;
let mut buff = Vec::new();
file.read_to_end(&mut buff).ok()?;
Expand All @@ -94,7 +105,7 @@ impl MethodArea {
fn to_java_class(
&self,
class_file: ClassFile,
) -> crate::error::Result<(String, Rc<JavaClass>)> {
) -> crate::error::Result<(String, Arc<JavaClass>)> {
let cpool_helper = CPoolHelper::new(class_file.constant_pool());

let this_class_index = class_file.this_class();
Expand Down Expand Up @@ -134,23 +145,18 @@ impl MethodArea {
let (non_static_field_descriptors, static_fields) =
Self::get_field_descriptors(&class_file.fields(), &cpool_helper)?;

if let Some(method_area) = self.self_ref.borrow().upgrade() {
Ok((
class_name.clone(),
Rc::new(JavaClass::new(
methods,
static_fields,
non_static_field_descriptors,
cpool_helper,
class_name,
super_class_name,
interface_names,
Rc::clone(&method_area),
)),
))
} else {
Err(Error::new_execution("Error upgrading method_area"))
}
Ok((
class_name.clone(),
Arc::new(JavaClass::new(
methods,
static_fields,
non_static_field_descriptors,
cpool_helper,
class_name,
super_class_name,
interface_names,
)),
))
}

fn get_methods(
Expand Down Expand Up @@ -203,7 +209,7 @@ impl MethodArea {

method_by_signature.insert(
key.clone(),
Rc::new(JavaMethod::new(
Arc::new(JavaMethod::new(
method_descriptor,
class_name,
&key,
Expand Down Expand Up @@ -241,8 +247,7 @@ impl MethodArea {
})?;

if field_info.access_flags().contains(FieldFlags::ACC_STATIC) {
static_field_by_name
.insert(field_name, Rc::new(RefCell::new(Field::new(descriptor))));
static_field_by_name.insert(field_name, Arc::new(Field::new(descriptor)));
} else {
let field_name_key = format!("{field_name}:{field_descriptor}");
non_static_field_descriptors.insert(field_name_key, descriptor);
Expand All @@ -259,11 +264,11 @@ impl MethodArea {
&self,
class_name: &str,
field_name: &str,
) -> Option<Rc<RefCell<Field>>> {
) -> Option<Arc<Field>> {
let rc = self.get(class_name).ok()?;

if let Some(field) = rc.static_field(field_name).ok() {
Some(Rc::clone(&field))
Some(Arc::clone(&field))
} else {
let parent_class_name = rc.parent().clone()?;

Expand All @@ -275,11 +280,11 @@ impl MethodArea {
&self,
class_name: &str,
full_method_signature: &str,
) -> Option<Rc<JavaMethod>> {
) -> Option<Arc<JavaMethod>> {
let rc = self.get(class_name).ok()?;

if let Some(java_method) = rc.methods.method_by_signature.get(full_method_signature) {
Some(Rc::clone(&java_method))
Some(Arc::clone(&java_method))
} else {
let parent_class_name = rc.parent().clone()?;

Expand Down Expand Up @@ -313,7 +318,7 @@ impl MethodArea {
&self,
class_name: &str,
instance_fields_hierarchy: &mut IndexMap<ClassName, HashMap<FieldNameType, Field>>,
) -> Option<Rc<JavaMethod>> {
) -> Option<JavaMethod> {
let rc = self.get(class_name).ok()?;
let instance_fields = rc.default_value_instance_fields();
instance_fields_hierarchy.insert(class_name.to_string(), instance_fields);
Expand Down
17 changes: 6 additions & 11 deletions vm/src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
use crate::error::Error;
use crate::execution_engine::engine::Engine;
use crate::method_area::method_area::MethodArea;
use std::cell::RefCell;
use std::rc::Rc;
use crate::method_area::method_area::{init_method_area, with_method_area};

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

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

pub fn new(std_dir: &str) -> Self {
Self {
method_area: MethodArea::new(std_dir),
}
init_method_area(std_dir);
Self {}
}

pub fn run(&mut self, main_class_name: &str) -> crate::error::Result<Option<Vec<i32>>> {
let internal_name = &main_class_name.replace('.', "/");
let java_class = self.method_area.borrow().get(internal_name)?;
let java_class = with_method_area(|area| area.get(internal_name))?;

let java_method = java_class
.methods
Expand All @@ -30,7 +25,7 @@ impl VM {
format!("main method not found in {main_class_name}").as_str(),
))?;

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

engine.execute(java_method)
}
Expand Down

0 comments on commit e5ea3d2

Please sign in to comment.