Skip to content

Commit

Permalink
Refactoring: execute routines
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Nov 16, 2024
1 parent 0775034 commit dc548df
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 199 deletions.
118 changes: 118 additions & 0 deletions vm/src/execution_engine/executor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use crate::execution_engine::engine::Engine;
use crate::heap::heap::with_heap_write_lock;
use crate::method_area::java_class::JavaClass;
use crate::method_area::method_area::with_method_area;
use crate::stack::sack_value::StackValueKind;
use crate::stack::stack_frame::StackFrame;

pub struct Executor {}

impl Executor {
const STATIC_INIT_METHOD: &'static str = "<clinit>:()V";
const INIT_METHOD: &'static str = "<init>:()V";

pub fn do_static_fields_initialization(java_class: &JavaClass) -> crate::error::Result<()> {
//todo: protect me with recursive mutex
if let Some(static_init_method) = java_class.try_get_method(Self::STATIC_INIT_METHOD) {
Engine::execute(
static_init_method.new_stack_frame()?,
&format!("static initialization {}", java_class.this_class_name()),
)?;
}

Ok(())
}

pub fn invoke_static_method(
class_name: &str,
method_name: &str,
args: &[StackValueKind],
) -> crate::error::Result<Vec<i32>> {
let result = Self::exec(class_name, method_name, args)?;
match result {
Some(value) => Ok(value),
None => Ok(vec![]),
}
}

pub fn invoke_default_constructor(class_name: &str) -> crate::error::Result<i32> {
let instance_with_default_fields = with_method_area(|method_area| {
method_area.create_instance_with_default_fields(class_name)
});

let instance_ref =
with_heap_write_lock(|heap| heap.create_instance(instance_with_default_fields));
Self::exec(class_name, Self::INIT_METHOD, &[instance_ref.into()])?;

Ok(instance_ref)
}

pub fn invoke_args_constructor(
class_name: &str,
full_signature: &str,
args: &[StackValueKind],
) -> crate::error::Result<i32> {
let instance_with_default_fields = with_method_area(|method_area| {
method_area.create_instance_with_default_fields(&class_name)
});

let instance_ref =
with_heap_write_lock(|heap| heap.create_instance(instance_with_default_fields));

let mut new_args = Vec::with_capacity(args.len() + 1);
new_args.push(instance_ref.into());
new_args.extend_from_slice(args);
Self::exec(class_name, full_signature, &new_args)?;

Ok(instance_ref)
}

pub fn create_primordial_thread(args: &[StackValueKind]) -> crate::error::Result<i32> {
let instance_with_default_fields = with_method_area(|method_area| {
method_area.create_instance_with_default_fields("java/lang/Thread")
});

let thread_obj_ref =
with_heap_write_lock(|heap| heap.create_instance(instance_with_default_fields));
with_method_area(|area| area.set_system_thread_id(thread_obj_ref)); //save primordial thread id

let mut new_args = Vec::with_capacity(args.len() + 1);
new_args.push(thread_obj_ref.into());
new_args.extend_from_slice(args);
Self::exec(
"java/lang/Thread",
"<init>:(Ljava/lang/ThreadGroup;Ljava/lang/String;)V",
&new_args,
)?;

Ok(thread_obj_ref)
}

fn exec(
class_name: &str,
method_name: &str,
args: &[StackValueKind],
) -> crate::error::Result<Option<Vec<i32>>> {
let java_class = with_method_area(|area| area.get(class_name))?;
let java_method = java_class.get_method(method_name)?;
let mut stack_frame = java_method.new_stack_frame()?;
Self::set_stack_arguments(&mut stack_frame, args)?;
Engine::execute(stack_frame, &format!("invoke {class_name}.{method_name}"))
}

fn set_stack_arguments(
stack_frame: &mut StackFrame,
args: &[StackValueKind],
) -> crate::error::Result<()> {
for (i, arg) in args.iter().enumerate() {
match arg {
StackValueKind::I32(value) => stack_frame.set_local(i, *value),
StackValueKind::I64(value) => stack_frame.set_local(i, *value),
StackValueKind::F32(value) => stack_frame.set_local(i, *value),
StackValueKind::F64(value) => stack_frame.set_local(i, *value),
}
}

Ok(())
}
}
3 changes: 2 additions & 1 deletion vm/src/execution_engine/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub(crate) mod engine;
mod engine;
pub(crate) mod executor;
pub(crate) mod ldc_resolution_manager;
pub(crate) mod opcode;
mod ops_comparison_processor;
Expand Down
13 changes: 2 additions & 11 deletions vm/src/execution_engine/ops_reference_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,7 @@ pub(crate) fn process(
})?;
let full_signature = format!("{}:{}", method_name, method_descriptor);
let rc = with_method_area(|method_area| method_area.get(class_name.as_str()))?;
let special_method = rc
.methods
.method_by_signature
.get(&full_signature)
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting JavaMethod by class name {class_name} and full signature {full_signature} invoking special")))?;
let special_method = rc.get_method(&full_signature)?;
// ^^^ todo: implement lookup in parents

