diff --git a/src/bytecode.rs b/src/bytecode.rs index 5082bf2..38247c2 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), @@ -87,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 => { @@ -324,7 +326,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 @@ -332,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 bb3f02f..c1f869e 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))?; @@ -765,6 +772,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))?; @@ -898,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))?; @@ -1019,19 +1042,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 +1061,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() ); @@ -1542,7 +1568,18 @@ 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::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))?; + + 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))?;