Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework method area to make it a singleton #37

Merged
merged 1 commit into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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