let arg_num = special_method.get_method_descriptor().arguments_length();
Expand Down Expand Up @@ -280,12 +276,7 @@ pub(crate) fn process(
})?;
let full_signature = format!("{}:{}", method_name, method_descriptor);
let rc = with_method_area(|method_area| method_area.get(class_name.as_str()))?;
let static_method = rc
.methods
.method_by_signature
.get(&full_signature)
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting JavaMethod by class name {class_name} and full signature {full_signature} invoking static")))?;

let static_method = rc.get_method(&full_signature)?;
// todo: according to requirements of JVMS Section 5.4
// all static fields of the class should be initialized
// at this point
Expand Down
54 changes: 5 additions & 49 deletions vm/src/execution_engine/string_pool_helper.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::error::Error;
use crate::execution_engine::engine::Engine;
use crate::execution_engine::executor::Executor;
use crate::heap::heap::{with_heap_read_lock, with_heap_write_lock};
use crate::method_area::method_area::with_method_area;

pub struct StringPoolHelper {}

Expand All @@ -16,72 +14,30 @@ impl StringPoolHelper {
Ok(string_ref)
}

// refactor candidate A: generalize object creation and constructor invocation
fn create_string(string: &str) -> crate::error::Result<i32> {
if string.is_empty() {
return Self::create_empty_string();
}

let codepoints = Self::string_to_codepoints(&string);

let array_ref =
with_heap_write_lock(|heap| heap.create_array_with_values("[I", &codepoints));
let string_class_name = "java/lang/String".to_string();
let instance_with_default_fields = with_method_area(|method_area| {
method_area.create_instance_with_default_fields(&string_class_name)
});

let args = vec![array_ref.into(), 0.into(), (codepoints.len() as i32).into()];
let string_instance_ref =
with_heap_write_lock(|heap| heap.create_instance(instance_with_default_fields));

let full_signature = "<init>:([III)V";
let rc = with_method_area(|method_area| method_area.get(string_class_name.as_str()))?;
let special_method = rc
.methods
.method_by_signature
.get(full_signature)
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting JavaMethod by class name {string_class_name} and full signature {full_signature} invoking special")))?;

let mut stack_frame = special_method.new_stack_frame()?;
stack_frame.set_local(0, string_instance_ref);
stack_frame.set_local(1, array_ref);
stack_frame.set_local(2, 0);
stack_frame.set_local(3, codepoints.len() as i32);

Engine::execute(stack_frame, &format!("creating \"{string}\""))?;
Executor::invoke_args_constructor("java/lang/String", "<init>:([III)V", &args)?;

// todo: ensure that array_ref is collected by GC
Ok(string_instance_ref)
}

// todo: consider creating all CPool strings like this
// refactor candidate A: generalize object creation and constructor invocation
fn create_empty_string() -> crate::error::Result<i32> {
let byte_array_ref =
with_heap_write_lock(|heap| heap.create_array_with_values("[b", &vec![]));
let string_class_name = "java/lang/String".to_string();
let instance_with_default_fields = with_method_area(|method_area| {
method_area.create_instance_with_default_fields(&string_class_name)
});

let args = vec![byte_array_ref.into(), 0.into() /*coder LATIN1*/];
let string_instance_ref =
with_heap_write_lock(|heap| heap.create_instance(instance_with_default_fields));

let full_signature = "<init>:([BB)V";
let rc = with_method_area(|method_area| method_area.get(string_class_name.as_str()))?;
let special_method = rc
.methods
.method_by_signature
.get(full_signature)
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting JavaMethod by class name {string_class_name} and full signature {full_signature} invoking special")))?;

let mut stack_frame = special_method.new_stack_frame()?;
stack_frame.set_local(0, string_instance_ref);
stack_frame.set_local(1, byte_array_ref);
stack_frame.set_local(2, 0); // coder LATIN1

Engine::execute(stack_frame, "creating \"\"")?;

Executor::invoke_args_constructor("java/lang/String", "<init>:([BB)V", &args)?;
Ok(string_instance_ref)
}

