Type correction and opcode implementations
This commit is contained in:
parent
c6e4ecec3d
commit
b053461e74
5 changed files with 307 additions and 148 deletions
143
src/jvm.rs
143
src/jvm.rs
|
@ -553,7 +553,7 @@ impl JVM {
|
|||
AbstractTypeKind::Byte() => {
|
||||
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
|
||||
|
||||
FieldValue::Byte(int_entry.value as u8)
|
||||
FieldValue::Byte(int_entry.value as i8)
|
||||
},
|
||||
AbstractTypeKind::Char() => {
|
||||
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
|
||||
|
@ -678,6 +678,14 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_0 + value_1)))?;
|
||||
}
|
||||
|
||||
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))?;
|
||||
|
||||
|
@ -740,6 +748,16 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Instruction::BranchIntLessThan(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::BranchNonNull(branch_offset) => {
|
||||
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
|
@ -785,10 +803,10 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Instruction::BranchZero(branch_offset) => {
|
||||
Instruction::BranchPositive(branch_offset) => {
|
||||
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
if test_value == 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};
|
||||
}
|
||||
|
@ -804,6 +822,15 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Instruction::BranchZero(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::CheckCast(classref_index) => {
|
||||
// TODO: Class loading checks
|
||||
let class_name = class.gather_class(classref_index)?;
|
||||
|
@ -1110,10 +1137,7 @@ impl JVM {
|
|||
|
||||
// TODO: Throw error
|
||||
if ! self.class_store.are_types_compatible(&this_object_descriptor, &base_object_descriptor) {
|
||||
return Err(Error::RunTimeError(format!(
|
||||
"InvokeVirtual: Cannot call '{base_method_name}' from class '{base_class_name}' on instance from class '{}: Types are incompatible'",
|
||||
this_object_class_name
|
||||
)))
|
||||
return Err(Error::RunTimeError(format!("InvokeVirtual: Cannot call '{base_method_name}' from class '{base_class_name}' on instance from class '{this_object_class_name}: Types are incompatible'")))
|
||||
}
|
||||
|
||||
let (invoked_class_index, invoked_method_index, _invoked_method_info) = match ClassMethodIterator::new(this_object_class_index, &self.class_store)
|
||||
|
@ -1145,9 +1169,18 @@ impl JVM {
|
|||
|
||||
Instruction::LoadByteImmediate(byte) => {
|
||||
// sign extend into int
|
||||
let i8_int = i8::from_be_bytes([byte]);
|
||||
|
||||
let frame_result = frame.operand_stack.push(StackValue::Int(i8_int as i32));
|
||||
let frame_result = frame.operand_stack.push(StackValue::Int(byte as i32));
|
||||
match frame_result {
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
|
||||
}
|
||||
}
|
||||
|
||||
Instruction::LoadShortImmediate(short) => {
|
||||
// sign extend into int
|
||||
|
||||
let frame_result = frame.operand_stack.push(StackValue::Int(short as i32));
|
||||
match frame_result {
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
|
||||
|
@ -1263,13 +1296,19 @@ impl JVM {
|
|||
let string_obj_ref = self.heap_area.make_handmade_string(string_constant, &self.class_store);
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?;
|
||||
},
|
||||
}
|
||||
|
||||
ConstantPoolInfo::Integer(int_data) => {
|
||||
let int_value = int_data.value;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?;
|
||||
}
|
||||
_ => {
|
||||
println!("{:?}", class.pool_entry(wide_index).unwrap());
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Instruction::LoadLocalFloat0() => {
|
||||
load_local_float(class, method, frame, 0)?;
|
||||
|
@ -1297,6 +1336,9 @@ impl JVM {
|
|||
load_local_int(class, method, frame, 3)?;
|
||||
}
|
||||
|
||||
Instruction::LoadLocalReference(index) => {
|
||||
load_local_reference(class, method, frame, index as usize)?;
|
||||
}
|
||||
Instruction::LoadLocalReference0() => {
|
||||
load_local_reference(class, method, frame, 0)?;
|
||||
}
|
||||
|
@ -1310,6 +1352,27 @@ impl JVM {
|
|||
load_local_reference(class, method, frame, 3)?;
|
||||
}
|
||||
|
||||
Instruction::LogicalShiftIntRight() => {
|
||||
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))?;
|
||||
let uint = u32::from_ne_bytes(int.to_ne_bytes());
|
||||
let u_result = uint >> shift;
|
||||
let i_result = i32::from_ne_bytes(u_result.to_ne_bytes());
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(i_result)))?;
|
||||
}
|
||||
|
||||
Instruction::LookupSwitch(default_offset, pairs) => {
|
||||
let key = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let jump_offset = match pairs.binary_search_by(|(match_key, _offset)| match_key.cmp(&key)) {
|
||||
Ok(offset) => pairs[offset].1,
|
||||
Err(_) => default_offset,
|
||||
};
|
||||
|
||||
frame.instruction_pointer -= offset as u32;
|
||||
frame.instruction_pointer = if jump_offset < 0 { frame.instruction_pointer - jump_offset.abs() as u32} else { frame.instruction_pointer + jump_offset.abs() as u32};
|
||||
}
|
||||
|
||||
Instruction::MultiplyInt() => {
|
||||
let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
@ -1516,20 +1579,26 @@ impl JVM {
|
|||
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
if ref_value != ObjectReference::NULL {
|
||||
let value_native_name = self.heap_area.object_area.get_reference_native_class_name(ref_value, &self.class_store);
|
||||
let value_native_name = self.heap_area.object_area.get_reference_native_class_name(ref_value, &self.class_store);
|
||||
let parsed_native_name = AbstractTypeDescription::parse_first(value_native_name).unwrap().1;
|
||||
|
||||
if ! self.class_store.are_types_compatible(&matched_field.descriptor, &parsed_native_name) {
|
||||
if ! self.class_store.are_types_compatible(&parsed_native_name, &matched_field.descriptor) {
|
||||
return Err(Error::RunTimeError(format!("PutStatic: Trying to set a value with type '{parsed_native_name:?}' on a field with type '{:?}'", matched_field.descriptor)));
|
||||
}
|
||||
}
|
||||
|
||||
FieldValue::Reference(ref_value)
|
||||
}
|
||||
|
||||
(1..=255, _) => {
|
||||
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
FieldValue::Reference(ref_value)
|
||||
}
|
||||
|
||||
_ => {
|
||||
println!("{:?}", matched_field);
|
||||
todo!()
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?;
|
||||
|
@ -1568,13 +1637,6 @@ impl JVM {
|
|||
return Ok(JVMCallbackOperation::PopFrame());
|
||||
},
|
||||
|
||||
Instruction::ShiftIntRight() => {
|
||||
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))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?;
|
||||
},
|
||||
|
||||
Instruction::StoreIntoBArray() => {
|
||||
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
@ -1582,7 +1644,7 @@ impl JVM {
|
|||
|
||||
match self.heap_area.object_area.get_entry(array_ref) {
|
||||
CompartmentEntry::ByteArray(_) => {
|
||||
let byte_value = value.to_ne_bytes()[3];
|
||||
let byte_value = value as i8;
|
||||
|
||||
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Byte(byte_value));
|
||||
}
|
||||
|
@ -1590,6 +1652,22 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Instruction::StoreIntoCArray() => {
|
||||
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
match self.heap_area.object_area.get_entry(array_ref) {
|
||||
CompartmentEntry::CharArray(_) => {
|
||||
let int_bytes = value.to_ne_bytes();
|
||||
let char_value = u16::from_ne_bytes([int_bytes[2], int_bytes[3]]);
|
||||
|
||||
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Char(char_value));
|
||||
}
|
||||
_ => todo!(), // TODO: Handle as error
|
||||
}
|
||||
}
|
||||
|
||||
Instruction::StoreIntoRArray() => {
|
||||
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
@ -1633,26 +1711,31 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Int(int)))?;
|
||||
}
|
||||
|
||||
Instruction::StoreReference0() => {
|
||||
Instruction::StoreLocalReference(index) => {
|
||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Reference(reference)))?;
|
||||
}
|
||||
Instruction::StoreLocalReference0() => {
|
||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Reference(reference)))?;
|
||||
},
|
||||
Instruction::StoreReference1() => {
|
||||
}
|
||||
Instruction::StoreLocalReference1() => {
|
||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Reference(reference)))?;
|
||||
},
|
||||
Instruction::StoreReference2() => {
|
||||
}
|
||||
Instruction::StoreLocalReference2() => {
|
||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Reference(reference)))?;
|
||||
},
|
||||
Instruction::StoreReference3() => {
|
||||
}
|
||||
Instruction::StoreLocalReference3() => {
|
||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Reference(reference)))?;
|
||||
},
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction)))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue