From 4dabd6c3a81d659027612faf62162e375485f3fe Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Tue, 3 Sep 2024 00:49:28 +0200 Subject: [PATCH] Class loading, object creation --- src/classfile.rs | 15 +++++- src/classstore.rs | 16 +++--- src/heap_area.rs | 134 ++++++++++++++++++++++++++++++++++++++++++++-- src/jvm.rs | 107 +++++++++++++++++++++++++++--------- src/main.rs | 2 +- 5 files changed, 235 insertions(+), 39 deletions(-) diff --git a/src/classfile.rs b/src/classfile.rs index 0522622..94496eb 100644 --- a/src/classfile.rs +++ b/src/classfile.rs @@ -162,7 +162,18 @@ impl JavaClassFile { ) } - pub fn get_classname(&self) -> Result { + pub fn has_super_class(&self) -> bool { + return self.super_class != 0; + } + + pub fn get_super_class_name(&self) -> Result<&String, Error> { + let super_class_entry = self.pool_class_entry(self.super_class)?; + let super_name_entry = self.pool_utf8_entry(super_class_entry.name_index)?; + + return Ok(&super_name_entry.utf8); + } + + pub fn get_classname(&self) -> Result<&String, Error> { let class_info_entry = self.pool_entry(self.this_class)?; let class_info_entry = match class_info_entry { @@ -176,7 +187,7 @@ impl JavaClassFile { _ => return Err(Error::BadFileError(format!("Invalid class_info.name_index from this_class, expected index to Utf8 but found {:?}", name_entry))) }; - return Ok(name_entry.utf8.clone()); + return Ok(&name_entry.utf8); } diff --git a/src/classstore.rs b/src/classstore.rs index 93df77f..3c67ddd 100644 --- a/src/classstore.rs +++ b/src/classstore.rs @@ -61,6 +61,10 @@ impl ClassStore { } } + pub fn class_count(&self) -> usize { + return self.classes.len(); + } + pub fn add_class(&mut self, class_file: JavaClassFile, was_init: bool) { return self.classes.push((was_init, class_file)); } @@ -70,7 +74,7 @@ impl ClassStore { let classfile = JavaClassFile::new(&mut file_reader)?; let classname = classfile.get_classname()?; - self.class_ids.insert(classname, self.classes.len()); + self.class_ids.insert(classname.to_string(), self.classes.len()); self.classes.push((false, classfile)); return Ok(self.classes.len() - 1); @@ -121,14 +125,14 @@ impl ClassStore { } } - pub fn class_idx_from_name(&self, classname: &String) -> Option<&usize> { - return self.class_ids.get(classname); + pub fn class_idx_from_name(&self, classname: &String) -> Option { + return self.class_ids.get(classname).copied(); } - pub fn was_init(&self, classname: &String) -> Option<&bool> { - let (was_init, _) = self.classes.get(*self.class_idx_from_name(classname).unwrap()).unwrap(); + pub fn was_init(&self, classname: &String) -> Option { + let (was_init, _) = self.classes.get(self.class_idx_from_name(classname).unwrap()).unwrap(); - return Some(was_init); + return Some(*was_init); } pub fn set_init(&mut self, class_idx: usize, was_init: bool) { diff --git a/src/heap_area.rs b/src/heap_area.rs index 19b9f82..e448e9d 100644 --- a/src/heap_area.rs +++ b/src/heap_area.rs @@ -1,7 +1,10 @@ use std::collections::HashMap; +use core::fmt::Debug as DebugTrait; + use crate::accessmasks::FieldAccessFlag; use crate::classfile::{ JavaClassFile, AbstractTypeDescription, MethodInfo, AbstractTypeKind }; +use crate::classstore::ClassStore; use crate::jvm::Error; #[derive(Debug)] @@ -22,6 +25,13 @@ impl HeapArea { } } + pub fn make_object(&mut self, class_store: &ClassStore, class_index: usize) -> ObjectReference { + let (object_ref, object_size) = self.object_area.make(class_store, class_index); + self.memory_used += object_size; + + return object_ref; + } + pub fn make_static(&mut self, class: &JavaClassFile, class_index: usize) { self.memory_used += self.static_area.make(class, class_index); } @@ -30,27 +40,144 @@ impl HeapArea { pub type ObjectReference=u32; const DEFAULT_COMPARTMENT_CAPACITY: usize = u16::MAX as usize; +const INVALID_FIRST_OBJECT: usize = u16::MAX as usize; +const INVALID_NEXT_COMPARTMENT: usize = 0; #[derive(Default, Debug)] pub struct ObjectArea { compartments: Vec, + first_free_compartment: usize, +} + +impl ObjectArea { + pub fn make(&mut self, class_store: &ClassStore, target_class_index: usize) -> (ObjectReference, usize) { + let mut fields = Vec::new(); + let mut current_class_index; + let mut next_class_index = target_class_index; + + let mut object_size = 0; + + while next_class_index != class_store.class_count() { + current_class_index = next_class_index; + + let class = class_store.class_file_from_idx(current_class_index).unwrap(); + + for field in &class.fields { + let new_field = ObjectField { + value: FieldValue::default_for(&field.descriptor) + }; + object_size += std::mem::size_of_val(&new_field); + + fields.push(new_field); + } + + if class.has_super_class() { + next_class_index = class_store.class_idx_from_name(class.get_super_class_name().unwrap()).unwrap(); + } else { + next_class_index = class_store.class_count(); + } + } + + let new_object = HeapObject { + class_index: target_class_index, + fields: fields.into_boxed_slice(), + }; + + object_size += std::mem::size_of_val(&new_object); + object_size += std::mem::size_of_val(&new_object.fields); + + let object_ref = self.store_object(new_object); + + return (object_ref, object_size); + } + + fn store_object(&mut self, object: HeapObject) -> ObjectReference { + if self.first_free_compartment == 0 { + self.compartments.push(ObjectCompartment::new(INVALID_NEXT_COMPARTMENT)); + self.first_free_compartment = self.compartments.len(); + } + + let compartment_index = self.first_free_compartment - 1; + let object_index = self.compartments.get_mut(compartment_index).unwrap().store(object); + if self.compartments[compartment_index].first_free == INVALID_FIRST_OBJECT { + self.first_free_compartment = self.compartments[compartment_index].next_free_compartment; + } + + return object_index + (DEFAULT_COMPARTMENT_CAPACITY as u32 * (compartment_index+1) as u32); + } } -#[derive(Debug)] pub struct ObjectCompartment { objects: Box<[ObjectCompartmentEntry]>, first_free: usize, reserved_count: usize, + next_free_compartment: usize, +} + +impl ObjectCompartment { + fn new(next_free: usize) -> Self { + let mut os = Vec::with_capacity(DEFAULT_COMPARTMENT_CAPACITY); + for i in 0..DEFAULT_COMPARTMENT_CAPACITY-1 { + os.push(ObjectCompartmentEntry::EmptyNext(i+1)); + } + os.push(ObjectCompartmentEntry::EmptyTail()); + + ObjectCompartment { + objects: os.into_boxed_slice(), + first_free: 0, + reserved_count: 0, + next_free_compartment: next_free, + } + } + + fn store(&mut self, object: HeapObject) -> ObjectReference { + let store_slot = self.objects.get(self.first_free).unwrap(); + let compartment_index = self.first_free; + + match store_slot { + ObjectCompartmentEntry::Valid(_) => unreachable!(), + ObjectCompartmentEntry::EmptyNext(next) => { + self.first_free = *next; + }, + ObjectCompartmentEntry::EmptyTail() => { + // TODO: Maybe change to something else + self.first_free = INVALID_FIRST_OBJECT; + }, + } + + *self.objects.get_mut(compartment_index).unwrap() = ObjectCompartmentEntry::Valid(object); + self.reserved_count += 1; + + return compartment_index as u32; + } +} + +impl DebugTrait for ObjectCompartment { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + f.debug_struct("ObjectCompartment") + .field("first_free", &self.first_free) + .field("reserved_count", &self.reserved_count) + .field("next_free_compartment", &self.next_free_compartment) + .field("objects", &self.objects + .iter() + .enumerate() + .filter(|e| match e { (_, ObjectCompartmentEntry::Valid(_)) => true, _ => false}) + .map(|e| match e { (i, ObjectCompartmentEntry::Valid(o)) => (i, o), _ => unreachable!()}) + .collect::>() + ).finish() + } } #[derive(Debug)] pub enum ObjectCompartmentEntry { Valid(HeapObject), - Empty(usize), // next empty value + EmptyNext(usize), + EmptyTail(), // next empty value } #[derive(Debug)] pub struct HeapObject { + class_index: usize, fields: Box<[ObjectField]>, } @@ -105,7 +232,7 @@ impl StaticArea { let field_array_size = std::mem::size_of_val(&new_object.fields); let method_array_size = std::mem::size_of_val(&new_object.methods); - let _ = self.static_objects.insert(class.get_classname().unwrap(), new_object); + let _ = self.static_objects.insert(class.get_classname().unwrap().to_string(), new_object); return object_memory_size + field_array_size + fields_cumulative_size + method_array_size; } @@ -138,7 +265,6 @@ pub struct StaticField { #[derive(Debug)] pub struct ObjectField { - pub type_description: AbstractTypeDescription, pub value: FieldValue, } diff --git a/src/jvm.rs b/src/jvm.rs index f2cae7c..052d5e2 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -10,7 +10,7 @@ use crate::classfile::{ JavaClassFile, MethodInfo, MethodDescriptor, AbstractTyp use crate::classstore; use crate::classstore::ClassStore; use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo}; -use crate::heap_area::{ HeapArea, FieldValue }; +use crate::heap_area::{ HeapArea, FieldValue, ObjectReference }; use crate::stackframe; use crate::stackframe::{ StackFrame, StackValue, OperandStack }; @@ -128,6 +128,10 @@ impl JVM { ); self.class_store.add_class(entry_class, true); + self.class_store.load_class(&"java/lang/Class".to_string())?; + self.class_store.load_class(&"java/lang/Object".to_string())?; + + self.new_object(&"java/lang/Class".to_string())?; Ok(()) } @@ -156,12 +160,13 @@ impl JVM { JVMCallbackOperation::PushFrame(frame) => self.stack_frames.push(frame), JVMCallbackOperation::LoadClass(name) => { - self.class_store.load_class(&name)?; - () + // TODO: throw exception + self.load_class_hierarchy(&name)?; }, JVMCallbackOperation::InitClass(name) => { - self.init_class(*self.class_store.class_idx_from_name(&name).unwrap())?; + // TODO: throw exception + self.init_class_hierarchy(&name)?; } } } @@ -169,13 +174,82 @@ impl JVM { Ok(()) } - pub fn init_class(&mut self, class_idx: usize) -> Result<(), Error> { + fn new_object(&mut self, class_name: &String) -> Result { + let (_, class_idx) = self.class_store.get_class(class_name)?; + Ok(self.heap_area.make_object(&mut self.class_store, class_idx)) + } + + fn load_class_hierarchy(&mut self, name: &String) -> Result<(), Error> { + self.class_store.load_class(&name)?; + let super_class_name = { + let (file, _) = self.class_store.get_class(&name)?; + file.get_super_class_name()?.clone() + }; + let mut super_classes = vec![super_class_name]; + + while super_classes.len() != 0 { + let current_super = super_classes.pop().unwrap(); + let have_super_super = { + let (super_file, _) = self.class_store.get_class(¤t_super)?; + super_file.has_super_class() + }; + + if have_super_super { + let super_super_name = { + let (super_file, _) = self.class_store.get_class(¤t_super)?; + super_file.get_super_class_name()? + }; + if self.class_store.have_class(super_super_name) { + self.class_store.load_class(¤t_super)?; + } else { + super_classes.push(current_super); + super_classes.push(super_super_name.to_string()); + } + } else { + self.class_store.load_class(¤t_super)?; + } + } + + Ok(()) + } + + fn init_class_hierarchy(&mut self, name: &String) -> Result<(), Error> { + let mut class_stack = vec![name.to_string()]; + + while class_stack.len() != 0 { + let current_name = class_stack.pop().unwrap(); + let was_super_init = { + let (file, _) = self.class_store.get_class(¤t_name)?; + if ! file.has_super_class() { + true + } else { + let super_name = file.get_super_class_name()?; + self.class_store.was_init(super_name).unwrap() + } + }; + + if was_super_init { + let class_idx = self.class_store.class_idx_from_name(¤t_name).unwrap(); + self.init_class(class_idx)?; + } else { + let super_name = { + let (file, _) = self.class_store.get_class(¤t_name)?; + file.get_super_class_name()? + }; + class_stack.push(current_name); + class_stack.push(super_name.to_string()); + } + } + + Ok(()) + } + + fn init_class(&mut self, class_idx: usize) -> Result<(), Error> { let class_file = self.class_store.class_file_from_idx(class_idx).unwrap(); let clinit_idx = class_file.find_method_index(&"".to_string()); self.heap_area.make_static(class_file, class_idx); - // TODO: ConstantValue Attributes (final) for field in &class_file.fields { if field.access_flags & FieldAccessFlag::Static { let cvalue_attrs: Vec<&ConstantValueAttributeData> = (&field.attributes).iter() @@ -211,7 +285,7 @@ impl JVM { _ => todo!() }; - self.heap_area.static_area.set(&class_file.get_classname()?, &field.name, field_value)?; + self.heap_area.static_area.set(class_file.get_classname()?, &field.name, field_value)?; } } } @@ -223,25 +297,6 @@ impl JVM { Ok(()) } - fn prepare_invoke_static(&mut self, class_index: usize, method_name: &String, arguments: &[StackValue]) -> Result<(), Error> { - - let class_file = self.class_store.class_file_from_idx(class_index).unwrap(); - - let method_index = class_file.find_method_index(method_name) - .ok_or(Error::BadNameError(format!("Could not find method '{}' in class '{}'", method_name, class_file.get_classname()?)))?; - - let new_frame = StackFrame::new( - class_file, - class_index, - method_index.try_into().expect(&format!("Bad method index: {}", method_index)), - arguments - ); - - self.stack_frames.push(new_frame); - - return Ok(()); - } - fn bytecode_loop(&mut self) -> Result { let frame = { diff --git a/src/main.rs b/src/main.rs index 03dcf99..0ad7fba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,6 @@ fn main() { Err(e) => println!("{:#?}", e), }; - println!("{:#?}", jvm); + //println!("{:#?}", jvm.heap_area); //println!("{:#?}", JavaClassFile::new(&mut File::open("java/Class.class").unwrap())); }