Compare commits
5 commits
9190d3f7e7
...
022bfe9ee6
Author | SHA1 | Date | |
---|---|---|---|
022bfe9ee6 | |||
202d7692bc | |||
95beeef1c5 | |||
cc4166a814 | |||
49ce37402e |
2 changed files with 59 additions and 18 deletions
|
@ -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
|
||||
|
|
71
src/jvm.rs
71
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))?;
|
||||
|
|
Loading…
Reference in a new issue