rusty-jvm 0.5.0

An implementation of a Java Virtual Machine (JVM).
Documentation
use crate::vm::error::{Error, Result};
use crate::vm::heap::heap::with_heap_write_lock;
use crate::vm::helper::undecorate;
use crate::vm::method_area::method_area::with_method_area;
use crate::vm::method_area::primitives_helper::PRIMITIVE_TYPE_BY_CODE;
use jdescriptor::TypeDescriptor;
use std::collections::HashMap;
use std::sync::RwLock;

#[derive(Debug, Default)]
pub struct ReflectionClassLoader {
    class_type_instance_by_name: RwLock<HashMap<String, i32>>,
}

impl ReflectionClassLoader {
    pub fn load(&self, for_class: &str) -> Result<i32> {
        let class_modifiers = with_method_area(|area| {
            Ok::<u16, Error>(area.get(for_class)?.class_modifiers().bits())
        })?;

        let component_type_ref_empty = 0;
        if !for_class.starts_with('[') && !for_class.ends_with(';') {
            return self.get_or_create(for_class, component_type_ref_empty, class_modifiers);
        }

        let descriptor: TypeDescriptor = for_class.parse()?;
        match &descriptor {
            TypeDescriptor::Array(value, dimension) => {
                let component_ref_name = value.as_ref().to_string();
                let component_name = undecorate(&component_ref_name);
                let component_flags = with_method_area(|area| {
                    Ok::<u16, Error>(area.get(&component_name)?.class_modifiers().bits())
                })?;

                let mut array_ref = self.get_or_create(
                    &component_ref_name,
                    component_type_ref_empty,
                    component_flags,
                )?;

                for padding in (0..*dimension as usize).rev() {
                    let name = &for_class[padding..];
                    array_ref = self.get_or_create(name, array_ref, class_modifiers)?;
                }

                Ok(array_ref)
            }
            _ => self.get_or_create(for_class, component_type_ref_empty, class_modifiers),
        }
    }

    fn get_or_create(
        &self,
        class_name: &str,
        component_type_ref: i32,
        modifiers: u16,
    ) -> Result<i32> {
        let mut class_type_map = self.class_type_instance_by_name.write()?;
        if let Some(&reflection_ref) = class_type_map.get(class_name) {
            return Ok(reflection_ref);
        }

        let reflection_ref =
            Self::create_reflection_instance(class_name, component_type_ref, modifiers)?;
        class_type_map.insert(class_name.to_string(), reflection_ref);
        Ok(reflection_ref)
    }

    fn create_reflection_instance(
        this_class_name: &str,
        component_type_ref: i32,
        modifiers: u16,
    ) -> Result<i32> {
        let mut reflection_instance = with_method_area(|method_area| {
            method_area.create_instance_with_default_fields("java/lang/Class")
        })?;
        reflection_instance.set_field_value(
            "java/lang/Class",
            "componentType",
            vec![component_type_ref],
        )?;
        reflection_instance.set_field_value(
            "java/lang/Class",
            "primitive",
            vec![if PRIMITIVE_TYPE_BY_CODE.contains_key(this_class_name) {
                1
            } else {
                0
            }],
        )?;
        reflection_instance.set_field_value(
            "java/lang/Class",
            "modifiers",
            vec![modifiers as i32],
        )?;

        let reflection_reference =
            with_heap_write_lock(|heap| heap.create_instance(reflection_instance));

        with_method_area(|method_area| {
            method_area.put_to_reflection_table(reflection_reference, this_class_name)
        })?;

        Ok(reflection_reference)
    }
}