diff --git a/src/bytecode.rs b/src/bytecode.rs index cf271cb..f4949f7 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -49,6 +49,7 @@ impl Bytecode { 0x2D => (Instruction::LoadLocalReference3(), 1), 0x32 => (Instruction::ArrayElement(), 1), + 0x33 => (Instruction::LoadFromBArray(), 1), 0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2), 0x3B => (Instruction::StoreLocalInt0(), 1), 0x3C => (Instruction::StoreLocalInt1(), 1), @@ -66,6 +67,7 @@ impl Bytecode { 0x59 => (Instruction::Duplicate(), 1), 0x60 => (Instruction::AddInt(), 1), + 0x64 => (Instruction::SubtractInt(), 1), 0x68 => (Instruction::MultiplyInt(), 1), 0x6C => (Instruction::DivideInt(), 1), 0x6D => (Instruction::DivideLong(), 1), @@ -73,6 +75,7 @@ impl Bytecode { 0x7A => (Instruction::ShiftIntRight(), 1), 0x80 => (Instruction::OrInt(), 1), + 0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3), 0x95 => (Instruction::CompareFloatL(), 1), 0x96 => (Instruction::CompareFloatG(), 1), @@ -155,6 +158,7 @@ impl Bytecode { 0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xBE => (Instruction::ArrayLength(), 1), + 0xC0 => (Instruction::CheckCast((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xC1 => (Instruction::InstanceOf((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xC2 => (Instruction::EnterMonitor(), 1), 0xC3 => (Instruction::ExitMonitor(), 1), @@ -238,6 +242,7 @@ pub enum Instruction { LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack ArrayElement() = 0x32, // load element from array + LoadFromBArray() = 0x33, // store into byte array StoreLocalInt(u8) = 0x36, // store into indexed local variable StoreLocalInt0() = 0x3B, // store int into local variable StoreLocalInt1() = 0x3C, // store int into local variable @@ -254,6 +259,7 @@ pub enum Instruction { Duplicate() = 0x59, // duplicate top stack value AddInt() = 0x60, // int addition + SubtractInt() = 0x64, // int subtraction MultiplyInt() = 0x68, // int multiplication DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideLong() = 0x6D, // long division @@ -261,6 +267,7 @@ pub enum Instruction { ShiftIntRight() = 0x7a, // shift int OrInt() = 0x80, // value, value => or + IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8 CompareFloatL() = 0x95, // compare float, push -1 if one is NaN CompareFloatG() = 0x96, // compare float, push 1 if one is NaN @@ -298,7 +305,8 @@ pub enum Instruction { NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference ArrayLength() = 0xBE, // Get length from array reference - InstanceOf(u16) = 0xC1, // branch if Null + CheckCast(u16) = 0xC0, // throw exception on fail + InstanceOf(u16) = 0xC1, // push integer result for success EnterMonitor() = 0xC2, // enter the synchronization monitor of an object ExitMonitor() = 0xC3, // exit the synchronization monitor of an object BranchNull(i16) = 0xC6, // branch if Null diff --git a/src/classstore.rs b/src/classstore.rs index 083d788..e135f96 100644 --- a/src/classstore.rs +++ b/src/classstore.rs @@ -33,7 +33,7 @@ pub struct PrimitiveClassStore { } #[derive(Debug)] -struct ClassStoreEntry { +pub struct ClassStoreEntry { was_init: bool, class_object: ObjectReference, class_file: JavaClassFile, @@ -133,6 +133,8 @@ impl ClassStore { if path_buf.is_file() { return self.load_class_from_file(&path_buf); } + + path_buf.clear(); }; return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath"))); diff --git a/src/heap_area.rs b/src/heap_area.rs index 56abcfa..916388e 100644 --- a/src/heap_area.rs +++ b/src/heap_area.rs @@ -76,10 +76,11 @@ impl HeapArea { byte_buffer }; - 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 byte_array_ref = self.make_primitive_byte_array(utf16_bytes.len(), class_store); + for (index, byte) in utf16_bytes.iter().enumerate() { + self.object_area.set_array_element(byte_array_ref, index, FieldValue::Byte(*byte)); + } 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); @@ -88,9 +89,15 @@ impl HeapArea { 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 + string_ref } + pub fn make_primitive_char_array(&mut self, array_capacity: usize, class_store: &ClassStore) -> ObjectReference { + let (array_ref, size) = self.object_area.make_primitive_char_array(array_capacity, class_store); + self.memory_used += size; + + array_ref + } } #[derive(Clone, Copy, Debug, Default, PartialEq)] @@ -214,8 +221,7 @@ impl ObjectArea { return (object_ref, object_size); } - pub fn get_reference_native_class_name<'a>(&self, reference: ObjectReference, class_store: &'a ClassStore) -> &'a String { - let class_ref = self.get_reference_class_ref(reference, class_store); + pub fn get_class_ref_native_class_name<'a>(&self, class_ref: ObjectReference, class_store: &'a ClassStore) -> &'a String { let class_data_ref = match self.get_object_field(class_ref, "classData", self.get_object_class_index(class_ref), class_store).unwrap() { FieldValue::Reference(r) => r, _ => unreachable!(), @@ -228,6 +234,11 @@ impl ObjectArea { return class_store.get_native_class_name(native_name_index as usize); } + pub fn get_reference_native_class_name<'a>(&self, reference: ObjectReference, class_store: &'a ClassStore) -> &'a String { + let class_ref = self.get_reference_class_ref(reference, class_store); + self.get_class_ref_native_class_name(class_ref, class_store) + } + pub fn get_object_class_index(&self, reference: ObjectReference) -> usize { match self.get_entry(reference) { CompartmentEntry::Object(o) => o.class_index, @@ -282,22 +293,26 @@ impl ObjectArea { pub fn get_array_length(&self, reference: ObjectReference) -> usize { // TODO: Throw errors - let array = match self.get_entry(reference) { - CompartmentEntry::ReferenceArray(a) => a, + match self.get_entry(reference) { + CompartmentEntry::ReferenceArray(a) => a.content.len(), + CompartmentEntry::ByteArray(b) => b.content.len(), _ => unreachable!(), - }; - - array.content.len() + } } - pub fn get_array_element(&self, array_ref: ObjectReference, element_index: i32) -> ObjectReference { + pub fn get_array_element(&self, array_ref: ObjectReference, element_index: i32) -> FieldValue { // TODO: Throw errors - let array = match self.get_entry(array_ref) { - CompartmentEntry::ReferenceArray(a) => a, + match self.get_entry(array_ref) { + CompartmentEntry::ReferenceArray(array) => { + let element = array.content[element_index as usize]; + FieldValue::Reference(element) + } + CompartmentEntry::ByteArray(array) => { + let element = array.content[element_index as usize]; + FieldValue::Byte(element) + } _ => unreachable!(), - }; - - array.content[element_index as usize] + } } pub fn get_object_field(&self, reference: ObjectReference, field_name: &str, accessing_class_idx: usize, class_store: &ClassStore) -> Result { @@ -387,6 +402,27 @@ impl ObjectArea { ))) } } + + fn make_primitive_char_array(&mut self, array_capacity: usize, class_store: &ClassStore) -> (ObjectReference, usize) { + // make new type desc + let array_type_desc = AbstractTypeDescription { + array_level: 1, + kind: AbstractTypeKind::Char(), + }; + + let array_class_ref = class_store.get_array_class_ref(&array_type_desc).unwrap(); + + let array_size = array_capacity * std::mem::size_of::() + std::mem::size_of::(); + + let array_object = CharArray { + class_ref: array_class_ref, + content: vec![0; array_capacity].into(), + }; + + let array_ref = self.store_entry(CompartmentEntry::CharArray(array_object)); + + (array_ref, array_size) + } } pub struct ObjectCompartment { @@ -428,6 +464,7 @@ impl ObjectCompartment { CompartmentEntry::Object(_) => unreachable!(), CompartmentEntry::ReferenceArray(_) => unreachable!(), CompartmentEntry::ByteArray(_) => unreachable!(), + CompartmentEntry::CharArray(_) => unreachable!(), } *self.objects.get_mut(compartment_index).unwrap() = object; @@ -457,10 +494,17 @@ pub enum CompartmentEntry { Object(HeapObject), ReferenceArray(ReferenceArray), ByteArray(ByteArray), + CharArray(CharArray), EmptyNext(usize), EmptyTail(), // last empty value } +#[derive(Debug)] +pub struct CharArray { + class_ref: ObjectReference, + content: Box<[u16]>, +} + #[derive(Debug)] pub struct ByteArray { class_ref: ObjectReference, diff --git a/src/jvm.rs b/src/jvm.rs index 9a2b773..b34785b 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -193,7 +193,7 @@ impl JVM { ); } - fn make_primitive_class(&mut self, class_name: &str, class_descriptor: &str) -> ObjectReference { + fn make_primitive_class(&mut self, class_name: &str, class_descriptor: &str, string_names: bool) -> ObjectReference { let class_class_index = self.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap(); let data_class_index = self.class_store.class_idx_from_name(&String::from("::NativeClassData")).unwrap(); @@ -209,15 +209,17 @@ impl JVM { &self.class_store, ).unwrap(); - let name_string_ref = self.heap_area.make_handmade_string(&class_name.into(), &self.class_store); - // set name string object - self.heap_area.object_area.set_object_field( - primitive_class_object, - "name", - FieldValue::Reference(name_string_ref), - class_class_index, - &self.class_store, - ).unwrap(); + if string_names { + let name_string_ref = self.heap_area.make_handmade_string(&class_name.into(), &self.class_store); + // set name string object + self.heap_area.object_area.set_object_field( + primitive_class_object, + "name", + FieldValue::Reference(name_string_ref), + class_class_index, + &self.class_store, + ).unwrap(); + } // set native name index on class data self.heap_area.object_area.set_object_field( @@ -365,22 +367,7 @@ impl JVM { self.heap_area.fill_byte_cache(&self.class_store); - self.class_store.primitive_classes.int_class = self.make_primitive_class("int", "I"); - self.class_store.primitive_classes.byte_class = self.make_primitive_class("byte", "B"); - self.class_store.primitive_classes.char_class = self.make_primitive_class("char", "C"); - self.class_store.primitive_classes.long_class = self.make_primitive_class("long", "J"); - self.class_store.primitive_classes.float_class = self.make_primitive_class("float", "F"); - self.class_store.primitive_classes.short_class = self.make_primitive_class("short", "S"); - self.class_store.primitive_classes.double_class = self.make_primitive_class("double", "D"); - self.class_store.primitive_classes.boolean_class = self.make_primitive_class("boolean", "Z"); - - self.make_array_class( - self.class_store.primitive_classes.int_class, - AbstractTypeDescription { - array_level: 0, - kind: AbstractTypeKind::Int(), - } - ); + self.class_store.primitive_classes.byte_class = self.make_primitive_class("byte", "B", false); self.make_array_class( self.class_store.primitive_classes.byte_class, AbstractTypeDescription { @@ -388,6 +375,39 @@ impl JVM { kind: AbstractTypeKind::Byte(), } ); + { + // we can only make a byte class name after the byte array is loaded + let string_ref = self.heap_area.make_handmade_string(&String::from("byte"), &self.class_store); + self.heap_area.object_area.set_object_field( + self.class_store.primitive_classes.byte_class, + "name", + FieldValue::Reference(string_ref), + class_class_index, + &self.class_store + ).unwrap(); + } + self.class_store.primitive_classes.int_class = self.make_primitive_class("int", "I", true); + self.class_store.primitive_classes.char_class = self.make_primitive_class("char", "C", true); + self.class_store.primitive_classes.long_class = self.make_primitive_class("long", "J", true); + self.class_store.primitive_classes.float_class = self.make_primitive_class("float", "F", true); + self.class_store.primitive_classes.short_class = self.make_primitive_class("short", "S", true); + self.class_store.primitive_classes.double_class = self.make_primitive_class("double", "D", true); + self.class_store.primitive_classes.boolean_class = self.make_primitive_class("boolean", "Z", true); + + self.make_array_class( + self.class_store.primitive_classes.char_class, + AbstractTypeDescription { + array_level: 0, + kind: AbstractTypeKind::Char(), + } + ); + self.make_array_class( + self.class_store.primitive_classes.int_class, + AbstractTypeDescription { + array_level: 0, + kind: AbstractTypeKind::Int(), + } + ); let string_refs = arguments.iter() @@ -672,7 +692,7 @@ impl JVM { let element = self.heap_area.object_area.get_array_element(array_reference, element_index); - wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(element)))?; + wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(element))?; }, Instruction::BranchAlways(branch_offset) => { @@ -690,6 +710,16 @@ impl JVM { } } + Instruction::BranchIntGreaterEquals(branch_offset) => { + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + if value_1 >= value_2 { + frame.instruction_pointer -= offset as u32; + frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32}; + } + } + Instruction::BranchIntInequality(branch_offset) => { let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; @@ -774,6 +804,26 @@ impl JVM { } } + Instruction::CheckCast(classref_index) => { + // TODO: Class loading checks + let class_name = class.gather_class(classref_index)?; + let class_index = self.class_store.class_idx_from_name(class_name).unwrap(); + let class_object_ref = self.class_store.get_class_objectref_from_index(class_index); + let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store); + let class_description = AbstractTypeDescription::parse_full(native_class_description)?; + + let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store); + let object_description = AbstractTypeDescription::parse_full(native_class_name)?; + + if ! self.class_store.are_types_compatible(&object_description, &class_description) { + // TODO: Throw Exception + return Err(Error::RunTimeError(format!("Trying to cast an object of type {native_class_name} to {class_name}"))) + } + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(object)))?; + } + Instruction::CompareFloatG() => { let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; @@ -886,8 +936,27 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?; } + Instruction::IncrementLocalInt(index, constant) => { + let int = wrap_stackframe_error(class, method, frame.load_local_int(index as u16))?; + + wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Int(int + constant as i32)))?; + } + Instruction::InstanceOf(classref_index) => { + // TODO: Class loading checks let class_name = class.gather_class(classref_index)?; + let class_index = self.class_store.class_idx_from_name(class_name).unwrap(); + let class_object_ref = self.class_store.get_class_objectref_from_index(class_index); + let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store); + let class_description = AbstractTypeDescription::parse_full(native_class_description)?; + + let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store); + let object_description = AbstractTypeDescription::parse_full(native_class_name)?; + + let instruction_result = if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 }; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(instruction_result)))?; } Instruction::InvokeSpecial(methodref_index) => { @@ -1085,6 +1154,15 @@ impl JVM { } } + Instruction::LoadFromBArray() => { + let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let array = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + + let element = self.heap_area.object_area.get_array_element(array, index); + + wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(element))?; + } + Instruction::LoadConstant(index) => { // TODO: Handle error instead of unwrap match class.pool_entry(index as u16).unwrap() { @@ -1283,6 +1361,7 @@ impl JVM { Instruction::NewPrimitiveArray(array_type) => { let array_capacity = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + const CHAR: u8 = 5; const BYTE: u8 = 8; let array_ref = match array_type { BYTE => { @@ -1291,6 +1370,12 @@ impl JVM { array_ref } + CHAR => { + let array_ref = self.heap_area.make_primitive_char_array(array_capacity as usize, &self.class_store); + + array_ref + } + _ => todo!() }; @@ -1333,6 +1418,9 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(2.0)))?; } + Instruction::PushConstIntM1() => { + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(-1)))?; + } Instruction::PushConstInt0() => { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?; } @@ -1364,6 +1452,7 @@ impl JVM { _ => match wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))? { StackValue::Int(i) => FieldValue::Int(i), StackValue::Reference(r) => FieldValue::Reference(r), + StackValue::Float(f) => FieldValue::Float(f), stack_value @ _ => { println!("{stack_value:?}"); todo!() @@ -1511,31 +1600,38 @@ impl JVM { self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value)); } + Instruction::SubtractInt() => { + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 - value_2)))?; + } + Instruction::StoreLocalInt(index) => { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Int(int)))?; - }, + } Instruction::StoreLocalInt0() => { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?; - }, + } Instruction::StoreLocalInt1() => { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Int(int)))?; - }, + } Instruction::StoreLocalInt2() => { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Int(int)))?; - }, + } Instruction::StoreLocalInt3() => { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Int(int)))?; - }, + } Instruction::StoreReference0() => { let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; diff --git a/src/main.rs b/src/main.rs index 24a5a86..e8d5b95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,11 +15,13 @@ mod native_methods; //use crate::accessmasks::FieldAccessFlag; //use crate::stackframe::StackValue; //use crate::classfile::JavaClassFile; +use std::path::PathBuf; fn main() { //println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/System.class").unwrap()).unwrap()); let mut jvm = jvm::JVM::new(); + jvm.class_store.class_path_fragments.push(PathBuf::from("./classpath")); match jvm.entrypoint( &"Main".to_string(), diff --git a/src/native_methods.rs b/src/native_methods.rs index 6b3b2b9..2c3d291 100644 --- a/src/native_methods.rs +++ b/src/native_methods.rs @@ -49,6 +49,8 @@ impl JavaLangClass { }; // max_locals: 1 // max_stack: 1 + let class = jvm.class_store.class_file_from_idx(frame.class_index).unwrap(); + let method = &class.methods[frame.method_index as usize]; let class_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap(); let (string_class_file, string_class_index) = jvm.class_store.get_class(&String::from("java/lang/String")).unwrap(); let string_equals_index = string_class_file.find_method_index(&String::from("equals")).unwrap(); @@ -57,7 +59,9 @@ impl JavaLangClass { _ => unreachable!(), }; - match frame.instruction_pointer { + frame.instruction_pointer += 1; + + match frame.instruction_pointer - 1 { 0 => { let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class; let boolean_class_name_ref = match jvm.heap_area.object_area.get_object_field( @@ -77,10 +81,206 @@ impl JavaLangClass { &[StackValue::Reference(boolean_class_name_ref), StackValue::Reference(passed_wanted_string)], ); - frame.instruction_pointer += 1; - Ok(JVMCallbackOperation::PushFrame(string_compare_frame)) - }, + } + + 1 => { + if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { + let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class; + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(boolean_class_ref))) + } else { + let byte_class_ref = jvm.class_store.primitive_classes.byte_class; + let byte_class_name_ref = match jvm.heap_area.object_area.get_object_field( + byte_class_ref, + "name", + class_class_index, + &jvm.class_store + ).unwrap() { + FieldValue::Reference(r) => r, + _ => unreachable!(), + }; + + let string_compare_frame = StackFrame::new( + string_class_file, + string_class_index, + string_equals_index as u16, + &[StackValue::Reference(byte_class_name_ref), StackValue::Reference(passed_wanted_string)], + ); + + Ok(JVMCallbackOperation::PushFrame(string_compare_frame)) + } + } + + 2 => { + if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { + let char_class_ref = jvm.class_store.primitive_classes.char_class; + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(char_class_ref))) + } else { + let char_class_ref = jvm.class_store.primitive_classes.char_class; + let char_class_name_ref = match jvm.heap_area.object_area.get_object_field( + char_class_ref, + "name", + class_class_index, + &jvm.class_store + ).unwrap() { + FieldValue::Reference(r) => r, + _ => unreachable!(), + }; + + let string_compare_frame = StackFrame::new( + string_class_file, + string_class_index, + string_equals_index as u16, + &[StackValue::Reference(char_class_name_ref), StackValue::Reference(passed_wanted_string)], + ); + + Ok(JVMCallbackOperation::PushFrame(string_compare_frame)) + } + } + + 3 => { + if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { + let short_class_ref = jvm.class_store.primitive_classes.short_class; + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(short_class_ref))) + } else { + let short_class_ref = jvm.class_store.primitive_classes.short_class; + let short_class_name_ref = match jvm.heap_area.object_area.get_object_field( + short_class_ref, + "name", + class_class_index, + &jvm.class_store + ).unwrap() { + FieldValue::Reference(r) => r, + _ => unreachable!(), + }; + + let string_compare_frame = StackFrame::new( + string_class_file, + string_class_index, + string_equals_index as u16, + &[StackValue::Reference(short_class_name_ref), StackValue::Reference(passed_wanted_string)], + ); + + Ok(JVMCallbackOperation::PushFrame(string_compare_frame)) + } + } + + 4 => { + if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { + let int_class_ref = jvm.class_store.primitive_classes.int_class; + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(int_class_ref))) + } else { + let int_class_ref = jvm.class_store.primitive_classes.int_class; + let int_class_name_ref = match jvm.heap_area.object_area.get_object_field( + int_class_ref, + "name", + class_class_index, + &jvm.class_store + ).unwrap() { + FieldValue::Reference(r) => r, + _ => unreachable!(), + }; + + let string_compare_frame = StackFrame::new( + string_class_file, + string_class_index, + string_equals_index as u16, + &[StackValue::Reference(int_class_name_ref), StackValue::Reference(passed_wanted_string)], + ); + + Ok(JVMCallbackOperation::PushFrame(string_compare_frame)) + } + } + + 5 => { + if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { + let float_class_ref = jvm.class_store.primitive_classes.float_class; + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(float_class_ref))) + } else { + let float_class_ref = jvm.class_store.primitive_classes.float_class; + let float_class_name_ref = match jvm.heap_area.object_area.get_object_field( + float_class_ref, + "name", + class_class_index, + &jvm.class_store + ).unwrap() { + FieldValue::Reference(r) => r, + _ => unreachable!(), + }; + + let string_compare_frame = StackFrame::new( + string_class_file, + string_class_index, + string_equals_index as u16, + &[StackValue::Reference(float_class_name_ref), StackValue::Reference(passed_wanted_string)], + ); + + Ok(JVMCallbackOperation::PushFrame(string_compare_frame)) + } + } + + 6 => { + if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { + let double_class_ref = jvm.class_store.primitive_classes.double_class; + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(double_class_ref))) + } else { + let double_class_ref = jvm.class_store.primitive_classes.double_class; + let double_class_name_ref = match jvm.heap_area.object_area.get_object_field( + double_class_ref, + "name", + class_class_index, + &jvm.class_store + ).unwrap() { + FieldValue::Reference(r) => r, + _ => unreachable!(), + }; + + let string_compare_frame = StackFrame::new( + string_class_file, + string_class_index, + string_equals_index as u16, + &[StackValue::Reference(double_class_name_ref), StackValue::Reference(passed_wanted_string)], + ); + + Ok(JVMCallbackOperation::PushFrame(string_compare_frame)) + } + } + + 7 => { + if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { + let long_class_ref = jvm.class_store.primitive_classes.long_class; + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(long_class_ref))) + } else { + let long_class_ref = jvm.class_store.primitive_classes.long_class; + let long_class_name_ref = match jvm.heap_area.object_area.get_object_field( + long_class_ref, + "name", + class_class_index, + &jvm.class_store + ).unwrap() { + FieldValue::Reference(r) => r, + _ => unreachable!(), + }; + + let string_compare_frame = StackFrame::new( + string_class_file, + string_class_index, + string_equals_index as u16, + &[StackValue::Reference(long_class_name_ref), StackValue::Reference(passed_wanted_string)], + ); + + Ok(JVMCallbackOperation::PushFrame(string_compare_frame)) + } + } + + 8 => { + if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { + let long_class_ref = jvm.class_store.primitive_classes.long_class; + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(long_class_ref))) + } else { + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL))) + } + } _ => Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL))) } }