Type correction and opcode implementations

This commit is contained in:
VegOwOtenks 2024-09-10 17:15:20 +02:00
parent c6e4ecec3d
commit b053461e74
5 changed files with 307 additions and 148 deletions

View file

@ -25,12 +25,16 @@ impl Bytecode {
0x0E => (Instruction::PushConstDouble0(), 1), 0x0E => (Instruction::PushConstDouble0(), 1),
0x0F => (Instruction::PushConstDouble1(), 1), 0x0F => (Instruction::PushConstDouble1(), 1),
0x10 => (Instruction::LoadByteImmediate(self.bytes[offset+1]), 2), 0x10 => (Instruction::LoadByteImmediate(i8::from_be_bytes([self.bytes[offset+1]])), 2),
0x11 => (Instruction::LoadShortImmediate((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0x11 => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::LoadShortImmediate(i16::from_be_bytes(bytes)), 3)
}
0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2), 0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2),
0x13 => (Instruction::LoadCostantWide((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0x13 => (Instruction::LoadCostantWide((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2),
0x1A => (Instruction::LoadLocalInt0(), 1), 0x1A => (Instruction::LoadLocalInt0(), 1),
0x1B => (Instruction::LoadLocalInt1(), 1), 0x1B => (Instruction::LoadLocalInt1(), 1),
0x1C => (Instruction::LoadLocalInt2(), 1), 0x1C => (Instruction::LoadLocalInt2(), 1),
@ -51,17 +55,19 @@ impl Bytecode {
0x32 => (Instruction::ArrayElement(), 1), 0x32 => (Instruction::ArrayElement(), 1),
0x33 => (Instruction::LoadFromBArray(), 1), 0x33 => (Instruction::LoadFromBArray(), 1),
0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2), 0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2),
0x3A => (Instruction::StoreLocalReference(self.bytes[offset+1]), 2),
0x3B => (Instruction::StoreLocalInt0(), 1), 0x3B => (Instruction::StoreLocalInt0(), 1),
0x3C => (Instruction::StoreLocalInt1(), 1), 0x3C => (Instruction::StoreLocalInt1(), 1),
0x3D => (Instruction::StoreLocalInt2(), 1), 0x3D => (Instruction::StoreLocalInt2(), 1),
0x3E => (Instruction::StoreLocalInt3(), 1), 0x3E => (Instruction::StoreLocalInt3(), 1),
0x4B => (Instruction::StoreReference0(), 1), 0x4B => (Instruction::StoreLocalReference0(), 1),
0x4C => (Instruction::StoreReference1(), 1), 0x4C => (Instruction::StoreLocalReference1(), 1),
0x4D => (Instruction::StoreReference2(), 1), 0x4D => (Instruction::StoreLocalReference2(), 1),
0x4E => (Instruction::StoreReference3(), 1), 0x4E => (Instruction::StoreLocalReference3(), 1),
0x53 => (Instruction::StoreIntoRArray(), 1), 0x53 => (Instruction::StoreIntoRArray(), 1),
0x54 => (Instruction::StoreIntoBArray(), 1), 0x54 => (Instruction::StoreIntoBArray(), 1),
0x55 => (Instruction::StoreIntoCArray(), 1),
0x57 => (Instruction::Pop(), 1), 0x57 => (Instruction::Pop(), 1),
0x59 => (Instruction::Duplicate(), 1), 0x59 => (Instruction::Duplicate(), 1),
@ -72,7 +78,8 @@ impl Bytecode {
0x6C => (Instruction::DivideInt(), 1), 0x6C => (Instruction::DivideInt(), 1),
0x6D => (Instruction::DivideLong(), 1), 0x6D => (Instruction::DivideLong(), 1),
0x7A => (Instruction::ShiftIntRight(), 1), 0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
0x7C => (Instruction::LogicalShiftIntRight(), 1),
0x80 => (Instruction::OrInt(), 1), 0x80 => (Instruction::OrInt(), 1),
0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3), 0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3),
@ -136,13 +143,31 @@ impl Bytecode {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchReferenceInequality(i16::from_be_bytes(bytes)), 3) (Instruction::BranchReferenceInequality(i16::from_be_bytes(bytes)), 3)
} }
0xAC => (Instruction::ReturnInt(), 1),
0xA7 => { 0xA7 => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchAlways(i16::from_be_bytes(bytes)), 3) (Instruction::BranchAlways(i16::from_be_bytes(bytes)), 3)
} }
0xAB => {
let padding = 4 - (offset % 4) - 1;
let default_bytes = [self.bytes[offset+padding+1], self.bytes[offset+padding+2], self.bytes[offset+padding+3], self.bytes[offset+padding+4]];
let default = i32::from_be_bytes(default_bytes);
let npairs_bytes = [self.bytes[offset+padding+5], self.bytes[offset+padding+6], self.bytes[offset+padding+7], self.bytes[offset+padding+8]];
let npairs = i32::from_be_bytes(npairs_bytes);
let mut pairs_vec = Vec::with_capacity(npairs as usize);
for i in 0..npairs as usize {
let match_bytes = [self.bytes[offset+padding+8*(1+i)+1], self.bytes[offset+padding+8*(1+i)+2], self.bytes[offset+padding+8*(1+i)+3], self.bytes[offset+padding+8*(1+i)+4]];
let offset_bytes = [self.bytes[offset+padding+8*(1+i)+5], self.bytes[offset+padding+8*(1+i)+6], self.bytes[offset+padding+8*(1+i)+7], self.bytes[offset+padding+8*(1+i)+8]];
pairs_vec.push((i32::from_be_bytes(match_bytes), i32::from_be_bytes(offset_bytes)));
}
(Instruction::LookupSwitch(default, pairs_vec.into()), 1 + padding + 4 + 4 + npairs as usize * 8)
}
0xAC => (Instruction::ReturnInt(), 1),
0xB0 => (Instruction::ReturnReference(), 1), 0xB0 => (Instruction::ReturnReference(), 1),
0xB1 => (Instruction::ReturnVoid(), 1), 0xB1 => (Instruction::ReturnVoid(), 1),
0xB2 => (Instruction::GetStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xB2 => (Instruction::GetStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
@ -217,12 +242,13 @@ pub enum Instruction {
PushConstDouble0() = 0x0E, // Push 0.0 PushConstDouble0() = 0x0E, // Push 0.0
PushConstDouble1() = 0x0F, // Push 1.0 PushConstDouble1() = 0x0F, // Push 1.0
LoadByteImmediate(u8) = 0x10, // push immediate short LoadByteImmediate(i8) = 0x10, // push immediate short
LoadShortImmediate(u16) = 0x11, // push immediate short LoadShortImmediate(i16) = 0x11, // push immediate short
LoadConstant(u8) = 0x12, // Push from constant pool LoadConstant(u8) = 0x12, // Push from constant pool
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
// double or long or whatever // double or long or whatever
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
LoadLocalReference(u8) = 0x19, // Load reference from indexed local variable
LoadLocalInt0() = 0x1A, // Load int from local variable LoadLocalInt0() = 0x1A, // Load int from local variable
LoadLocalInt1() = 0x1B, // Load int from local variable LoadLocalInt1() = 0x1B, // Load int from local variable
LoadLocalInt2() = 0x1C, // Load int from local variable LoadLocalInt2() = 0x1C, // Load int from local variable
@ -244,17 +270,19 @@ pub enum Instruction {
ArrayElement() = 0x32, // load element from array ArrayElement() = 0x32, // load element from array
LoadFromBArray() = 0x33, // store into byte array LoadFromBArray() = 0x33, // store into byte array
StoreLocalInt(u8) = 0x36, // store into indexed local variable StoreLocalInt(u8) = 0x36, // store into indexed local variable
StoreLocalReference(u8) = 0x3A, // store into indexed local variable
StoreLocalInt0() = 0x3B, // store int into local variable StoreLocalInt0() = 0x3B, // store int into local variable
StoreLocalInt1() = 0x3C, // store int into local variable StoreLocalInt1() = 0x3C, // store int into local variable
StoreLocalInt2() = 0x3D, // store int into local variable StoreLocalInt2() = 0x3D, // store int into local variable
StoreLocalInt3() = 0x3E, // store int into local variable StoreLocalInt3() = 0x3E, // store int into local variable
StoreReference0() = 0x4B, // store reference into local variable StoreLocalReference0() = 0x4B, // store reference into local variable
StoreReference1() = 0x4C, // store reference into local variable StoreLocalReference1() = 0x4C, // store reference into local variable
StoreReference2() = 0x4D, // store reference into local variable StoreLocalReference2() = 0x4D, // store reference into local variable
StoreReference3() = 0x4E, // store reference into local variable StoreLocalReference3() = 0x4E, // store reference into local variable
StoreIntoRArray() = 0x53, // store value into reference array StoreIntoRArray() = 0x53, // store value into reference array
StoreIntoBArray() = 0x54, // store value into byte or boolean array StoreIntoBArray() = 0x54, // store value into byte or boolean array
StoreIntoCArray() = 0x55, // store value into char array
Pop() = 0x57, // Pop top stack value Pop() = 0x57, // Pop top stack value
Duplicate() = 0x59, // duplicate top stack value Duplicate() = 0x59, // duplicate top stack value
@ -264,7 +292,8 @@ pub enum Instruction {
DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideInt() = 0x6C, // integer division, round toward zero and more rules
DivideLong() = 0x6D, // long division DivideLong() = 0x6D, // long division
ShiftIntRight() = 0x7a, // shift int ArithmeticShiftIntRight() = 0x7A, // shift int
LogicalShiftIntRight() = 0x7C, // shift int right with zero extension
OrInt() = 0x80, // value, value => or OrInt() = 0x80, // value, value => or
IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8 IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8
@ -288,6 +317,7 @@ pub enum Instruction {
BranchReferenceInequality(i16) = 0xA6, BranchReferenceInequality(i16) = 0xA6,
BranchAlways(i16) = 0xA7, // branch if true BranchAlways(i16) = 0xA7, // branch if true
LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // offset based on switch value
ReturnInt() = 0xAC, // return integer from function ReturnInt() = 0xAC, // return integer from function
ReturnReference() = 0xB0, // return top-ref from current function ReturnReference() = 0xB0, // return top-ref from current function

View file

@ -156,10 +156,12 @@ impl ClassStore {
}; };
let compatible_count = CompatibleTypesIterator::new(my_type_index, self) let compatible_count = CompatibleTypesIterator::new(my_type_index, self)
.filter(|type_name| *type_name == other_type_name) .filter(|type_name|
*type_name == other_type_name
)
.count(); .count();
compatible_count == 0 compatible_count != 0
} }
pub fn have_class(&self, classname: &String) -> bool { pub fn have_class(&self, classname: &String) -> bool {

View file

@ -79,14 +79,14 @@ impl HeapArea {
let byte_array_ref = self.make_primitive_byte_array(utf16_bytes.len(), class_store); let byte_array_ref = self.make_primitive_byte_array(utf16_bytes.len(), class_store);
for (index, byte) in utf16_bytes.iter().enumerate() { for (index, byte) in utf16_bytes.iter().enumerate() {
self.object_area.set_array_element(byte_array_ref, index, FieldValue::Byte(*byte)); self.object_area.set_array_element(byte_array_ref, index, FieldValue::Byte(i8::from_ne_bytes([*byte])));
} }
let string_class_index = class_store.class_idx_from_name(&String::from("java/lang/String")).unwrap(); 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); let string_ref = self.make_object(class_store, string_class_index);
self.object_area.set_object_field(string_ref, "value", FieldValue::Reference(byte_array_ref), string_class_index, class_store).unwrap(); self.object_area.set_object_field(string_ref, "value", FieldValue::Reference(byte_array_ref), string_class_index, class_store).unwrap();
const UTF16_CODER: u8 = 1; // TODO: I don't like this const UTF16_CODER: i8 = 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(); self.object_area.set_object_field(string_ref, "coder", FieldValue::Byte(UTF16_CODER), string_class_index, class_store).unwrap();
string_ref string_ref
@ -104,6 +104,12 @@ impl HeapArea {
pub struct ObjectReference(u32); pub struct ObjectReference(u32);
impl Into<FieldValue> for ObjectReference {
fn into(self) -> FieldValue {
FieldValue::Reference(self)
}
}
impl ObjectReference { impl ObjectReference {
pub const NULL: ObjectReference = ObjectReference(0); pub const NULL: ObjectReference = ObjectReference(0);
} }
@ -125,7 +131,7 @@ impl ObjectArea {
fn fill_byte_cache(&mut self, class_store: &ClassStore) -> usize { fn fill_byte_cache(&mut self, class_store: &ClassStore) -> usize {
let byte_class_index = class_store.class_idx_from_name(&String::from("java/lang/Byte")).unwrap(); let byte_class_index = class_store.class_idx_from_name(&String::from("java/lang/Byte")).unwrap();
let mut total_memory_usage = 0; let mut total_memory_usage = 0;
for byte in 0..=u8::MAX { for byte in i8::MIN..=i8::MAX {
let (byte_object_ref, object_memory) = self.make(class_store, byte_class_index); let (byte_object_ref, object_memory) = self.make(class_store, byte_class_index);
self.set_object_field(byte_object_ref, "value", FieldValue::Byte(byte), byte_class_index, class_store).unwrap(); self.set_object_field(byte_object_ref, "value", FieldValue::Byte(byte), byte_class_index, class_store).unwrap();
@ -154,7 +160,7 @@ impl ObjectArea {
let array_object = ByteArray { let array_object = ByteArray {
class_ref: array_class_ref, class_ref: array_class_ref,
content: vec![0_u8; capacity].into(), content: vec![0_i8; capacity].into(),
}; };
let array_ref = self.store_entry(CompartmentEntry::ByteArray(array_object)); let array_ref = self.store_entry(CompartmentEntry::ByteArray(array_object));
@ -350,12 +356,17 @@ impl ObjectArea {
let array_element = array.content.get_mut(index).unwrap(); let array_element = array.content.get_mut(index).unwrap();
*array_element = match element { FieldValue::Reference(r) => r, _ => unreachable!() } ; *array_element = match element { FieldValue::Reference(r) => r, _ => unreachable!() } ;
}, }
CompartmentEntry::ByteArray(array) => { CompartmentEntry::ByteArray(array) => {
let array_element = array.content.get_mut(index).unwrap(); let array_element = array.content.get_mut(index).unwrap();
*array_element = match element { FieldValue::Byte(b) => b, _ => unreachable!() } ; *array_element = match element { FieldValue::Byte(b) => b, _ => unreachable!() } ;
}, }
CompartmentEntry::CharArray(array) => {
let array_element = array.content.get_mut(index).unwrap();
*array_element = match element { FieldValue::Char(c) => c, _ => unreachable!() } ;
}
_ => unreachable!(), _ => unreachable!(),
}; };
@ -508,7 +519,7 @@ pub struct CharArray {
#[derive(Debug)] #[derive(Debug)]
pub struct ByteArray { pub struct ByteArray {
class_ref: ObjectReference, class_ref: ObjectReference,
content: Box<[u8]>, content: Box<[i8]>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -639,7 +650,7 @@ pub struct ObjectField {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum FieldValue { pub enum FieldValue {
Boolean(bool), Boolean(bool),
Byte(u8), Byte(i8),
Char(u16), Char(u16),
Short(i16), Short(i16),
Int(i32), Int(i32),
@ -674,7 +685,7 @@ impl FieldValue {
AbstractTypeKind::Long() => Self::Long(0), AbstractTypeKind::Long() => Self::Long(0),
AbstractTypeKind::Classname(_) => Self::Reference(ObjectReference::NULL), AbstractTypeKind::Classname(_) => Self::Reference(ObjectReference::NULL),
AbstractTypeKind::Short() => Self::Short(0), AbstractTypeKind::Short() => Self::Short(0),
AbstractTypeKind::Boolean() => Self::Boolean(true), AbstractTypeKind::Boolean() => Self::Boolean(false),
} }
} }
} }

View file

@ -553,7 +553,7 @@ impl JVM {
AbstractTypeKind::Byte() => { AbstractTypeKind::Byte() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?; 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() => { AbstractTypeKind::Char() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?; 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)))?; 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() => { Instruction::ArrayLength() => {
let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; 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) => { Instruction::BranchNonNull(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; 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))?; 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 -= 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}; 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) => { Instruction::CheckCast(classref_index) => {
// TODO: Class loading checks // TODO: Class loading checks
let class_name = class.gather_class(classref_index)?; let class_name = class.gather_class(classref_index)?;
@ -1110,10 +1137,7 @@ impl JVM {
// TODO: Throw error // TODO: Throw error
if ! self.class_store.are_types_compatible(&this_object_descriptor, &base_object_descriptor) { if ! self.class_store.are_types_compatible(&this_object_descriptor, &base_object_descriptor) {
return Err(Error::RunTimeError(format!( 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'")))
"InvokeVirtual: Cannot call '{base_method_name}' from class '{base_class_name}' on instance from class '{}: Types are incompatible'",
this_object_class_name
)))
} }
let (invoked_class_index, invoked_method_index, _invoked_method_info) = match ClassMethodIterator::new(this_object_class_index, &self.class_store) 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) => { Instruction::LoadByteImmediate(byte) => {
// sign extend into int // 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 { match frame_result {
Ok(_) => (), Ok(_) => (),
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), 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); 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)))?; 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()); println!("{:?}", class.pool_entry(wide_index).unwrap());
todo!() todo!()
} }
} }
}, }
Instruction::LoadLocalFloat0() => { Instruction::LoadLocalFloat0() => {
load_local_float(class, method, frame, 0)?; load_local_float(class, method, frame, 0)?;
@ -1297,6 +1336,9 @@ impl JVM {
load_local_int(class, method, frame, 3)?; load_local_int(class, method, frame, 3)?;
} }
Instruction::LoadLocalReference(index) => {
load_local_reference(class, method, frame, index as usize)?;
}
Instruction::LoadLocalReference0() => { Instruction::LoadLocalReference0() => {
load_local_reference(class, method, frame, 0)?; load_local_reference(class, method, frame, 0)?;
} }
@ -1310,6 +1352,27 @@ impl JVM {
load_local_reference(class, method, frame, 3)?; 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() => { Instruction::MultiplyInt() => {
let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; 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))?; let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
@ -1519,17 +1582,23 @@ impl JVM {
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; 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))); 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) 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); println!("{:?}", matched_field);
todo!() todo!()
}, }
}; };
self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?; self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?;
@ -1568,13 +1637,6 @@ impl JVM {
return Ok(JVMCallbackOperation::PopFrame()); 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() => { Instruction::StoreIntoBArray() => {
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; 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 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) { match self.heap_area.object_area.get_entry(array_ref) {
CompartmentEntry::ByteArray(_) => { 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)); 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() => { Instruction::StoreIntoRArray() => {
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; 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))?; 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)))?; 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))?; 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)))?; 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))?; 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)))?; 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))?; 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)))?; 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))?; 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)))?; wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Reference(reference)))?;
}, }
_ => { _ => {
return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction))) return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction)))

