From 272a34b7cd8a4e81628a104900ea93218ab7aa98 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Sun, 3 Nov 2024 17:42:04 +0100 Subject: [PATCH] Implemented a lot of opcodes and some native methods --- src/bytecode.rs | 40 +++++++- src/classfile.rs | 10 ++ src/jvm.rs | 222 +++++++++++++++++++++++++++++++++++------- src/native_methods.rs | 103 ++++++++++++++++---- src/stackframe.rs | 120 ++++++++++++++--------- 5 files changed, 394 insertions(+), 101 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 5af57e1..a88fdb3 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -35,12 +35,17 @@ impl Bytecode { 0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0x15 => (Instruction::LoadLocalInt(self.bytes[offset+1]), 2), + 0x16 => (Instruction::LoadLocalLong(self.bytes[offset+1]), 2), 0x17 => (Instruction::LoadLocalFloat(self.bytes[offset+1]), 2), 0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2), 0x1A => (Instruction::LoadLocalInt0(), 1), 0x1B => (Instruction::LoadLocalInt1(), 1), 0x1C => (Instruction::LoadLocalInt2(), 1), 0x1D => (Instruction::LoadLocalInt3(), 1), + 0x1E => (Instruction::LoadLocalLong0(), 1), + 0x1F => (Instruction::LoadLocalLong1(), 1), + 0x20 => (Instruction::LoadLocalLong2(), 1), + 0x21 => (Instruction::LoadLocalLong3(), 1), 0x22 => (Instruction::LoadLocalFloat0(), 1), 0x23 => (Instruction::LoadLocalFloat1(), 1), 0x24 => (Instruction::LoadLocalFloat2(), 1), @@ -64,6 +69,10 @@ impl Bytecode { 0x3C => (Instruction::StoreLocalInt1(), 1), 0x3D => (Instruction::StoreLocalInt2(), 1), 0x3E => (Instruction::StoreLocalInt3(), 1), + 0x3F => (Instruction::StoreLocalLong0(), 1), + 0x40 => (Instruction::StoreLocalLong1(), 1), + 0x41 => (Instruction::StoreLocalLong2(), 1), + 0x42 => (Instruction::StoreLocalLong3(), 1), 0x4B => (Instruction::StoreLocalReference0(), 1), 0x4C => (Instruction::StoreLocalReference1(), 1), 0x4D => (Instruction::StoreLocalReference2(), 1), @@ -80,11 +89,15 @@ impl Bytecode { 0x60 => (Instruction::AddInt(), 1), 0x64 => (Instruction::SubtractInt(), 1), + 0x65 => (Instruction::SubtractLong(), 1), 0x68 => (Instruction::MultiplyInt(), 1), + 0x69 => (Instruction::MultiplyLong(), 1), 0x6A => (Instruction::MultiplyFloat(), 1), 0x6C => (Instruction::DivideInt(), 1), 0x6D => (Instruction::DivideLong(), 1), + 0x74 => (Instruction::NegateInt(), 1), + 0x75 => (Instruction::NegateLong(), 1), 0x78 => (Instruction::ArithmeticShiftIntLeft(), 1), 0x7A => (Instruction::ArithmeticShiftIntRight(), 1), 0x7C => (Instruction::LogicalShiftIntRight(), 1), @@ -93,10 +106,14 @@ impl Bytecode { 0x80 => (Instruction::OrInt(), 1), 0x82 => (Instruction::XorInt(), 1), 0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3), + 0x85 => (Instruction::ConvertIntToLong(), 1), 0x86 => (Instruction::ConvertIntToFloat(), 1), + 0x88 => (Instruction::ConvertLongToInt(), 1), 0x8B => (Instruction::ConvertFloatToInt(), 1), + 0x91 => (Instruction::ConvertIntToByte(), 1), 0x92 => (Instruction::ConvertIntToChar(), 1), + 0x94 => (Instruction::CompareLong(), 1), 0x95 => (Instruction::CompareFloatL(), 1), 0x96 => (Instruction::CompareFloatG(), 1), 0x99 => { @@ -207,6 +224,7 @@ impl Bytecode { (Instruction::LookupSwitch(default, pairs_vec.into()), 1 + padding + 4 + 4 + npairs as usize * 8) } 0xAC => (Instruction::ReturnInt(), 1), + 0xAD => (Instruction::ReturnLong(), 1), 0xB0 => (Instruction::ReturnReference(), 1), 0xB1 => (Instruction::ReturnVoid(), 1), @@ -289,13 +307,18 @@ pub enum Instruction { LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load // double or long or whatever LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool - LoadLocalInt(u8) = 0x15, // Load int from indexed local variable - LoadLocalFloat(u8) = 0x17, // Load int from indexed local variable + LoadLocalInt(u8) = 0x15, // Load int from indexed local variable + LoadLocalLong(u8) = 0x16, // Load long from indexed local variable + LoadLocalFloat(u8) = 0x17, // Load float from indexed local variable LoadLocalReference(u8) = 0x19, // Load reference from indexed local variable LoadLocalInt0() = 0x1A, // Load int from local variable LoadLocalInt1() = 0x1B, // Load int from local variable LoadLocalInt2() = 0x1C, // Load int from local variable LoadLocalInt3() = 0x1D, // Load int from local variable + LoadLocalLong0() = 0x1E, // load long from local variable + LoadLocalLong1() = 0x1F, // load long from local variable + LoadLocalLong2() = 0x20, // load long from local variable + LoadLocalLong3() = 0x21, // load long from local variable LoadLocalFloat0() = 0x22, // Load local double variable reference onto stack LoadLocalFloat1() = 0x23, // Load local double variable reference onto stack @@ -320,6 +343,10 @@ pub enum Instruction { StoreLocalInt1() = 0x3C, // store int into local variable StoreLocalInt2() = 0x3D, // store int into local variable StoreLocalInt3() = 0x3E, // store int into local variable + StoreLocalLong0() = 0x3F, // store int into local variable + StoreLocalLong1() = 0x40, // store int into local variable + StoreLocalLong2() = 0x41, // store int into local variable + StoreLocalLong3() = 0x42, // store int into local variable StoreLocalReference0() = 0x4B, // store reference into local variable StoreLocalReference1() = 0x4C, // store reference into local variable StoreLocalReference2() = 0x4D, // store reference into local variable @@ -335,11 +362,15 @@ pub enum Instruction { AddInt() = 0x60, // int addition SubtractInt() = 0x64, // int subtraction + SubtractLong() = 0x65, // long subtraction MultiplyInt() = 0x68, // int multiplication + MultiplyLong() = 0x69, // long multiplication MultiplyFloat() = 0x6A, // float multiplication DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideLong() = 0x6D, // long division + NegateInt() = 0x74, // arithmetic negation + NegateLong() = 0x75, // arithmetic negation ArithmeticShiftIntLeft() = 0x78, // shift int left, preserve sign ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign LogicalShiftIntRight() = 0x7C, // shift int right with zero extension @@ -348,10 +379,14 @@ pub enum Instruction { OrInt() = 0x80, // value, value => or XorInt() = 0x82, // value, value => xor IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8 + ConvertIntToLong() = 0x85, // convert int on stack to long ConvertIntToFloat() = 0x86, // change data type + ConvertLongToInt() = 0x88, // change data type ConvertFloatToInt() = 0x8B, // change data type + ConvertIntToByte() = 0x91, // truncate int to 8 bits ConvertIntToChar() = 0x92, // truncate int to 16 bits + CompareLong() = 0x94, // compare long 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 @@ -374,6 +409,7 @@ pub enum Instruction { TableSwitch(i32, i32, i32, Box<[i32]>) = 0xAA, // jump based on indexed range LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // jump based on switch value ReturnInt() = 0xAC, // return integer from function + ReturnLong() = 0xAD, // return long from function ReturnReference() = 0xB0, // return top-ref from current function ReturnVoid() = 0xB1, // return void from function diff --git a/src/classfile.rs b/src/classfile.rs index a2dd4b6..9ae184a 100644 --- a/src/classfile.rs +++ b/src/classfile.rs @@ -6,6 +6,7 @@ use core::str::Utf8Error; use crate::accessmasks::*; use crate::bytecode::Bytecode; use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantInterfaceMethodRefInfo, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo }; +use crate::constantpool::ConstantDoubleInfo; #[derive(Debug)] pub enum Error { @@ -266,6 +267,15 @@ impl JavaClassFile { }; } + pub fn pool_double_entry(&self, index: u16) -> Result<&ConstantDoubleInfo, Error> { + let pool_entry = self.pool_entry(index)?; + + return match pool_entry { + ConstantPoolInfo::Double(data) => Ok(data), + _ => Err(Error::BadFileError(format!("Expected constant pool entry {} in class {} to be of type Double but found {:?}", index, self.get_classname()?, pool_entry))) + }; + } + pub fn pool_long_entry(&self, index: u16) -> Result<&ConstantLongInfo, Error> { let pool_entry = self.pool_entry(index)?; diff --git a/src/jvm.rs b/src/jvm.rs index e3b7c36..f2ad7eb 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -442,7 +442,7 @@ impl JVM { }; let class = self.class_store.class_file_from_idx(frame.class_index).unwrap(); let method = & class.methods[frame.method_index as usize]; - wrap_stackframe_error(class, method, self.stack_frames.last_mut().unwrap().operand_stack.push(value))?; + wrap_stackframe_error(class, method, self.stack_frames.last_mut().unwrap().operand_stack.push_field_value(value))?; } JVMCallbackOperation::PushFrame(frame) => self.stack_frames.push(frame), @@ -580,6 +580,11 @@ impl JVM { FieldValue::Float(float_entry.value) }, + AbstractTypeKind::Double() => { + let double_entry = class_file.pool_double_entry(constant_value_info.constant_value_index)?; + + FieldValue::Double(double_entry.value) + } AbstractTypeKind::Classname(ref name) => { if name == "java/lang/String" { let string_entry = class_file.gather_string(constant_value_info.constant_value_index)?; @@ -880,26 +885,28 @@ impl JVM { // TODO: Class loading checks let class_name = class.gather_class(classref_index)?; let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; - let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store); + if object != ObjectReference::NULL { + let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store); - let instruction_result = if class_name == native_class_name { - 1 - } else { - let class_index = self.class_store.class_idx_from_name(class_name).unwrap(); - let class_object_ref = self.class_store.get_class_objectref_from_index(class_index); - let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store); - let class_description = AbstractTypeDescription::parse_full(native_class_description)?; + let instruction_result = if class_name == native_class_name { + 1 + } else { + let class_index = self.class_store.class_idx_from_name(class_name).unwrap(); + let class_object_ref = self.class_store.get_class_objectref_from_index(class_index); + let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store); + let class_description = AbstractTypeDescription::parse_full(native_class_description)?; - let object_description = AbstractTypeDescription::parse_full(native_class_name)?; - if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 } - }; + let object_description = AbstractTypeDescription::parse_full(native_class_name)?; + if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 } + }; - if instruction_result == 0 { - // TODO: Throw Exception - return Err(Error::RunTimeError(format!("Trying to cast an object of type {native_class_name} to {class_name}"))) + if instruction_result == 0 { + // TODO: Throw Exception + return Err(Error::RunTimeError(format!("Trying to cast an object of type {native_class_name} to {class_name}"))) + } } - wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(object)))?; + } Instruction::CompareFloatG() => { @@ -936,6 +943,20 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(comparison_result)))?; } + Instruction::CompareLong() => { + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let comparison_result = if value_1 > value_2 { + 1 + } else if value_1 < value_2 { + -1 + } else { + 0 + }; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(comparison_result)))?; + } + Instruction::ConvertFloatToInt() => { let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; let int_value = match float { @@ -947,6 +968,13 @@ impl JVM { frame.operand_stack.push(StackValue::Int(int_value)).unwrap(); } + Instruction::ConvertIntToByte() => { + let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let byte_value = int_value & 0x000000FF; + + frame.operand_stack.push(StackValue::Int(byte_value)).unwrap(); + } + Instruction::ConvertIntToChar() => { let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let char_value = int_value & 0x0000FFFF; @@ -961,6 +989,20 @@ impl JVM { frame.operand_stack.push(StackValue::Float(float_value)).unwrap(); } + Instruction::ConvertIntToLong() => { + let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let long_value = int_value as i64; + + wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?; + } + + Instruction::ConvertLongToInt() => { + let long_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let int_value = long_value as i32; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?; + } + Instruction::DivideInt() => { // TODO: Obey all the rules let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; @@ -969,6 +1011,15 @@ impl JVM { frame.operand_stack.push(StackValue::Int(divident / quotient)).unwrap(); } + Instruction::DivideLong() => { + // TODO: Obey all the rules + let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let divident = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let result = divident / quotient; + + wrap_stackframe_error(class, method, frame.operand_stack.push_long(result))?; + } + Instruction::Duplicate() => { let popped_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?; wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?; @@ -1474,6 +1525,11 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?; } + ConstantPoolInfo::Float(float_data) => { + let float_value = float_data.value; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(float_value)))?; + } _ => { println!("{:?}", class.pool_entry(wide_index).unwrap()); todo!() @@ -1488,6 +1544,11 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?; } + ConstantPoolInfo::Double(double_data) => { + let double = double_data.value; + + wrap_stackframe_error(class, method, frame.operand_stack.push_double(double))?; + } _ => { println!("{:?}", class.pool_entry(wide_index).unwrap()); todo!() @@ -1527,6 +1588,28 @@ impl JVM { load_local_int(class, method, frame, 3)?; } + Instruction::LoadLocalLong(index) => { + let long_value = wrap_stackframe_error(class, method, frame.load_local_long(index as u16))?; + + wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?; + } + Instruction::LoadLocalLong0() => { + let long_value = wrap_stackframe_error(class, method, frame.load_local_long(0))?; + wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?; + } + Instruction::LoadLocalLong1() => { + let long_value = wrap_stackframe_error(class, method, frame.load_local_long(1))?; + wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?; + } + Instruction::LoadLocalLong2() => { + let long_value = wrap_stackframe_error(class, method, frame.load_local_long(2))?; + wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?; + } + Instruction::LoadLocalLong3() => { + let long_value = wrap_stackframe_error(class, method, frame.load_local_long(3))?; + wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?; + } + Instruction::LoadLocalReference(index) => { load_local_reference(class, method, frame, index as usize)?; } @@ -1588,6 +1671,27 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(java_result)))?; } + Instruction::MultiplyLong() => { + let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + + let result = factor_1 * factor_2; + + wrap_stackframe_error(class, method, frame.operand_stack.push_long(result))?; + } + + Instruction::NegateInt() => { + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let negated = -int; + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(negated)))?; + } + + Instruction::NegateLong() => { + let long = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let negated = -long; + wrap_stackframe_error(class, method, frame.operand_stack.push_long(negated))?; + } + Instruction::NewArray(component_class_index) => { // construct single level array let component_class_name = class.gather_class(component_class_index)?; @@ -1743,6 +1847,7 @@ impl JVM { StackValue::Int(i) => FieldValue::Int(i), StackValue::Reference(r) => FieldValue::Reference(r), StackValue::Float(f) => FieldValue::Float(f), + StackValue::Byte(b) => FieldValue::Byte(b), stack_value @ _ => { println!("{stack_value:?}"); todo!() @@ -1845,17 +1950,28 @@ impl JVM { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; - return Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(int))); + return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(int))); + } + Instruction::ReturnLong() => { + match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) { + (0, AbstractTypeKind::Long()) => (), + _ => return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type))) + } + + let long = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + + return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Long(long))); } Instruction::ReturnReference() => { match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) { + (1..=u8::MAX, _) => (), (_, AbstractTypeKind::Classname(_)) => (), _ => return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type))) } let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; - return Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ref_value))); + return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(ref_value))); } Instruction::ReturnVoid() => { let expected_type = AbstractTypeDescription { @@ -1928,6 +2044,13 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 - value_2)))?; } + Instruction::SubtractLong() => { + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + + wrap_stackframe_error(class, method, frame.operand_stack.push_long(value_1 - value_2))?; + } + Instruction::StoreLocalFloat(index) => { let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; @@ -1961,11 +2084,39 @@ impl JVM { } Instruction::StoreLocalLong(index) => { - let long1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long1(0))?; + let _ = wrap_stackframe_error(class, method, frame.operand_stack.pop_long1(0))?; let long0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long0(0))?; wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Long0(long0)))?; - wrap_stackframe_error(class, method, frame.store_local(index as u16 + 1, StackValue::Long1(long1)))?; + wrap_stackframe_error(class, method, frame.store_local(index as u16 + 1, StackValue::Long1()))?; + } + Instruction::StoreLocalLong0() => { + let _ = wrap_stackframe_error(class, method, frame.operand_stack.pop_long1(0))?; + let long0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long0(0))?; + + wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Long0(long0)))?; + wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Long1()))?; + } + Instruction::StoreLocalLong1() => { + let _ = wrap_stackframe_error(class, method, frame.operand_stack.pop_long1(0))?; + let long0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long0(0))?; + + wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Long0(long0)))?; + wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Long1()))?; + } + Instruction::StoreLocalLong2() => { + let _ = wrap_stackframe_error(class, method, frame.operand_stack.pop_long1(0))?; + let long0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long0(0))?; + + wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Long0(long0)))?; + wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Long1()))?; + } + Instruction::StoreLocalLong3() => { + let _ = wrap_stackframe_error(class, method, frame.operand_stack.pop_long1(0))?; + let long0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long0(0))?; + + wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Long0(long0)))?; + wrap_stackframe_error(class, method, frame.store_local(4, StackValue::Long1()))?; } Instruction::StoreLocalReference(index) => { @@ -2029,7 +2180,7 @@ impl JVM { pub enum JVMCallbackOperation { PopFrame(), - ReturnFrame(StackValue), + ReturnFrame(FieldValue), PushFrame(StackFrame), LoadClass(String), InitClass(String), @@ -2053,9 +2204,9 @@ fn load_local_float(class: &JavaClassFile, method: &MethodInfo, frame: &mut Stac } fn load_local_int(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> { - let loaded_value = wrap_stackframe_error(class, method, frame.load_local_int(index as u16))?; + let int_compatible_stackvalue = wrap_stackframe_error(class, method, frame.load_local_int_compatible(index as u16))?; - wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(loaded_value)))?; + wrap_stackframe_error(class, method, frame.operand_stack.push(int_compatible_stackvalue))?; Ok(()) } @@ -2095,15 +2246,12 @@ fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut Ve ) }, AbstractTypeKind::Double() => { - arguments.push_front( - StackValue::Double1( - wrap_stackframe_error( - class, - method, - stack.pop_double1(0) - )? - ) - ); + wrap_stackframe_error( + class, + method, + stack.pop_double1(0) + )?; + arguments.push_front(StackValue::Double1()); arguments.push_front( StackValue::Double0( wrap_stackframe_error( @@ -2137,13 +2285,13 @@ fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut Ve ) }, AbstractTypeKind::Long() => { + wrap_stackframe_error( + class, + method, + stack.pop_long1(0) + )?; arguments.push_front( StackValue::Long1( - wrap_stackframe_error( - class, - method, - stack.pop_long1(0) - )? ) ); arguments.push_front( diff --git a/src/native_methods.rs b/src/native_methods.rs index 71f8fa3..f87c138 100644 --- a/src/native_methods.rs +++ b/src/native_methods.rs @@ -87,7 +87,7 @@ impl JavaLangClass { 1 => { if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(boolean_class_ref))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(boolean_class_ref))) } else { let byte_class_ref = jvm.class_store.primitive_classes.byte_class; let byte_class_name_ref = match jvm.heap_area.object_area.get_object_field( @@ -114,7 +114,7 @@ impl JavaLangClass { 2 => { if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { let char_class_ref = jvm.class_store.primitive_classes.char_class; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(char_class_ref))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(char_class_ref))) } else { let char_class_ref = jvm.class_store.primitive_classes.char_class; let char_class_name_ref = match jvm.heap_area.object_area.get_object_field( @@ -141,7 +141,7 @@ impl JavaLangClass { 3 => { if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { let short_class_ref = jvm.class_store.primitive_classes.short_class; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(short_class_ref))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(short_class_ref))) } else { let short_class_ref = jvm.class_store.primitive_classes.short_class; let short_class_name_ref = match jvm.heap_area.object_area.get_object_field( @@ -168,7 +168,7 @@ impl JavaLangClass { 4 => { if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { let int_class_ref = jvm.class_store.primitive_classes.int_class; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(int_class_ref))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(int_class_ref))) } else { let int_class_ref = jvm.class_store.primitive_classes.int_class; let int_class_name_ref = match jvm.heap_area.object_area.get_object_field( @@ -195,7 +195,7 @@ impl JavaLangClass { 5 => { if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { let float_class_ref = jvm.class_store.primitive_classes.float_class; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(float_class_ref))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(float_class_ref))) } else { let float_class_ref = jvm.class_store.primitive_classes.float_class; let float_class_name_ref = match jvm.heap_area.object_area.get_object_field( @@ -222,7 +222,7 @@ impl JavaLangClass { 6 => { if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { let double_class_ref = jvm.class_store.primitive_classes.double_class; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(double_class_ref))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(double_class_ref))) } else { let double_class_ref = jvm.class_store.primitive_classes.double_class; let double_class_name_ref = match jvm.heap_area.object_area.get_object_field( @@ -249,7 +249,7 @@ impl JavaLangClass { 7 => { if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { let long_class_ref = jvm.class_store.primitive_classes.long_class; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(long_class_ref))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(long_class_ref))) } else { let long_class_ref = jvm.class_store.primitive_classes.long_class; let long_class_name_ref = match jvm.heap_area.object_area.get_object_field( @@ -276,17 +276,55 @@ impl JavaLangClass { 8 => { if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 { let long_class_ref = jvm.class_store.primitive_classes.long_class; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(long_class_ref))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(long_class_ref))) } else { - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(ObjectReference::NULL))) } } - _ => Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL))) + _ => Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(ObjectReference::NULL))) } } pub fn desired_assertion_status_0(_: &mut JVM) -> Result { - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(1))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(1))) + } +} + +struct JavaLangFloat {} + +impl JavaLangFloat { + pub fn float_to_raw_int_bits(jvm: &mut JVM) -> Result { + let frame = { + let frame_index = jvm.stack_frames.len() - 1; + &mut jvm.stack_frames[frame_index] + }; + let class = jvm.class_store.class_file_from_idx(frame.class_index).unwrap(); + let method = & class.methods[frame.method_index as usize]; + + let float_value = wrap_stackframe_error(class, method, frame.load_local_float(0))?; + let ubits = float_value.to_bits(); + let ibits = i32::from_ne_bytes(ubits.to_ne_bytes()); + + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(ibits))) + } +} + +struct JavaLangDouble {} + +impl JavaLangDouble { + pub fn double_to_raw_long_bits(jvm: &mut JVM) -> Result { + let frame = { + let frame_index = jvm.stack_frames.len() - 1; + &mut jvm.stack_frames[frame_index] + }; + let class = jvm.class_store.class_file_from_idx(frame.class_index).unwrap(); + let method = & class.methods[frame.method_index as usize]; + + let double_value = wrap_stackframe_error(class, method, frame.load_local_double(0))?; + let ubits = double_value.to_bits(); + let ibits = i64::from_ne_bytes(ubits.to_ne_bytes()); + + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Long(ibits))) } } @@ -294,7 +332,7 @@ struct JavaLangStringUTF16 {} impl JavaLangStringUTF16 { pub fn is_big_endian(_jvm: &mut JVM) -> Result { - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(if cfg!(target_endian = "big") {1} else {0}))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(if cfg!(target_endian = "big") {1} else {0}))) } } @@ -336,12 +374,12 @@ impl JdkInternalMiscUnsafe { std::mem::size_of::() as i32 }; - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(index_scale))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(index_scale))) } pub fn array_base_offset_0(jvm: &mut JVM) -> Result { // TODO: Check passed class - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(0))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(0))) } } @@ -390,7 +428,7 @@ impl JdkInternalUtilSystemPropsRaw { } - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(array_reference))) } // command-line configured properties, should return at least java.home @@ -404,6 +442,7 @@ impl JdkInternalUtilSystemPropsRaw { ("user.country", "US"), ("user.variant", ""), ("sun.nio.MaxDirectMemorySize", "9223372036854775807"), + ("sun.nio.PageAlignDirectMemory", "false"), ]; // TODO: Cross-Platform tmpdir // TODO: locale detection @@ -420,7 +459,7 @@ impl JdkInternalUtilSystemPropsRaw { jvm.heap_area.object_area.set_array_element(array_reference, index * 2 + 1, value_reference.into()); } - Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference))) + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(array_reference))) } } @@ -921,6 +960,36 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul Ok(todo_call) } + ("java/lang/Double", "doubleToRawLongBits") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Double() } + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long() }, + }; + + 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(JavaLangDouble::double_to_raw_long_bits) + } + + ("java/lang/Double", "longBitsToDouble") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long() } + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Double() }, + }; + + 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(JavaLangDouble::double_to_raw_long_bits) + } + ("java/lang/Float", "intBitsToFloat") => { let expected_descriptor = MethodDescriptor { argument_types: Box::new([ @@ -948,7 +1017,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul 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(todo_call) + Ok(JavaLangFloat::float_to_raw_int_bits) } ("java/lang/String", "intern") => { diff --git a/src/stackframe.rs b/src/stackframe.rs index 8ef95c0..ce6ce48 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -6,17 +6,17 @@ use crate::heap_area::{ ObjectReference, FieldValue }; #[derive(Copy, Clone, Debug)] pub enum StackValue { Boolean(bool), - Byte(u8), + Byte(i8), Char(u16), Short(u16), Int(i32), Float(f32), Reference(ObjectReference), ReturnAddress(u32), - Double0(u32), - Double1(u32), - Long0(u32), - Long1(u32), + Double0(f64), + Double1(), + Long0(i64), + Long1(), Empty(), } @@ -59,12 +59,15 @@ impl OperandStack { } pub fn push_long(&mut self, long: i64) -> Result<(), Error> { - let long_bytes: [u8; 8] = long.to_be_bytes(); + self.push(StackValue::Long0(long))?; + self.push(StackValue::Long1())?; - let long0_bytes = u32::from_be_bytes([long_bytes[0], long_bytes[1], long_bytes[2], long_bytes[3]]); - self.push(StackValue::Long0(long0_bytes))?; - let long1_bytes = u32::from_be_bytes([long_bytes[4], long_bytes[5], long_bytes[6], long_bytes[7]]); - self.push(StackValue::Long1(long1_bytes))?; + Ok(()) + } + + pub fn push_double(&mut self, double: f64) -> Result<(), Error> { + self.push(StackValue::Double0(double))?; + self.push(StackValue::Double1())?; Ok(()) } @@ -91,6 +94,10 @@ impl OperandStack { self.push(StackValue::Float(i)) } + FieldValue::Long(l) => { + self.push_long(l) + } + _ => { println!("{value:?}"); todo!(); @@ -106,19 +113,12 @@ impl OperandStack { self.depth -= 2; match (value_bot, value_top) { - (StackValue::Long0(l0), StackValue::Long1(l1)) => { - let l0_bytes = l0.to_ne_bytes(); - let l1_bytes = l1.to_ne_bytes(); - let concat_bytes = [l0_bytes[0], l0_bytes[1], l0_bytes[2], l0_bytes[3], l1_bytes[0], l1_bytes[1], l1_bytes[2], l1_bytes[3]]; + (StackValue::Long0(l0), StackValue::Long1()) => { - Ok(FieldValue::Long(i64::from_ne_bytes(concat_bytes))) + Ok(FieldValue::Long(l0)) } - (StackValue::Double0(d0), StackValue::Double1(d1)) => { - let d0_bytes = d0.to_ne_bytes(); - let d1_bytes = d1.to_ne_bytes(); - let concat_bytes = [d0_bytes[0], d0_bytes[1], d0_bytes[2], d0_bytes[3], d1_bytes[0], d1_bytes[1], d1_bytes[2], d1_bytes[3]]; - - Ok(FieldValue::Double(f64::from_ne_bytes(concat_bytes))) + (StackValue::Double0(d0), StackValue::Double1()) => { + Ok(FieldValue::Double(d0)) } _ => Err(Error::LocalError(format!("Mismatched type at index {index} of the function operand stack, expected type with computational type 2 but found '{value_bot:?}, {value_top:?}'"))) } @@ -130,7 +130,7 @@ impl OperandStack { self.depth -= 1; match value { - StackValue::Long0(_) | StackValue::Long1(_) | StackValue::Double0(_) | StackValue::Double1(_) => { + StackValue::Long0(_) | StackValue::Long1() | StackValue::Double0(_) | StackValue::Double1() => { Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected type with computational type 1 but found '{:?}'", index, value))) }, _ => Ok(value), @@ -147,12 +147,13 @@ impl OperandStack { } } - pub fn pop_byte(&mut self, index: usize) -> Result { + pub fn pop_byte(&mut self, index: usize) -> Result { let absolute_index = self.depth as usize - 1 - index; let value = self.stack[absolute_index]; + self.depth -= 1; match value { - StackValue::Byte(b) => Ok(b), - _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Byte but found '{:?}'", index, value))) + StackValue::Int(b) => Ok(b as i8), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Int(Byte) but found '{:?}'", index, value))) } } @@ -225,7 +226,7 @@ impl OperandStack { } } - pub fn pop_double0(&mut self, index: usize) -> Result { + pub fn pop_double0(&mut self, index: usize) -> Result { let absolute_index = self.depth as usize - 1 - index; let value = self.stack[absolute_index]; self.depth -= 1; @@ -235,17 +236,17 @@ impl OperandStack { } } - pub fn pop_double1(&mut self, index: usize) -> Result { + pub fn pop_double1(&mut self, index: usize) -> Result<(), Error> { let absolute_index = self.depth as usize - 1 - index; let value = self.stack[absolute_index]; self.depth -= 1; match value { - StackValue::Double1(a) => Ok(a), + StackValue::Double1() => Ok(()), _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Double1 but found '{:?}'", index, value))) } } - pub fn pop_long0(&mut self, index: usize) -> Result { + pub fn pop_long0(&mut self, index: usize) -> Result { let absolute_index = self.depth as usize - 1 - index; let value = self.stack[absolute_index]; self.depth -= 1; @@ -255,12 +256,12 @@ impl OperandStack { } } - pub fn pop_long1(&mut self, index: usize) -> Result { + pub fn pop_long1(&mut self, index: usize) -> Result<(), Error> { let absolute_index = self.depth as usize - 1 - index; let value = self.stack[absolute_index]; self.depth -= 1; match value { - StackValue::Long1(a) => Ok(a), + StackValue::Long1() => Ok(()), _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Long1 but found '{:?}'", index, value))) } } @@ -271,11 +272,8 @@ impl OperandStack { let lower_bytes = self.stack[absolute_index + 1]; self.depth -= 2; match (higher_bytes, lower_bytes) { - (StackValue::Double0(hi), StackValue::Double1(lo)) => { - let v: u64 = ((hi as u64) << 32) | lo as u64; - Ok( - f64::from_bits(v) - ) + (StackValue::Double0(double), StackValue::Double1()) => { + Ok(double) }, _ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Double0, Double1) but found '{:?}'", index, (higher_bytes, lower_bytes)))) } @@ -283,17 +281,14 @@ impl OperandStack { pub fn pop_long(&mut self, index: usize) -> Result { let absolute_index = self.depth as usize - 1 - index; - let lower_bytes = self.stack[absolute_index]; - let higher_bytes = self.stack[absolute_index - 1]; + let long0 = self.stack[absolute_index]; + let long1 = self.stack[absolute_index - 1]; self.depth -= 2; - match (higher_bytes, lower_bytes) { - (StackValue::Long0(hi), StackValue::Long1(lo)) => { - let concat_u64 = ((hi as u64) << 32) | lo as u64; - let concat_array = concat_u64.to_ne_bytes(); - let long_value = i64::from_ne_bytes(concat_array); - Ok(long_value) + match (long1, long0) { + (StackValue::Long0(long), StackValue::Long1()) => { + Ok(long) }, - _ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Long0, Long1) but found '{:?}'", index, (higher_bytes, lower_bytes)))) + _ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Long0, Long1) but found '{:?}'", index, (long1, long0)))) } } } @@ -339,6 +334,18 @@ impl StackFrame { } } + pub fn load_local_long(&self, index: u16) -> Result { + let long0 = self.locals[index as usize]; + let long1 = self.locals[index as usize + 1]; + + match (long0, long1) { + (StackValue::Long0(long), StackValue::Long1()) => { + Ok(long) + } + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function locals, expected Long0, Long1 but found '{:?},{:?}'", index, long0, long1))) + } + } + pub fn load_local_float(&self, index: u16) -> Result { let local = self.locals[index as usize]; match local { @@ -347,6 +354,18 @@ impl StackFrame { } } + pub fn load_local_double(&self, index: u16) -> Result { + let double0 = self.locals[index as usize]; + let double1 = self.locals[index as usize + 1]; + + match (double0, double1) { + (StackValue::Double0(double), StackValue::Double1()) => { + Ok(double) + } + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function locals, expected Long0, Long1 but found '{:?},{:?}'", index, double0, double1))) + } + } + pub fn load_local_int(&self, index: u16) -> Result { let local = self.locals[index as usize]; match local { @@ -355,6 +374,17 @@ impl StackFrame { } } + pub fn load_local_int_compatible(&self, index: u16) -> Result { + let local = self.locals[index as usize]; + match local { + StackValue::Int(_) => Ok(local), + StackValue::Short(_) => Ok(local), + StackValue::Char(_) => Ok(local), + StackValue::Byte(_) => Ok(local), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function locals, expected Int but found '{:?}'", index, local))) + } + } + pub fn load_local_reference(&self, index: u16) -> Result { let local = self.locals[index as usize]; match local {