From 9243c0b291c56ef198793b50a9217c592c7c457a Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Fri, 6 Sep 2024 15:04:21 +0200 Subject: [PATCH] Fix enumeration issue --- src/classstore.rs | 2 +- src/heap_area.rs | 64 ++++++++++++++++++++++++++++++++++++----------- src/jvm.rs | 51 ++++++++----------------------------- src/main.rs | 2 +- 4 files changed, 62 insertions(+), 57 deletions(-) diff --git a/src/classstore.rs b/src/classstore.rs index 1cc171f..c62d4f4 100644 --- a/src/classstore.rs +++ b/src/classstore.rs @@ -91,7 +91,7 @@ impl ClassStore { return Ok(self.classes.len() - 1); } - pub fn add_native_class_name(&mut self, name: String) -> usize { + pub fn add_native_class_descriptor(&mut self, name: String) -> usize { self.native_class_names.push(name); return self.native_class_names.len() - 1; } diff --git a/src/heap_area.rs b/src/heap_area.rs index 5fc7afa..62a7d48 100644 --- a/src/heap_area.rs +++ b/src/heap_area.rs @@ -51,21 +51,37 @@ impl HeapArea { self.memory_used += self.static_area.make(class, class_index); } - pub fn byte_array_from_rust_string(&mut self, string: &str, class_store: &ClassStore) -> ObjectReference { - let mut byte_obj_vec = Vec::::with_capacity(string.len()); - for byte in string.as_bytes() { - // TODO: Take bytes from ByteCache + pub fn fill_byte_cache(&mut self, class_store: &ClassStore) { + self.memory_used += self.object_area.fill_byte_cache(class_store); + } - let byte_class_idx = class_store.class_idx_from_name(&"java/lang/Byte".to_string()).unwrap(); - let byte_obj = self.make_object(&class_store, byte_class_idx); - self.object_area.set_object_field(byte_obj, "value", FieldValue::Byte(*byte), byte_class_idx, &class_store).unwrap(); + pub fn make_handmade_string(&mut self, s: &String, class_store: &ClassStore) -> ObjectReference { + let utf16_bytes = { + let utf16 = s.encode_utf16(); + let mut byte_buffer = Vec::with_capacity(s.len() * 2); - byte_obj_vec.push(byte_obj); - } + for utf16_point in utf16 { + let bytes = utf16_point.to_ne_bytes(); + byte_buffer.push(bytes[0]); + byte_buffer.push(bytes[1]); + } - let byte_array = self.make_array(&class_store, byte_obj_vec.into_boxed_slice()); + byte_buffer + }; - byte_array + let byte_object_refs = utf16_bytes.iter().map(|byte| self.object_area.cached_byte_object(*byte)).collect(); + + let byte_array_ref = self.make_array(class_store, byte_object_refs); + + + let string_class_index = class_store.class_idx_from_name(&String::from("java/lang/String")).unwrap(); + let string_ref = self.make_object(class_store, string_class_index); + + self.object_area.set_object_field(string_ref, "value", FieldValue::Reference(byte_array_ref), string_class_index, class_store).unwrap(); + const UTF16_CODER: u8 = 1; // TODO: I don't like this + self.object_area.set_object_field(string_ref, "coder", FieldValue::Byte(UTF16_CODER), string_class_index, class_store).unwrap(); + + string_ref } } @@ -83,14 +99,34 @@ const DEFAULT_COMPARTMENT_CAPACITY: u32 = u16::MAX as u32; const INVALID_FIRST_OBJECT: usize = u16::MAX as usize; const INVALID_NEXT_COMPARTMENT: usize = 0; -#[derive(Default, Debug)] +#[derive(Debug, Default)] pub struct ObjectArea { memory_used: usize, + byte_object_cache: Vec, compartments: Vec, first_free_compartment: usize, } impl ObjectArea { + fn fill_byte_cache(&mut self, class_store: &ClassStore) -> usize { + let byte_class_index = class_store.class_idx_from_name(&String::from("java/lang/Byte")).unwrap(); + let mut total_memory_usage = 0; + for byte in 0..=u8::MAX { + let (byte_object_ref, object_memory) = self.make(class_store, byte_class_index); + self.set_object_field(byte_object_ref, "value", FieldValue::Byte(byte), byte_class_index, class_store).unwrap(); + + self.byte_object_cache.push(byte_object_ref); + + total_memory_usage += object_memory; + } + + total_memory_usage + } + + pub fn cached_byte_object(&mut self, byte: u8) -> ObjectReference { + self.byte_object_cache[byte as usize] + } + fn make_empty_array(&mut self, class_store: &ClassStore, element_type_desc: AbstractTypeDescription, capacity: usize) -> (ObjectReference, usize) { // // make new type desc @@ -225,8 +261,8 @@ impl ObjectArea { let field_option = ClassFieldIterator::new(object.class_index, class_store) .filter(|f| ! (f.access_flags & FieldAccessFlag::Static)) - .filter(|f| f.name == field_name) .enumerate() + .filter(|(_, f)| f.name == field_name) .next(); match field_option { @@ -265,8 +301,8 @@ impl ObjectArea { let field_option = ClassFieldIterator::new(object.class_index, class_store) .filter(|f| ! (f.access_flags & FieldAccessFlag::Static)) - .filter(|f| f.name == field_name) .enumerate() + .filter(|(_, f)| f.name == field_name) .next(); match field_option { diff --git a/src/jvm.rs b/src/jvm.rs index b3d5e95..22bbf2d 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -112,7 +112,7 @@ impl JVM { self.heap_area.object_area.set_object_field( class_data_object, "native_class_descriptor_index", - FieldValue::Int(self.class_store.add_native_class_name(class_name.to_string()) as i32), + FieldValue::Int(self.class_store.add_native_class_descriptor(class_name.to_string()) as i32), self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(), &self.class_store, ).unwrap(); @@ -171,7 +171,7 @@ impl JVM { self.heap_area.object_area.set_object_field( array_class_data_object, "native_class_descriptor_index", - FieldValue::Int(self.class_store.add_native_class_name((&array_type_description).into()) as i32), + FieldValue::Int(self.class_store.add_native_class_descriptor((&array_type_description).into()) as i32), self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(), &self.class_store, ).unwrap(); @@ -288,7 +288,7 @@ impl JVM { ]), attributes: Box::new([]), }; - let entry_frame = StackFrame::new(&entry_class, 0, 0, &[]); + self.class_store.add_class(entry_class, true)?; // 0 self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1 self.class_store.load_class(&"java/lang/Object".to_string())?; // 2 @@ -302,23 +302,16 @@ impl JVM { self.make_array_class("Ljava/lang/Byte;"); self.make_array_class("Ljava/lang/String;"); - let argument_array = self.heap_area.make_empty_array(&self.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, arguments.len()); - for (arg_index, argument) in arguments.iter().enumerate() { - let byte_array = self.heap_area.byte_array_from_rust_string(argument, &self.class_store); - self.stack_frames.push( - StackFrame::new( - self.class_store.get_class(&"::EntryPoint".to_string()).unwrap().0, - self.class_store.class_idx_from_name(&"::EntryPoint".to_string()).unwrap(), - 1, // method index - &[StackValue::Reference(byte_array), StackValue::Reference(argument_array), StackValue::Int(arg_index as i32)], - ) - ); + self.heap_area.fill_byte_cache(&self.class_store); - self.run()?; - } + let string_refs = arguments.iter() + .map(|s| self.heap_area.make_handmade_string(&s.to_string(), &self.class_store)) + .collect(); + let argument_array_ref = self.heap_area.make_array(&self.class_store, string_refs); // push the entry frame which will call main + let entry_frame = StackFrame::new(self.class_store.get_class(&String::from("::EntryPoint")).unwrap().0, 0, 0, &[StackValue::Reference(argument_array_ref)]); self.stack_frames.push(entry_frame); Ok(()) @@ -481,31 +474,7 @@ impl JVM { if name == "java/lang/String" { let string_entry = class_file.gather_string(constant_value_info.constant_value_index)?; - let (string_class_file, string_class_index) = self.class_store.get_class(name).unwrap(); - let string_object = self.heap_area.make_object(&self.class_store, string_class_index); - // TODO: Review this if it looks like there will be stack - // overflows in initialization - - let string_init_function_index = match ClassMethodIterator::new(string_class_index, &self.class_store) - .filter(|( cid, _mid, _minfo)| *cid == string_class_index) - .filter(|(_cid, _mid, minfo)| minfo.name == "") - .filter(|(_cid, _mid, minfo)| minfo.descriptor.argument_types.len() == 1) - .filter(|(_cid, _mid, minfo)| minfo.descriptor.argument_types[0] == AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() }) - .next() { - Some((_, method_index, _)) => method_index, - None => unreachable!(), - }; - - let byte_array = self.heap_area.byte_array_from_rust_string(string_entry, &self.class_store); - - self.stack_frames.push( - StackFrame::new( - string_class_file, - string_class_index, - string_init_function_index as u16, - &[StackValue::Reference(byte_array)], - ) - ); + let string_object = self.heap_area.make_handmade_string(string_entry, &self.class_store); FieldValue::Reference(string_object) } else { diff --git a/src/main.rs b/src/main.rs index ccaa99e..84d646c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ use crate::accessmasks::FieldAccessFlag; use crate::classfile::JavaClassFile; fn main() { - //println!("{:#?}", JavaClassFile::new(&mut File::open("java/Main.class").unwrap()).unwrap()); + //println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/String.class").unwrap()).unwrap().fields.iter().filter(|f| ! (f.access_flags & FieldAccessFlag::Static)).collect::>()); let mut jvm = jvm::JVM::new();