rusty_jvm/vm/
mod.rs

1mod commons;
2mod error;
3mod exception;
4mod execution_engine;
5mod heap;
6mod helper;
7mod method_area;
8mod properties;
9mod stack;
10mod system_native;
11mod validation;
12
13use crate::vm::error::{Error, Result};
14use crate::vm::execution_engine::executor::Executor;
15use crate::vm::execution_engine::static_init::StaticInit;
16use crate::vm::execution_engine::string_pool_helper::StringPoolHelper;
17use crate::vm::helper::create_array_of_strings;
18use crate::vm::method_area::java_class::JavaClass;
19use crate::vm::method_area::method_area::{with_method_area, MethodArea};
20use crate::vm::properties::system_properties::init_system_properties;
21use crate::vm::system_native::properties_provider::properties::is_bigendian;
22use crate::vm::validation::validate_class_name;
23use crate::Arguments;
24use std::path::Path;
25use std::sync::Arc;
26use tracing_subscriber::layer::SubscriberExt;
27use tracing_subscriber::util::SubscriberInitExt;
28use tracing_subscriber::{fmt, EnvFilter};
29
30/// Launches the Rusty Java Virtual Machine with the given arguments.
31///
32/// This function initializes the JVM, loads the specified main class, and invokes its `main` method.
33///
34/// # Arguments
35///
36/// * `arguments` - The arguments for the Java program.
37/// * `std_dir` - The path to the standard library directory containing core Java classes.
38pub fn run(arguments: &Arguments, java_home: &Path) -> Result<Vec<i32>> {
39    let main_class_name = arguments.entry_point();
40    validate_class_name(main_class_name)?;
41
42    init_system_properties(arguments.system_properties().clone())?;
43
44    prelude(java_home)?;
45
46    let internal_name = &main_class_name.replace('.', "/");
47    StaticInit::initialize(internal_name)?; // before invoking static main method, static fields should be initialized (JVMS requirement)
48
49    let args_array_ref = create_array_of_strings(arguments.program_args())?;
50    Executor::invoke_static_method(
51        internal_name,
52        "main:([Ljava/lang/String;)V",
53        &[args_array_ref.into()],
54    )
55}
56
57fn prelude(java_home: &Path) -> Result<()> {
58    init_logger()?;
59
60    MethodArea::init(java_home)?;
61
62    init()?;
63
64    Ok(())
65}
66
67fn init_logger() -> Result<()> {
68    let fmt_layer = fmt::layer()
69        .with_target(false)
70        .without_time()
71        .with_ansi(false);
72    let filter_layer = EnvFilter::try_from_default_env()
73        .or_else(|_| EnvFilter::try_new("info"))
74        .map_err(|e| Error::new_execution(&format!("Error creating EnvFilter: {e}")))?;
75    tracing_subscriber::registry()
76        .with(filter_layer)
77        .with(fmt_layer)
78        .init();
79
80    Ok(())
81}
82
83fn init() -> Result<()> {
84    StaticInit::initialize("jdk/internal/misc/UnsafeConstants")?;
85    let lc = with_method_area(|area| area.get("jdk/internal/misc/UnsafeConstants"))?;
86    let big_endian = lc.static_field("BIG_ENDIAN").unwrap();
87    big_endian.set_raw_value(vec![if is_bigendian() { 1 } else { 0 }])?;
88
89    let address_size0 = lc.static_field("ADDRESS_SIZE0").unwrap();
90    address_size0.set_raw_value(vec![8])?;
91
92    StaticInit::initialize("java/lang/reflect/AccessibleObject")?;
93
94    put_synthetic_instance_field("java/lang/invoke/ResolvedMethodName", "vmtarget", "J", 0)?;
95
96    // create primordial ThreadGroup and Thread
97    let tg_obj_ref = Executor::invoke_default_constructor("java/lang/ThreadGroup")?;
98    with_method_area(|area| area.set_system_thread_group_id(tg_obj_ref))?;
99    let string_obj_ref = StringPoolHelper::get_string("system")?; // refactor candidate B: introduce and use here common string creator, not string pool one
100    let _thread_obj_ref =
101        Executor::create_primordial_thread(&vec![tg_obj_ref.into(), string_obj_ref.into()])?;
102
103    Executor::invoke_static_method("java/lang/System", "initPhase1:()V", &[])?;
104
105    Ok(())
106}
107
108fn put_synthetic_instance_field(
109    class_name: &str,
110    field_name: &str,
111    type_descriptor: &str,
112    flags: u16,
113) -> Result<()> {
114    let lc = with_method_area(|area| area.get(class_name))?;
115    let raw_java_class = Arc::into_raw(lc) as *mut JavaClass;
116    let result = unsafe {
117        (*raw_java_class).put_instance_field_descriptor(
118            field_name.to_string(),
119            str::parse(type_descriptor)?,
120            flags,
121            class_name,
122        )?
123    };
124    match result {
125        Some(field_property) => Err(Error::new_execution(&format!(
126            "field {field_name}:{} already exists in {class_name}",
127            field_property.type_descriptor()
128        ))),
129        None => Ok(()),
130    }
131}