From b4c33a0d9be6bc21b811cb582050e7c9f0060068 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Tue, 22 Oct 2024 13:01:20 +0200 Subject: [PATCH] stdout und stderr encoding --- src/bytecode.rs | 14 ++++++++- src/jvm.rs | 72 +++++++++++++++++++++++++++++++++++++++++-- src/native_methods.rs | 28 +++++++++++++++++ src/stackframe.rs | 8 +++-- 4 files changed, 116 insertions(+), 6 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 38247c2..a0ff1c4 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -35,6 +35,7 @@ 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), + 0x17 => (Instruction::LoadLocalFloat(self.bytes[offset+1]), 2), 0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2), 0x1A => (Instruction::LoadLocalInt0(), 1), 0x1B => (Instruction::LoadLocalInt1(), 1), @@ -56,6 +57,7 @@ impl Bytecode { 0x32 => (Instruction::ArrayElement(), 1), 0x33 => (Instruction::LoadFromBArray(), 1), 0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2), + 0x38 => (Instruction::StoreLocalFloat(self.bytes[offset+1]), 2), 0x3A => (Instruction::StoreLocalReference(self.bytes[offset+1]), 2), 0x3B => (Instruction::StoreLocalInt0(), 1), 0x3C => (Instruction::StoreLocalInt1(), 1), @@ -72,10 +74,12 @@ impl Bytecode { 0x57 => (Instruction::Pop(), 1), 0x59 => (Instruction::Duplicate(), 1), + 0x5A => (Instruction::DuplicateInsertDown(), 1), 0x60 => (Instruction::AddInt(), 1), 0x64 => (Instruction::SubtractInt(), 1), 0x68 => (Instruction::MultiplyInt(), 1), + 0x6A => (Instruction::MultiplyFloat(), 1), 0x6C => (Instruction::DivideInt(), 1), 0x6D => (Instruction::DivideLong(), 1), @@ -88,6 +92,8 @@ impl Bytecode { 0x82 => (Instruction::XorInt(), 1), 0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3), + 0x86 => (Instruction::ConvertIntToFloat(), 1), + 0x8B => (Instruction::ConvertFloatToInt(), 1), 0x92 => (Instruction::ConvertIntToChar(), 1), 0x95 => (Instruction::CompareFloatL(), 1), 0x96 => (Instruction::CompareFloatG(), 1), @@ -209,7 +215,7 @@ impl Bytecode { 0xB6 => (Instruction::InvokeVirtual((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xB7 => (Instruction::InvokeSpecial((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xB8 => (Instruction::InvokeStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), - 0xB9 => (Instruction::InvokeInterface((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), + 0xB9 => (Instruction::InvokeInterface((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 5), // TODO: Figure out the additional arguments 0xBA => (Instruction::InvokeDynamic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16, (self.bytes[offset+3] as u16) << 8 | self.bytes[offset+4] as u16), 5), 0xBB => (Instruction::NewObject((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xBC => (Instruction::NewPrimitiveArray(self.bytes[offset+1]), 2), @@ -282,6 +288,7 @@ pub enum Instruction { // 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 LoadLocalReference(u8) = 0x19, // Load reference from indexed local variable LoadLocalInt0() = 0x1A, // Load int from local variable LoadLocalInt1() = 0x1B, // Load int from local variable @@ -304,6 +311,7 @@ pub enum Instruction { ArrayElement() = 0x32, // load element from array LoadFromBArray() = 0x33, // store into byte array StoreLocalInt(u8) = 0x36, // store into indexed local variable + StoreLocalFloat(u8) = 0x38, // store into indexed local variable StoreLocalReference(u8) = 0x3A, // store into indexed local variable StoreLocalInt0() = 0x3B, // store int into local variable StoreLocalInt1() = 0x3C, // store int into local variable @@ -319,10 +327,12 @@ pub enum Instruction { StoreIntoCArray() = 0x55, // store value into char array Pop() = 0x57, // Pop top stack value Duplicate() = 0x59, // duplicate top stack value + DuplicateInsertDown() = 0x5A, // duplicate top stack value and insert two low AddInt() = 0x60, // int addition SubtractInt() = 0x64, // int subtraction MultiplyInt() = 0x68, // int multiplication + MultiplyFloat() = 0x6A, // float multiplication DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideLong() = 0x6D, // long division @@ -335,6 +345,8 @@ pub enum Instruction { XorInt() = 0x82, // value, value => xor IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8 + ConvertIntToFloat() = 0x86, // change data type + ConvertFloatToInt() = 0x8B, // change data type 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 diff --git a/src/jvm.rs b/src/jvm.rs index c1f869e..bcb39dc 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -667,7 +667,9 @@ impl JVM { let (instruction, offset) = bytecode.next_instruction(frame.instruction_pointer as usize); frame.instruction_pointer += offset as u32; - println!("{}{:25}.{:15}:{:<10}{instruction:?}", " ".repeat(frame_index), class.get_classname().unwrap(), method.name, frame.instruction_pointer); + //println!("{} locals: {:?}", " ".repeat(frame_index), frame.locals); + println!("{} stack: {:?}", " ".repeat(frame_index), frame.operand_stack); + println!("{}{:25}.{:15}:{:<10}{instruction:?}\n", " ".repeat(frame_index), class.get_classname().unwrap(), method.name, frame.instruction_pointer); match instruction { @@ -835,6 +837,16 @@ impl JVM { } } + Instruction::BranchReferenceEquality(branch_offset) => { + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(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::BranchReferenceInequality(branch_offset) => { let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; @@ -914,6 +926,17 @@ impl JVM { 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 { + f32::INFINITY => i32::MAX, + f32::NEG_INFINITY => i32::MIN, + v @ _ => if v.is_nan() { 0 } else { v as i32 } , + }; + + frame.operand_stack.push(StackValue::Int(int_value)).unwrap(); + } + Instruction::ConvertIntToChar() => { let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let char_value = int_value & 0x0000FFFF; @@ -921,6 +944,13 @@ impl JVM { frame.operand_stack.push(StackValue::Int(char_value)).unwrap(); } + Instruction::ConvertIntToFloat() => { + let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let float_value = int_value as f32; + + frame.operand_stack.push(StackValue::Float(float_value)).unwrap(); + } + Instruction::DivideInt() => { // TODO: Obey all the rules let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; @@ -935,6 +965,15 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?; } + Instruction::DuplicateInsertDown() => { + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?; + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?; + + wrap_stackframe_error(class, method, frame.operand_stack.push(value_1))?; + wrap_stackframe_error(class, method, frame.operand_stack.push(value_2))?; + wrap_stackframe_error(class, method, frame.operand_stack.push(value_1))?; + } + Instruction::EnterMonitor() => { // TODO: Revisit this when doing multi-threading let _monitored_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; @@ -1410,6 +1449,9 @@ impl JVM { } } + Instruction::LoadLocalFloat(index) => { + load_local_float(class, method, frame, index as usize)?; + } Instruction::LoadLocalFloat0() => { load_local_float(class, method, frame, 0)?; } @@ -1476,10 +1518,28 @@ impl JVM { 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::MultiplyFloat() => { + let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; + let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; + + let result = factor_1 * factor_2; + let java_result = result; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(java_result)))?; + } + 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))?; - wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(factor_1 * factor_2)))?; + + let (result, overflowed) = i32::overflowing_mul(factor_1, factor_2); + let java_result = match (overflowed, factor_1, factor_2) { + (true, 0..=i32::MAX, 0..=i32::MAX) => if result > 0 { -result } else { result }, + (true, 0..=i32::MAX, i32::MIN..0) | (true, i32::MIN..0, 0..=i32::MAX) => if result < 0 { -result } else { result }, + (true, i32::MIN..0, i32::MIN..0) => if result > 0 { - result } else { result }, + (false, _, _) => result, + }; + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(java_result)))?; } Instruction::NewArray(component_class_index) => { @@ -1799,6 +1859,12 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 - value_2)))?; } + Instruction::StoreLocalFloat(index) => { + let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; + + wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Float(float)))?; + } + Instruction::StoreLocalInt(index) => { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; @@ -2038,7 +2104,7 @@ fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut Ve }, AbstractTypeKind::Boolean() => { arguments.push_front( - StackValue::Boolean( + StackValue::Int( wrap_stackframe_error( class, method, diff --git a/src/native_methods.rs b/src/native_methods.rs index ee76b03..9a10e58 100644 --- a/src/native_methods.rs +++ b/src/native_methods.rs @@ -361,6 +361,34 @@ impl JdkInternalUtilSystemPropsRaw { }; 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); + let utf8_string_ref = jvm.heap_area.make_handmade_string(&String::from("UTF-8"), &jvm.class_store); + + { + let stdout_encoding_ndx_result = jvm.heap_area.static_area.get( + &String::from("jdk/internal/util/SystemProps$Raw"), + &String::from("_stdout_encoding_NDX"), + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() } + ); + let stdout_encoding_ndx = match stdout_encoding_ndx_result { + Ok(FieldValue::Int(i)) => i as usize, + _ => unreachable!(), + }; + jvm.heap_area.object_area.set_array_element(array_reference, stdout_encoding_ndx, FieldValue::Reference(utf8_string_ref)); + + } + { + let stderr_encoding_ndx_result = jvm.heap_area.static_area.get( + &String::from("jdk/internal/util/SystemProps$Raw"), + &String::from("_stderr_encoding_NDX"), + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() } + ); + let stderr_encoding_ndx = match stderr_encoding_ndx_result { + Ok(FieldValue::Int(i)) => i as usize, + _ => unreachable!(), + }; + jvm.heap_area.object_area.set_array_element(array_reference, stderr_encoding_ndx, FieldValue::Reference(utf8_string_ref)); + + } Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference))) } diff --git a/src/stackframe.rs b/src/stackframe.rs index 5ca99a7..5f0034f 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -68,6 +68,10 @@ impl OperandStack { self.push(StackValue::Int(i)) } + FieldValue::Float(i) => { + self.push(StackValue::Float(i)) + } + _ => { println!("{value:?}"); todo!(); @@ -114,12 +118,12 @@ impl OperandStack { } } - pub fn pop_boolean(&mut self, index: usize) -> Result { + pub fn pop_boolean(&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::Boolean(b) => Ok(b), + StackValue::Int(b) => Ok(b & 0x1), _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Boolean but found '{:?}'", index, value))) } }