Expand Down
58 changes: 24 additions & 34 deletions vm/src/method_area/java_class.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::execution_engine::engine::Engine;
use crate::execution_engine::executor::Executor;
use crate::heap::java_instance::FieldNameType;
use crate::method_area::cpool_helper::CPoolHelper;
use crate::method_area::field::Field;
Expand All @@ -8,13 +8,12 @@ use jdescriptor::TypeDescriptor;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tracing::trace;

const INTERFACE: u16 = 0x00000200;

#[derive(Debug)]
pub(crate) struct JavaClass {
pub(crate) methods: Methods,
methods: Methods,
static_fields: Fields,
non_static_field_descriptors: FieldDescriptors,
cpool_helper: CPoolHelper,
Expand All @@ -28,7 +27,7 @@ pub(crate) struct JavaClass {

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

#[derive(Debug)]
Expand All @@ -54,8 +53,6 @@ impl Fields {
}

impl JavaClass {
const STATIC_INIT_METHOD: &'static str = "<clinit>:()V";

pub fn new(
methods: Methods,
static_fields: Fields,
Expand Down Expand Up @@ -101,7 +98,7 @@ impl JavaClass {
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
self.do_static_fields_initialization()?;
Executor::do_static_fields_initialization(self)?;
}

Ok(self
Expand All @@ -111,33 +108,6 @@ impl JavaClass {
.map(|field| Arc::clone(field)))
}

fn do_static_fields_initialization(&self) -> crate::error::Result<()> {
//todo: protect me with recursive mutex

if let Some(static_init_method) = self
.methods
.method_by_signature
.get(Self::STATIC_INIT_METHOD)
{
trace!(
"<INVOKE> -> {}.{}",
self.this_class_name,
Self::STATIC_INIT_METHOD
);
Engine::execute(
static_init_method.new_stack_frame()?,
&format!("static initialization {}", self.this_class_name),
)?;
trace!(
"<RETURN> -> {}.{}",
self.this_class_name,
Self::STATIC_INIT_METHOD
);
}

Ok(())
}

pub fn instance_field_descriptor(
&self,
instance_field_name_type: &str,
Expand Down Expand Up @@ -204,6 +174,26 @@ impl JavaClass {

Ok(field_name.clone())
}

fn get_method_internal(&self, full_signature: &str) -> Option<Arc<JavaMethod>> {
self.methods
.method_by_signature
.get(full_signature)
.map(|method| Arc::clone(method))
}

pub fn try_get_method(&self, full_signature: &str) -> Option<Arc<JavaMethod>> {
self.get_method_internal(full_signature)
}

pub fn get_method(&self, full_signature: &str) -> crate::error::Result<Arc<JavaMethod>> {
self.get_method_internal(full_signature).ok_or_else(|| {
crate::error::Error::new_native(&format!(
"Method {full_signature} not found in {}",
self.this_class_name
))
})
}
}

impl Methods {
Expand Down
2 changes: 1 addition & 1 deletion vm/src/method_area/method_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ impl MethodArea {
) -> Option<Arc<JavaMethod>> {
let rc = self.get(class_name).ok()?;

if let Some(java_method) = rc.methods.method_by_signature.get(full_method_signature) {
if let Some(java_method) = rc.try_get_method(full_method_signature) {
Some(Arc::clone(&java_method))
} else {
let parent_class_name = rc.parent().clone()?;
Expand Down
2 changes: 1 addition & 1 deletion vm/src/stack/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
mod sack_value;
pub(crate) mod sack_value;
pub(crate) mod stack_frame;
32 changes: 32 additions & 0 deletions vm/src/stack/sack_value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
use crate::helper::i32toi64;
use crate::stack::stack_frame::StackFrame;

#[derive(Clone)]
pub enum StackValueKind {
I32(i32),
I64(i64),
F32(f32),
F64(f64),
}

impl From<i32> for StackValueKind {
fn from(value: i32) -> Self {
StackValueKind::I32(value)
}
}

impl From<i64> for StackValueKind {
fn from(value: i64) -> Self {
StackValueKind::I64(value)
}
}

impl From<f32> for StackValueKind {
fn from(value: f32) -> Self {
StackValueKind::F32(value)
}
}

impl From<f64> for StackValueKind {
fn from(value: f64) -> Self {
StackValueKind::F64(value)
}
}

pub trait StackValue {
fn push_onto(&self, stack_frame: &mut StackFrame);
fn pop_from(stack_frame: &mut StackFrame) -> Self;
Expand Down
Loading

0 comments on commit dc548df

Please sign in to comment.