From 49ce37402ea68c5774d94f7051f0e68ff9ae6cc9 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Wed, 11 Sep 2024 00:25:37 +0200 Subject: [PATCH 1/5] Find implementation of invokeinterface method --- src/jvm.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/jvm.rs b/src/jvm.rs index bb3f02f..06a3e3e 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -1019,19 +1019,9 @@ impl JVM { let target_interface_class_index = self.class_store.class_idx_from_name(supplied_interface_name).unwrap(); let parsed_expected_descriptor: MethodDescriptor = MethodDescriptor::try_from(supplied_descriptor_string)?; - let (class_index, method_index, method_info) = match ClassMethodIterator::new(target_interface_class_index, &self.class_store) - .filter(|(_cid, _mid, minfo)| minfo.name == *supplied_method_name) - .filter(|(_cid, _mid, minfo)| minfo.descriptor == parsed_expected_descriptor) - .next() { - Some(m) => m, - None => { - // TODO: Throw exception - return Err(Error::RunTimeError(format!("InvokeInterface: Failed to find requested method '{}' with descriptor '{}' in the class '{}'", supplied_method_name, supplied_descriptor_string, supplied_interface_name))); - } - }; let mut arguments = VecDeque::new(); - fill_arguments(class, method, &mut arguments, &method_info.descriptor.argument_types, &mut frame.operand_stack)?; + fill_arguments(class, method, &mut arguments, &parsed_expected_descriptor.argument_types, &mut frame.operand_stack)?; let this_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; arguments.push_front(StackValue::Reference(this_object)); @@ -1048,11 +1038,24 @@ impl JVM { } } - // TODO: I hate this, now I have to find the 'implementation' of a function - let interface_class_file = self.class_store.class_file_from_idx(target_interface_class_index).unwrap(); + // TODO: Filter abstract + // TODO: Check method info match + let (class_index, method_index, _method_info) = match ClassMethodIterator::new(object_class_index, &self.class_store) + .filter(|(_cid, _mid, minfo)| minfo.name == *supplied_method_name) + .filter(|(_cid, _mid, minfo)| minfo.descriptor == parsed_expected_descriptor) + .next() { + Some(m) => m, + None => { + // TODO: Throw exception + return Err(Error::RunTimeError(format!("InvokeInterface: Failed to find requested implementation of method '{}' with descriptor '{}' in the class '{}'", supplied_method_name, supplied_descriptor_string, supplied_interface_name))); + } + }; + + + let implementing_class_file = self.class_store.class_file_from_idx(class_index).unwrap(); let interface_frame = StackFrame::new( - interface_class_file, - target_interface_class_index, + implementing_class_file, + class_index, method_index as u16, arguments.make_contiguous() ); From cc4166a814624585b30aeafd80511c63588200bc Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Wed, 11 Sep 2024 00:26:54 +0200 Subject: [PATCH 2/5] Implement BranchNegative --- src/jvm.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/jvm.rs b/src/jvm.rs index 06a3e3e..1879548 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -765,6 +765,15 @@ impl JVM { } } + Instruction::BranchNegative(branch_offset) => { + let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + if test_value < 0 { + 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::BranchNonNull(branch_offset) => { let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; From 95beeef1c5535e8b0b4f331fafd998a77afbdc17 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Wed, 11 Sep 2024 00:31:31 +0200 Subject: [PATCH 3/5] Implement ArithmeticShiftIntLeft, OrInt --- src/bytecode.rs | 4 +++- src/jvm.rs | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 5082bf2..21185ff 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -79,6 +79,7 @@ impl Bytecode { 0x6C => (Instruction::DivideInt(), 1), 0x6D => (Instruction::DivideLong(), 1), + 0x78 => (Instruction::ArithmeticShiftIntLeft(), 1), 0x7A => (Instruction::ArithmeticShiftIntRight(), 1), 0x7C => (Instruction::LogicalShiftIntRight(), 1), 0x7E => (Instruction::AndInt(), 1), @@ -324,7 +325,8 @@ pub enum Instruction { DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideLong() = 0x6D, // long division - ArithmeticShiftIntRight() = 0x7A, // shift int + ArithmeticShiftIntLeft() = 0x78, // shift int left, preserve sign + ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign LogicalShiftIntRight() = 0x7C, // shift int right with zero extension AndInt() = 0x7E, // bitwise and diff --git a/src/jvm.rs b/src/jvm.rs index 1879548..108a53a 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -678,13 +678,20 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_0 + value_1)))?; } + Instruction::ArithmeticShiftIntLeft() => { + let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00011111; + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + // rust does arithmetic shift on singed values + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int << shift)))?; + } Instruction::ArithmeticShiftIntRight() => { let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00011111; let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; // rust does arithmetic shift on singed values wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?; - }, + } Instruction::ArrayLength() => { let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; @@ -1554,7 +1561,14 @@ impl JVM { let new_object = self.heap_area.make_object(&self.class_store, class_index); wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(new_object)))?; - }, + } + + Instruction::OrInt() => { + let value_0 = 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_0 | value_1)))?; + } Instruction::Pop() => { wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?; From 202d7692bc70eefa26c0ee5d01a8ad279073e8ac Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Wed, 11 Sep 2024 00:36:55 +0200 Subject: [PATCH 4/5] Implement ConvertIntToChar --- src/bytecode.rs | 2 ++ src/jvm.rs | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/bytecode.rs b/src/bytecode.rs index 21185ff..38247c2 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -88,6 +88,7 @@ impl Bytecode { 0x82 => (Instruction::XorInt(), 1), 0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3), + 0x92 => (Instruction::ConvertIntToChar(), 1), 0x95 => (Instruction::CompareFloatL(), 1), 0x96 => (Instruction::CompareFloatG(), 1), 0x99 => { @@ -334,6 +335,7 @@ pub enum Instruction { XorInt() = 0x82, // value, value => xor IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8 + ConvertIntToChar() = 0x92, // truncate int to 16 bits CompareFloatL() = 0x95, // compare float, push -1 if one is NaN CompareFloatG() = 0x96, // compare float, push 1 if one is NaN BranchZero(i16) = 0x99, // branch if value == 0 diff --git a/src/jvm.rs b/src/jvm.rs index 108a53a..731cb5f 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -914,6 +914,13 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(comparison_result)))?; } + Instruction::ConvertIntToChar() => { + let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let char_value = int_value & 0x0000FFFF; + + frame.operand_stack.push(StackValue::Int(char_value)).unwrap(); + } + Instruction::DivideInt() => { // TODO: Obey all the rules let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; From 022bfe9ee60bc1160e02d846ffc4548ca1695e30 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Wed, 11 Sep 2024 00:38:35 +0200 Subject: [PATCH 5/5] I just implemented no-op --- src/jvm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jvm.rs b/src/jvm.rs index 731cb5f..c1f869e 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -1570,6 +1570,10 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(new_object)))?; } + Instruction::NoOperation() => { + + } + Instruction::OrInt() => { let value_0 = 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))?;