diff --git a/src/bytecode.rs b/src/bytecode.rs index c188b84..7e41d6a 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -102,6 +102,7 @@ impl Bytecode { 0x6D => (Instruction::DivideLong(), 1), 0x6E => (Instruction::DivideFloat(), 1), + 0x70 => (Instruction::ModuloInt(), 1), 0x74 => (Instruction::NegateInt(), 1), 0x75 => (Instruction::NegateLong(), 1), 0x78 => (Instruction::ArithmeticShiftIntLeft(), 1), @@ -386,6 +387,7 @@ pub enum Instruction { DivideLong() = 0x6D, // long division DivideFloat() = 0x6E, // float division + ModuloInt() = 0x70, // modulo NegateInt() = 0x74, // arithmetic negation NegateLong() = 0x75, // arithmetic negation ArithmeticShiftIntLeft() = 0x78, // shift int left, preserve sign diff --git a/src/classfile.rs b/src/classfile.rs index f6399f3..4ce88d9 100644 --- a/src/classfile.rs +++ b/src/classfile.rs @@ -375,6 +375,15 @@ impl JavaClassFile { return Ok((class_name, method_name, method_descriptor)); } + + pub fn gather_methodref_compatible(&self, methodref_index: u16) -> Result<(&String, &String, &String), Error> { + return match self.pool_entry(methodref_index) { + Ok(ConstantPoolInfo::MethodRef(_)) => self.gather_methodref(methodref_index), + Ok(ConstantPoolInfo::InterfaceMethodRef(_)) => self.gather_interfacemethodref(methodref_index), + Err(i) => Err(i), + _ => unreachable!() + } + } pub fn sourcefile(&self) -> Result, Error> { match (&self.attributes).into_iter() diff --git a/src/jvm.rs b/src/jvm.rs index 32ab7aa..558a734 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -1403,7 +1403,7 @@ impl JVM { }, Instruction::InvokeStatic(methodref_index) => { - let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?; + let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref_compatible(methodref_index)?; if ! self.class_store.have_class(supplied_class_name) { // rewind the bytecode offset, I'll need to execute this instruction again @@ -1842,6 +1842,15 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push_long(result))?; } + Instruction::ModuloInt() => { + let int_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let int_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + let modulo = int_2.wrapping_rem(int_1); + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(modulo)))?; + } + Instruction::NegateInt() => { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let negated = -int; @@ -2020,6 +2029,7 @@ impl JVM { match expected_field_descriptor.as_str() { "Z" => FieldValue::Boolean(i != 0), "B" => FieldValue::Byte(i as i8), + "C" => FieldValue::Char(i as u16), _ => FieldValue::Int(i) } } @@ -2126,7 +2136,7 @@ impl JVM { _ => return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type))) } - let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?; return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(int))); } @@ -2429,8 +2439,8 @@ fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut Ve wrap_stackframe_error( class, method, - stack.pop_char(0) - )? as i32 + stack.pop_int_compatible(0) + )? ) ) }, diff --git a/src/native_methods.rs b/src/native_methods.rs index 350fb9d..f49ffd8 100644 --- a/src/native_methods.rs +++ b/src/native_methods.rs @@ -461,6 +461,14 @@ impl JavaLangThrowable { } } +struct JdkInternalMiscCDS {} + +impl JdkInternalMiscCDS { + fn get_cds_config_status(_jvm: &mut JVM) -> Result { + return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(0))); + } +} + struct JdkInternalMiscUnsafe {} impl JdkInternalMiscUnsafe { @@ -2949,6 +2957,185 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul }, JavaLangThrowable::fill_in_stacktrace ), + + ( + "java/lang/invoke/MethodHandle", + "invokeExact", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + }, + todo_call + ), + + ( + "java/lang/invoke/MethodHandle", + "invoke", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + }, + todo_call + ), + + ( + "java/lang/invoke/MethodHandle", + "invokeBasic", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + }, + todo_call + ), + + ( + "java/lang/invoke/MethodHandle", + "linkToVirtual", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + }, + todo_call + ), + + ( + "java/lang/invoke/MethodHandle", + "linkToStatic", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + }, + todo_call + ), + + ( + "java/lang/invoke/MethodHandle", + "linkToSpecial", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + }, + todo_call + ), + + ( + "java/lang/invoke/MethodHandle", + "linkToInterface", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + }, + todo_call + ), + + ( + "java/lang/invoke/MethodHandle", + "linkToNative", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + }, + todo_call + ), + + ( + "jdk/internal/misc/CDS", + "getCDSConfigStatus", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + }, + JdkInternalMiscCDS::get_cds_config_status + ), + + ( + "jdk/internal/misc/CDS", + "logLambdaFormInvoker", + 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::Void() }, + }, + todo_call + ), + + ( + "jdk/internal/misc/CDS", + "initializeFromArchive", + 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::Void() }, + }, + ignore_call // TODO: idk + ), + + ( + "jdk/internal/misc/CDS", + "defineArchivedModules", + 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/ClassLoader".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + todo_call + ), + + ( + "jdk/internal/misc/CDS", + "getRandomSeedForDumping", + MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long() }, + }, + todo_call + ), + + ( + "jdk/internal/misc/CDS", + "dumpClassList", + 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::Void() }, + }, + todo_call + ), + + ( + "jdk/internal/misc/CDS", + "dumpDynamicArchive", + 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::Void() }, + }, + todo_call + ), ]; for (classname, methodname, methoddescriptor, binding) in native_mappings { diff --git a/src/stackframe.rs b/src/stackframe.rs index 56b84cc..a18f82b 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -8,7 +8,7 @@ pub enum StackValue { Boolean(bool), Byte(i8), Char(u16), - Short(u16), + Short(i16), Int(i32), Float(f32), Reference(ObjectReference), @@ -102,9 +102,15 @@ impl OperandStack { self.push_long(l) } - _ => { - println!("{value:?}"); - todo!(); + FieldValue::Char(c) => { + self.push(StackValue::Char(c)) + } + + FieldValue::Short(s) => { + self.push(StackValue::Short(s)) + } + FieldValue::Double(d) => { + self.push_double(d) } } } @@ -191,7 +197,7 @@ impl OperandStack { } } - pub fn pop_short(&mut self, index: usize) -> Result { + pub fn pop_short(&mut self, index: usize) -> Result { let absolute_index = self.depth as usize - 1 - index; let value = self.stack[absolute_index]; self.depth -= 1; @@ -218,6 +224,7 @@ impl OperandStack { match value { StackValue::Int(i) => Ok(i), StackValue::Byte(b) => Ok(b as i32), + StackValue::Char(c) => Ok(c as i32), _ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Int-compatible but found '{:?}'", index, value))) } }