View file

@ -290,6 +290,14 @@ impl JavaLangClass {
} }
} }
struct JavaLangStringUTF16 {}
impl JavaLangStringUTF16 {
pub fn is_big_endian(_jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(if cfg!(target_endian = "big") {1} else {0})))
}
}
struct JdkInternalMiscUnsafe {} struct JdkInternalMiscUnsafe {}
impl JdkInternalMiscUnsafe { impl JdkInternalMiscUnsafe {
@ -357,8 +365,19 @@ impl JdkInternalUtilSystemPropsRaw {
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference))) Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
} }
// command-line configured properties, should return at least java.home
pub fn vm_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> { pub fn vm_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
let array_reference = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, 2); let array_length = 4;
let array_reference = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, array_length);
{
// TODO: Actual java home path
let java_home_key_reference = jvm.heap_area.make_handmade_string(&String::from("java.home"), &jvm.class_store);
let java_home_value_reference = jvm.heap_area.make_handmade_string(&String::from("./"), &jvm.class_store);
jvm.heap_area.object_area.set_array_element(array_reference, 0, java_home_key_reference.into());
jvm.heap_area.object_area.set_array_element(array_reference, 1, java_home_value_reference.into());
}
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference))) Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
} }
@ -896,6 +915,20 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
Ok(todo_call) Ok(todo_call)
} }
("java/lang/StringUTF16", "isBigEndian") => {
// until JDK 23
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(JavaLangStringUTF16::is_big_endian)
}
("java/lang/Object", "clone") => { ("java/lang/Object", "clone") => {
let expected_descriptor = MethodDescriptor { let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]), argument_types: Box::new([]),