From 43ceaa95bb568715dd0eb469efa4b5dde1e403d2 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Tue, 29 Oct 2024 13:24:26 +0100 Subject: [PATCH] Implemented VM.initalize and LoadConstant64 --- src/jvm.rs | 39 ++++++++++- src/native_methods.rs | 147 ++++++++++++++++++++++++++++++++++++++++-- src/stackframe.rs | 31 +++++++-- 3 files changed, 204 insertions(+), 13 deletions(-) diff --git a/src/jvm.rs b/src/jvm.rs index bcb39dc..eebc89b 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -1045,11 +1045,26 @@ impl JVM { } Instruction::InstanceOf(classref_index) => { - // 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 object = wrap_stackframe_error(class, method, frame.operand_stack.peek_reference(0))?; let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store); + if class_name.starts_with("[") { + // TODO: Create array class on demand + } else { + if ! self.class_store.have_class(class_name) { + frame.instruction_pointer -= offset as u32; + return Ok(JVMCallbackOperation::LoadClass(class_name.to_string())); + } + if ! self.class_store.was_init(class_name).unwrap() { + frame.instruction_pointer -= offset as u32; + return Ok(JVMCallbackOperation::InitClass(class_name.to_string())); + } + } + + frame.operand_stack.pop_reference(0).unwrap(); + + let instruction_result = if class_name == native_class_name { 1 } else { @@ -1449,6 +1464,20 @@ impl JVM { } } + Instruction::LoadConstant64(wide_index) => { + match class.pool_entry(wide_index).unwrap() { + ConstantPoolInfo::Long(long_data) => { + let long_value = long_data.value; + + wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?; + } + _ => { + println!("{:?}", class.pool_entry(wide_index).unwrap()); + todo!() + } + } + } + Instruction::LoadLocalFloat(index) => { load_local_float(class, method, frame, index as usize)?; } @@ -1749,6 +1778,12 @@ impl JVM { FieldValue::Int(int_value) } + (0, AbstractTypeKind::Long()) => { + let long_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + + FieldValue::Long(long_value) + } + (0..=255, AbstractTypeKind::Classname(_field_type_name)) => { let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; diff --git a/src/native_methods.rs b/src/native_methods.rs index 9a10e58..d3df129 100644 --- a/src/native_methods.rs +++ b/src/native_methods.rs @@ -395,22 +395,42 @@ impl JdkInternalUtilSystemPropsRaw { // command-line configured properties, should return at least java.home pub fn vm_properties(jvm: &mut JVM) -> Result { - let array_length = 4; + let native_array = vec![ + ("java.home", "./"), + ("stdout.encoding", "UTF-8"), + ("java.io.tmpdir", "/tmp"), + ("user.language", "en"), + ("user.script", ""), + ("user.country", "US"), + ("user.variant", ""), + ]; + // TODO: Cross-Platform tmpdir + // TODO: locale detection + let array_length = native_array.len() * 2 + 2; 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); + for (index, (key, value)) in native_array.iter().enumerate() { + let key_string: String = key.to_string(); + let value_string: String = value.to_string(); + let key_reference = jvm.heap_area.make_handmade_string(&key_string, &jvm.class_store); + let value_reference = jvm.heap_area.make_handmade_string(&value_string, &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()); + jvm.heap_area.object_area.set_array_element(array_reference, index * 2 , key_reference.into()); + jvm.heap_area.object_area.set_array_element(array_reference, index * 2 + 1, value_reference.into()); } Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference))) } } +pub struct JdkInternalMiscVM {} + +impl JdkInternalMiscVM { + pub fn initialize(jvm: &mut JVM) -> Result { + Ok(JVMCallbackOperation::PopFrame()) + } +} + pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Result { let method_name: &str = &m.name; @@ -2548,6 +2568,119 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul Ok(todo_call) } + ("jdk/internal/misc/VM", "getgid") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + 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(todo_call) + } + + ("jdk/internal/misc/VM", "getegid") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + 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(todo_call) + } + + ("jdk/internal/misc/VM", "geteuid") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + 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(todo_call) + } + + ("jdk/internal/misc/VM", "getuid") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + 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(todo_call) + } + + ("jdk/internal/misc/VM", "getNanoTimeAdjustment") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long()}, + ]), + 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(todo_call) + } + + ("jdk/internal/misc/VM", "getRuntimeArguments") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + }; + + 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(todo_call) + } + + ("jdk/internal/misc/VM", "initialize") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()}, + }; + + 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(JdkInternalMiscVM::initialize) + } + + ("jdk/internal/misc/VM", "latestUserDefinedLoader0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/ClassLoader".to_string())}, + }; + + 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(todo_call) + } + ("jdk/internal/util/SystemProps$Raw", "platformProperties") => { let expected_descriptor = MethodDescriptor { argument_types: Box::new([ diff --git a/src/stackframe.rs b/src/stackframe.rs index 5f0034f..2795a9a 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -50,6 +50,17 @@ impl OperandStack { Ok(()) } + pub fn push_long(&mut self, long: i64) -> Result<(), Error> { + let long_bytes: [u8; 8] = long.to_be_bytes(); + + 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_field_value(&mut self, value: FieldValue) -> Result<(), Error> { match value { FieldValue::Reference(r) => { @@ -187,6 +198,15 @@ impl OperandStack { } } + pub fn peek_reference(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value = self.stack[absolute_index]; + match value { + StackValue::Reference(o) => Ok(o), + _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Reference but found '{:?}'", index, value))) + } + } + pub fn pop_returnaddress(&mut self, index: usize) -> Result { let absolute_index = self.depth as usize - 1 - index; let value = self.stack[absolute_index]; @@ -253,14 +273,17 @@ impl OperandStack { } } - pub fn pop_long(&mut self, index: usize) -> Result { + pub fn pop_long(&mut self, index: usize) -> Result { let absolute_index = self.depth as usize - 1 - index; - let higher_bytes = self.stack[absolute_index]; - let lower_bytes = self.stack[absolute_index + 1]; + let lower_bytes = self.stack[absolute_index]; + let higher_bytes = self.stack[absolute_index - 1]; self.depth -= 2; match (higher_bytes, lower_bytes) { (StackValue::Long0(hi), StackValue::Long1(lo)) => { - Ok(((hi as u64) << 32) | lo as u64) + 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) }, _ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Long0, Long1) but found '{:?}'", index, (higher_bytes, lower_bytes)))) }