From 796e52241db5163e762fbefcec501193738f5ecd Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Tue, 12 Nov 2024 16:31:41 +0100 Subject: [PATCH] AndLong, IntModulo, ASHRLong and native methods --- src/bytecode.rs | 4 + src/jvm.rs | 34 ++++- src/native_methods.rs | 305 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 336 insertions(+), 7 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 7e41d6a..9b69209 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -108,8 +108,10 @@ impl Bytecode { 0x78 => (Instruction::ArithmeticShiftIntLeft(), 1), 0x79 => (Instruction::ArithmeticShiftLongLeft(), 1), 0x7A => (Instruction::ArithmeticShiftIntRight(), 1), + 0x7B => (Instruction::ArithmeticShiftLongRight(), 1), 0x7C => (Instruction::LogicalShiftIntRight(), 1), 0x7E => (Instruction::AndInt(), 1), + 0x7F => (Instruction::AndLong(), 1), 0x80 => (Instruction::OrInt(), 1), 0x82 => (Instruction::XorInt(), 1), @@ -393,8 +395,10 @@ pub enum Instruction { ArithmeticShiftIntLeft() = 0x78, // shift int left, preserve sign ArithmeticShiftLongLeft() = 0x79, // shift long left, preserve sign ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign + ArithmeticShiftLongRight() = 0x7B, // shift long right, preserve sign LogicalShiftIntRight() = 0x7C, // shift int right with zero extension AndInt() = 0x7E, // bitwise and + AndLong() = 0x7F, // bitwise and OrInt() = 0x80, // value, value => or XorInt() = 0x82, // value, value => xor diff --git a/src/jvm.rs b/src/jvm.rs index 558a734..62b61ed 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -786,6 +786,14 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push_long(long << shift))?; } + Instruction::ArithmeticShiftLongRight() => { + let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 % 64; + let long = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + + // rust does arithmetic shift on signed values + wrap_stackframe_error(class, method, frame.operand_stack.push_long(long >> shift))?; + } + Instruction::ArrayLength() => { let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; @@ -810,6 +818,13 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 & value_2)))?; } + Instruction::AndLong() => { + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let value_2 = 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::BranchAlways(branch_offset) => { 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}; @@ -1837,9 +1852,20 @@ impl JVM { 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; + let (result, overflowed) = i64::overflowing_mul(factor_1, factor_2); + let java_result = if overflowed { + if result < 0 && ((factor_1 >= 0 && factor_2 <= 0 ) || (factor_1 < 0 && factor_2 >= 0)) { + result.abs() + } else if factor_1 < 0 && factor_2 < 0 { + if result < 0 { result } else { -result } + } else { + -result.abs() + } + } else { + result + }; - wrap_stackframe_error(class, method, frame.operand_stack.push_long(result))?; + wrap_stackframe_error(class, method, frame.operand_stack.push_long(java_result))?; } Instruction::ModuloInt() => { @@ -2282,8 +2308,8 @@ impl JVM { 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()))?; + wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Long0(long0)))?; + wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Long1()))?; } Instruction::StoreLocalLong1() => { let _ = wrap_stackframe_error(class, method, frame.operand_stack.pop_long1(0))?; diff --git a/src/native_methods.rs b/src/native_methods.rs index f49ffd8..8b6e265 100644 --- a/src/native_methods.rs +++ b/src/native_methods.rs @@ -461,9 +461,22 @@ impl JavaLangThrowable { } } +struct JavaSecurityAccessController {} + +impl JavaSecurityAccessController { + fn get_stack_access_control_context(_jvm: &mut JVM) -> Result { + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(ObjectReference::NULL))) + } +} + struct JdkInternalMiscCDS {} impl JdkInternalMiscCDS { + fn get_random_seed_for_dumping(_jvm: &mut JVM) -> Result { + return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Long(42))); // TODO: Random seed + // depending on JVM + // version + } fn get_cds_config_status(_jvm: &mut JVM) -> Result { return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(0))); } @@ -708,12 +721,24 @@ impl JdkInternalMiscUnsafe { Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(index_scale))) } - pub fn array_base_offset_0(jvm: &mut JVM) -> Result { + pub fn array_base_offset_0(_jvm: &mut JVM) -> Result { // TODO: Check passed class Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(0))) } } +struct JdkInternalReflectReflection {} + +impl JdkInternalReflectReflection { + pub fn get_caller_class(jvm: &mut JVM) -> Result { + let caller_frame = &jvm.stack_frames[jvm.stack_frames.len() - 2]; + let caller_class_index = caller_frame.class_index; + let caller_class_reference = jvm.class_store.get_class_objectref_from_index(caller_class_index); + + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(caller_class_reference))) + } +} + pub struct JdkInternalUtilSystemPropsRaw {} impl JdkInternalUtilSystemPropsRaw { @@ -3110,7 +3135,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul ]), return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long() }, }, - todo_call + JdkInternalMiscCDS::get_random_seed_for_dumping ), ( @@ -3136,6 +3161,280 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul }, todo_call ), + + ( + "jdk/internal/reflect/Reflection", + "getCallerClass", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) }, + }, + JdkInternalReflectReflection::get_caller_class + ), + + ( + "jdk/internal/reflect/Reflection", + "getClassAccessFlags", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + }, + todo_call + ), + + ( + "jdk/internal/reflect/Reflection", + "areNestMates", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() }, + }, + todo_call + ), + + ( + "java/security/AccessController", + "getProtectionDomain", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/security/ProtectionDomain".to_string()) }, + }, + todo_call + ), + + ( + "java/security/AccessController", + "ensureMaterializedForStackWalk", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + ignore_call + ), + + ( + "java/security/AccessController", + "getStackAccessControlContext", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/security/AccessControlContext".to_string()) }, + }, + JavaSecurityAccessController::get_stack_access_control_context + ), + + ( + "java/security/AccessController", + "getInheritedAccessControlContext", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/security/AccessControlContext".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/ref/Reference", + "getAndClearReferencePendingList", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/ref/Reference".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/ref/Reference", + "hasReferencePendingList", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() }, + }, + todo_call + ), + + ( + "java/lang/ref/Reference", + "waitForReferencePendingList", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + todo_call + ), + + ( + "java/lang/ref/Reference", + "refersTo0", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() }, + }, + todo_call + ), + + ( + "java/lang/ref/Reference", + "clear0", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + todo_call + ), + + ( + "java/lang/ClassLoader", + "registerNatives", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + ignore_call + ), + + ( + "java/lang/ClassLoader", + "defineClass0", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/ClassLoader".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/security/ProtectionDomain".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/ClassLoader", + "defineClass1", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/ClassLoader".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/security/ProtectionDomain".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/ClassLoader", + "defineClass2", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/ClassLoader".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/nio/ByteBuffer".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/security/ProtectionDomain".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/ClassLoader", + "findBootstrapClass", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/ClassLoader", + "findLoadedClass0", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/ClassLoader", + "retrieveDirectives", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/AssertionStatusDirectives".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/reflect/Executable", + "getParameters0", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/Parameter".to_string()) }, + }, + todo_call + ), + + ( + "java/lang/reflect/Executable", + "getTypeAnnotationBytes0", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() }, + }, + todo_call + ), + + ( + "java/lang/reflect/Field", + "getTypeAnnotationBytes0", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() }, + }, + todo_call + ), ]; for (classname, methodname, methoddescriptor, binding) in native_mappings { @@ -3143,7 +3442,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul continue; } if methoddescriptor != m.descriptor { - return Err(Error::RunTimeError(format!("Descriptor mismatch in native method resolution: internal is {} but classfile wants {}", methoddescriptor.source_string(), m.descriptor.source_string()))); + return Err(Error::RunTimeError(format!("Descriptor mismatch in native method resolution for {class_name}.{method_name}: internal is {} but classfile wants {}", methoddescriptor.source_string(), m.descriptor.source_string()))); } return Ok(binding);