rusty_jvm/vm/
mod.rs

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