diff --git a/src/bytecode.rs b/src/bytecode.rs index 1df94cd..5ba9c72 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -58,6 +58,7 @@ impl Bytecode { 0x57 => (Instruction::Pop(), 1), 0x59 => (Instruction::Duplicate(), 1), + 0x60 => (Instruction::AddInt(), 1), 0x68 => (Instruction::MultiplyInt(), 1), 0x6C => (Instruction::DivideInt(), 1), 0x6D => (Instruction::DivideLong(), 1), @@ -80,7 +81,7 @@ impl Bytecode { } 0x9C => { let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; - (Instruction::BranchNonPositive(i16::from_be_bytes(bytes)), 3) + (Instruction::BranchNonNegative(i16::from_be_bytes(bytes)), 3) } 0x9D => { let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; @@ -88,7 +89,7 @@ impl Bytecode { } 0x9E => { let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; - (Instruction::BranchNonNegative(i16::from_be_bytes(bytes)), 3) + (Instruction::BranchNonPositive(i16::from_be_bytes(bytes)), 3) } 0x9F => { @@ -194,7 +195,7 @@ pub enum Instruction { LoadByteImmediate(u8) = 0x10, // push immediate short LoadShortImmediate(u16) = 0x11, // push immediate short LoadConstant(u8) = 0x12, // Push from constant pool - LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load + 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 LoadLocalInt0() = 0x1A, // Load int from local variable @@ -227,6 +228,7 @@ pub enum Instruction { Pop() = 0x57, // Pop top stack value Duplicate() = 0x59, // duplicate top stack value + AddInt() = 0x60, // int addition MultiplyInt() = 0x68, // int multiplication DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideLong() = 0x6D, // long division @@ -238,9 +240,9 @@ pub enum Instruction { BranchZero(i16) = 0x99, // branch if value == 0 BranchNonZero(i16) = 0x9A, // branch if value != 0 BranchNegative(i16) = 0x9B, // branch if value < 0 - BranchNonPositive(i16) = 0x9C, // branch if value <= 0 + BranchNonNegative(i16) = 0x9C, // branch if value <= 0 BranchPositive(i16) = 0x9D, // branch if value > 0 - BranchNonNegative(i16) = 0x9E, // branch if value >= 0 + BranchNonPositive(i16) = 0x9E, // branch if value >= 0 BranchIntEquality(i16) = 0x9F, BranchIntInequality(i16) = 0xA0, diff --git a/src/classfile.rs b/src/classfile.rs index 5d5e3f7..296f9b0 100644 --- a/src/classfile.rs +++ b/src/classfile.rs @@ -5,7 +5,7 @@ use core::str::Utf8Error; use crate::accessmasks::*; use crate::bytecode::Bytecode; -use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantStringInfo, ConstantMethodRefInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo }; +use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo }; #[derive(Debug)] pub enum Error { @@ -246,6 +246,15 @@ impl JavaClassFile { }; } + pub fn pool_float_entry(&self, index: u16) -> Result<&ConstantFloatInfo, Error> { + let pool_entry = self.pool_entry(index)?; + + return match pool_entry { + ConstantPoolInfo::Float(data) => Ok(data), + _ => Err(Error::BadFileError(format!("Expected constant pool entry {} in class {} to be of type Float 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)?; @@ -282,6 +291,12 @@ impl JavaClassFile { }; } + pub fn gather_float(&self, index: u16) -> Result { + let float = self.pool_float_entry(index)?; + + return Ok(float.value); + } + pub fn gather_string(&self, index: u16) -> Result<&String, Error> { let string = self.pool_string_entry(index)?; @@ -766,17 +781,17 @@ impl Into for &AbstractTypeKind { impl From<&str> for AbstractTypeKind { fn from(value: &str) -> Self { match value.chars().nth(0).unwrap() { - 'V' => AbstractTypeKind::Void(), - 'B' => AbstractTypeKind::Byte(), - 'C' => AbstractTypeKind::Char(), - 'D' => AbstractTypeKind::Double(), - 'F' => AbstractTypeKind::Float(), - 'I' => AbstractTypeKind::Int(), - 'J' => AbstractTypeKind::Long(), - 'S' => AbstractTypeKind::Short(), - 'Z' => AbstractTypeKind::Boolean(), - 'L' => todo!(), - _ => todo!(), + 'V' => AbstractTypeKind::Void(), + 'B' => AbstractTypeKind::Byte(), + 'C' => AbstractTypeKind::Char(), + 'D' => AbstractTypeKind::Double(), + 'F' => AbstractTypeKind::Float(), + 'I' => AbstractTypeKind::Int(), + 'J' => AbstractTypeKind::Long(), + 'S' => AbstractTypeKind::Short(), + 'Z' => AbstractTypeKind::Boolean(), + 'L' => AbstractTypeKind::Classname(value.chars().skip(1).map_while(|c| if c != ';' { Some(c) } else { None } ).collect()), + _ => unreachable!(), } } } diff --git a/src/classstore.rs b/src/classstore.rs index a9ad0c4..083d788 100644 --- a/src/classstore.rs +++ b/src/classstore.rs @@ -12,24 +12,24 @@ use crate::iterators::CompatibleTypesIterator; #[derive(Debug)] pub struct ClassStore { - class_ids: HashMap, - array_classes: HashMap, - classes: Vec, - class_path_fragments: Vec, - native_class_names: Vec, - primitive_classes: PrimitiveClassStore, + pub class_ids: HashMap, + pub array_classes: HashMap, + pub classes: Vec, + pub class_path_fragments: Vec, + pub native_class_names: Vec, + pub primitive_classes: PrimitiveClassStore, } #[derive(Debug, Default)] pub struct PrimitiveClassStore { - byte_class: ObjectReference, - char_class: ObjectReference, - double_class: ObjectReference, - float_class: ObjectReference, - integer_class: ObjectReference, - long_class: ObjectReference, - short_class: ObjectReference, - boolean_class: ObjectReference, + pub byte_class: ObjectReference, + pub char_class: ObjectReference, + pub double_class: ObjectReference, + pub float_class: ObjectReference, + pub int_class: ObjectReference, + pub long_class: ObjectReference, + pub short_class: ObjectReference, + pub boolean_class: ObjectReference, } #[derive(Debug)] @@ -228,6 +228,27 @@ impl ClassStore { AbstractTypeKind::Boolean() => { Some(self.primitive_classes.boolean_class) } + AbstractTypeKind::Byte() => { + Some(self.primitive_classes.byte_class) + } + AbstractTypeKind::Char() => { + Some(self.primitive_classes.char_class) + } + AbstractTypeKind::Double() => { + Some(self.primitive_classes.double_class) + } + AbstractTypeKind::Float() => { + Some(self.primitive_classes.float_class) + } + AbstractTypeKind::Int() => { + Some(self.primitive_classes.int_class) + } + AbstractTypeKind::Long() => { + Some(self.primitive_classes.long_class) + } + AbstractTypeKind::Short() => { + Some(self.primitive_classes.short_class) + } _ => todo!(), } } diff --git a/src/iterators.rs b/src/iterators.rs index 8f958db..0a44ba8 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -104,7 +104,7 @@ impl <'i>ClassMethodIterator<'i> { } } -impl <'i> Iterator for ClassMethodIterator<'i>{ +impl <'i> Iterator for ClassMethodIterator<'i> { type Item = (usize, usize, &'i MethodInfo); // class index, method index, method info fn next(&mut self) -> Option { diff --git a/src/jvm.rs b/src/jvm.rs index 4804e9b..a189ab8 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -13,8 +13,8 @@ use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry }; use crate::iterators::{ ClassMethodIterator, ClassFieldIterator }; use crate::native_methods; -use crate::native_methods::ignore_call; -use crate::native_registry::{ NativeRegistry }; +use crate::native_methods::{ EntryPoint, ignore_call }; +use crate::native_registry::NativeRegistry; use crate::stackframe; use crate::stackframe::{ StackFrame, StackValue, OperandStack }; @@ -233,10 +233,6 @@ impl JVM { primitive_class_object } - fn register_native(&mut self, class_name: &str, method_name: &str, method_descriptor: &MethodDescriptor) { - self.native_registry.register("java/lang/System", "registerNatives", ignore_call); - } - pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[&str]) -> Result<(), Error> { let entry_class = JavaClassFile { minor_version: 0, @@ -251,12 +247,17 @@ impl JVM { ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: class_name.to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: method_name.to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "([Ljava/lang/String;)V".to_string() }), - ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 11, name_and_type_index: 13}), // 10 - ConstantPoolInfo::Class(ConstantClassInfo { name_index: 12 } ), - ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/String".to_string() }), - ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 14, descriptor_index: 15 }), - ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "".to_string() }), - ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "([B)V".to_string() }), // 15 + ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 1, name_and_type_index: 11}), // 10 + ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 12, descriptor_index: 13 }), + ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "populateUnsafeConstants".to_string() }), + ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "()V".to_string() }), + ConstantPoolInfo::Class(ConstantClassInfo { name_index: 15 }), + ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "jdk/internal/misc/UnsafeConstants".to_string() }), // 15 + ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 17, name_and_type_index: 19}), + ConstantPoolInfo::Class(ConstantClassInfo { name_index: 18 }), + ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/System".to_string() }), + ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 20, descriptor_index: 13 }), + ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "initPhase1".to_string() }), ] ), access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() }, @@ -267,7 +268,7 @@ impl JVM { methods: Box::new([ MethodInfo { access_flags: MethodAccessFlagMask { - mask: MethodAccessFlag::Public.discriminant() | MethodAccessFlag::Static.discriminant() + mask: MethodAccessFlag::Private.discriminant() | MethodAccessFlag::Static.discriminant() }, name: "call_main".to_string(), descriptor: MethodDescriptor { @@ -287,8 +288,22 @@ impl JVM { max_locals: 1, code: Bytecode { bytes: Box::new([ - 0x2A_u8.to_be(), // aload_0 + // access something from UnsafeConstants + 0x12_u8.to_be(), // ldc + 0x0E_u8.to_be(), // index 14 into the constant pool + 0x57_u8.to_be(), // pop + // Update UnsafeConstants to actual values + 0xb8_u8.to_be(), // invokestatic + 0x0A_u16.to_be_bytes()[0], // index 10 into the constant + 0x0A_u16.to_be_bytes()[1], // pool + + // call initPhase1 + 0xb8_u8.to_be(), // invokestatic + 0x10_u16.to_be_bytes()[0], // index 10 into the constant + 0x10_u16.to_be_bytes()[1], // pool + + 0x2A_u8.to_be(), // aload_0 0xB8_u8.to_be(), // invokestatic 0x04_u16.to_be_bytes()[0], // index 4 into the constant 0x04_u16.to_be_bytes()[1], // pool @@ -301,29 +316,47 @@ impl JVM { } ]) }, + MethodInfo { + access_flags: MethodAccessFlagMask { + mask: MethodAccessFlag::Private.discriminant() | MethodAccessFlag::Static.discriminant() | MethodAccessFlag::Native.discriminant() + }, + name: "populateUnsafeConstants".to_string(), + descriptor: MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { + array_level: 0, + kind: AbstractTypeKind::Void(), + } + }, + code_attribute_index: 0, + attributes: Box::new([]) + } ]), attributes: Box::new([]), }; - self.class_store.add_class(entry_class, true)?; // 0 - self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1 - self.load_class(&"java/lang/Object".to_string())?; // 2 - self.load_class(&"java/lang/Number".to_string())?; // 3 - self.load_class(&"java/lang/Byte".to_string())?; // 4 - self.load_class(&"java/lang/String".to_string())?; // 5 - self.load_class(&"java/lang/Class".to_string())?; // 6 + self.native_registry.register("::EntryPoint", "populateUnsafeConstants", EntryPoint::populate_unsafe_constants); + + self.class_store.add_class(entry_class, true)?; // 0 + self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1 + self.load_class(&"java/lang/Object".to_string())?; // 2 + self.load_class(&"java/lang/Number".to_string())?; // 3 + let byte_class_index = self.load_class(&"java/lang/Byte".to_string())?; // 4 + let string_class_index = self.load_class(&"java/lang/String".to_string())?; // 5 + let class_class_index = self.load_class(&"java/lang/Class".to_string())?; // 6 + let system_class_index = self.load_class(&"java/lang/System".to_string())?; // 7 self.make_class_class("Ljava/lang/Byte;"); self.make_class_class("Ljava/lang/String;"); self.make_array_class( - self.class_store.get_class_objectref_from_index(4), + self.class_store.get_class_objectref_from_index(byte_class_index), AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Byte".into()), } ); self.make_array_class( - self.class_store.get_class_objectref_from_index(5), + self.class_store.get_class_objectref_from_index(string_class_index), AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()), @@ -332,18 +365,24 @@ impl JVM { self.heap_area.fill_byte_cache(&self.class_store); - let int_class_ref = self.make_primitive_class("int", "I"); - let byte_class_ref = self.make_primitive_class("byte", "B"); + self.class_store.primitive_classes.int_class = self.make_primitive_class("int", "I"); + self.class_store.primitive_classes.byte_class = self.make_primitive_class("byte", "B"); + self.class_store.primitive_classes.char_class = self.make_primitive_class("char", "C"); + self.class_store.primitive_classes.long_class = self.make_primitive_class("long", "J"); + self.class_store.primitive_classes.float_class = self.make_primitive_class("float", "F"); + self.class_store.primitive_classes.short_class = self.make_primitive_class("short", "S"); + self.class_store.primitive_classes.double_class = self.make_primitive_class("double", "D"); + self.class_store.primitive_classes.boolean_class = self.make_primitive_class("boolean", "Z"); self.make_array_class( - int_class_ref, + self.class_store.primitive_classes.int_class, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int(), } ); self.make_array_class( - byte_class_ref, + self.class_store.primitive_classes.byte_class, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Byte(), @@ -366,7 +405,6 @@ impl JVM { pub fn run(&mut self) -> Result<(), Error> { while self.stack_frames.len() != 0 { - println!("Enter bytecode loop:"); let jvm_op = self.bytecode_loop()?; match jvm_op { @@ -517,6 +555,11 @@ impl JVM { FieldValue::Long(long_entry.value) }, + AbstractTypeKind::Float() => { + let float_entry = class_file.pool_float_entry(constant_value_info.constant_value_index)?; + + FieldValue::Float(float_entry.value) + }, AbstractTypeKind::Classname(ref name) => { if name == "java/lang/String" { let string_entry = class_file.gather_string(constant_value_info.constant_value_index)?; @@ -585,15 +628,15 @@ impl JVM { } fn bytecode_loop(&mut self) -> Result { + //println!("Enter bytecode loop:"); - let frame = { - let frame_index = self.stack_frames.len() - 1; - &mut self.stack_frames[frame_index] - }; + let frame_index = self.stack_frames.len() - 1; + let frame = &mut self.stack_frames[frame_index]; let class = self.class_store.class_file_from_idx(frame.class_index).unwrap(); let method = & class.methods[frame.method_index as usize]; if method.access_flags & MethodAccessFlag::Native { + println!("{:25}.{:15}: (native)", class.get_classname().unwrap(), method.name); return self.native_call() } @@ -604,10 +647,17 @@ impl JVM { let (instruction, offset) = bytecode.next_instruction(frame.instruction_pointer as usize); frame.instruction_pointer += offset as u32; - println!("{:25}.{:15}:{:<10}{instruction:?}", class.get_classname().unwrap(), method.name, frame.instruction_pointer); + println!("{}{:25}.{:15}:{:<10}{instruction:?}", " ".repeat(frame_index), class.get_classname().unwrap(), method.name, frame.instruction_pointer); match instruction { + Instruction::AddInt() => { + let value_0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_0 + value_1)))?; + } + Instruction::ArrayLength() => { let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; @@ -659,6 +709,24 @@ impl JVM { } } + Instruction::BranchNonNegative(branch_offset) => { + let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + if test_value >= 0 { + 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::BranchNonZero(branch_offset) => { + let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + if test_value != 0 { + 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::BranchNull(branch_offset) => { let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; @@ -840,9 +908,6 @@ impl JVM { ))); } - if callee_method_info.access_flags & MethodAccessFlag::Native { - } - let supplied_descriptor: MethodDescriptor = supplied_descriptor_string.try_into()?; // TODO: Throw exception on fail @@ -982,6 +1047,12 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?; }, + ConstantPoolInfo::Float(_) => { + // TODO: Handle error instead of unwrap + let float_constant = class.gather_float(index as u16).unwrap(); + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(float_constant)))?; + }, _ => { println!("{:?}", class.pool_entry(index as u16).unwrap()); todo!() @@ -1000,11 +1071,7 @@ impl JVM { let array_level = class_name.len() - component_name.len(); let array_type_desc = AbstractTypeDescription { array_level: array_level as u8, - kind: if component_name.len() == 1 { - component_name.into() - } else { - AbstractTypeKind::Classname(component_name.to_string()) - } + kind: component_name.into(), }; if let Some(array_ref) = self.class_store.get_array_class_ref(&array_type_desc) { @@ -1166,6 +1233,10 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(new_object)))?; }, + Instruction::Pop() => { + wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?; + } + Instruction::PushConstInt0() => { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?; } @@ -1189,6 +1260,26 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(ObjectReference::NULL)))?; } + Instruction::PutField(fieldref_index) => { + let (_target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?; + + let value = match expected_field_descriptor.as_str() { + "J" | "D" => wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_2(0))?, + _ => match wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))? { + StackValue::Int(i) => FieldValue::Int(i), + StackValue::Reference(r) => FieldValue::Reference(r), + stack_value @ _ => { + println!("{stack_value:?}"); + todo!() + } + } + }; + + let this_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + + self.heap_area.object_area.set_object_field(this_object, target_field_name, value, frame.class_index, &self.class_store)?; + } + Instruction::PutStatic(fieldref_index) => { let (target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?; @@ -1228,7 +1319,13 @@ impl JVM { let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; FieldValue::Boolean((int_value & 1) != 0) - }, + } + + (0, AbstractTypeKind::Int()) => { + let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + FieldValue::Int(int_value) + } (0..=255, AbstractTypeKind::Classname(_field_type_name)) => { let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; @@ -1404,7 +1501,8 @@ fn load_local_int(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackF } fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut VecDeque, argument_types: &Box<[AbstractTypeDescription]>, stack: &mut OperandStack) -> Result<(), Error> { - for argument_type in argument_types { + for argument_type_index in 0..argument_types.len() { + let argument_type = &argument_types[argument_types.len() - argument_type_index - 1]; if argument_type.array_level != 0 { // TODO: Type checking arguments.push_front( @@ -1540,7 +1638,7 @@ fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut Ve Ok(()) } -fn wrap_stackframe_error(class: &JavaClassFile, method: &MethodInfo, frame_result: Result) -> Result { +pub fn wrap_stackframe_error(class: &JavaClassFile, method: &MethodInfo, frame_result: Result) -> Result { match frame_result { Ok(t) => Ok(t), Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), diff --git a/src/native_methods.rs b/src/native_methods.rs index 7bcf502..8999882 100644 --- a/src/native_methods.rs +++ b/src/native_methods.rs @@ -1,4 +1,7 @@ +use crate::heap_area::FieldValue; +use crate::jvm::wrap_stackframe_error; +use crate::stackframe::StackValue; use crate::classfile::{ AbstractTypeDescription, AbstractTypeKind, MethodDescriptor }; use crate::native_registry::NativeMethodCallable; use crate::jvm::JVM; @@ -13,10 +16,110 @@ pub fn todo_call(_: &mut JVM) -> Result { todo!() } -pub fn java_lang_object_get_class(jvm: &mut JVM) -> Result { - todo!() +pub struct EntryPoint {} + +impl EntryPoint { + pub fn populate_unsafe_constants(jvm: &mut JVM) -> Result { + jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("ADDRESS_SIZE0"), FieldValue::Int(4))?; // objectreference use u32 + + jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("PAGE_SIZE"), FieldValue::Int(4096))?; + // TODO: Get actual page size + + jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("BIG_ENDIAN"), FieldValue::Boolean(cfg!(target_endian = "big")))?; + + // This is the safe version, TODO: Change it to the actual value + jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("UNALIGNED_ACCESS"), FieldValue::Boolean(false))?; + + // This is the safe version, TODO: Change it to the actual value + jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("DATA_CACHE_LINE_FLUSH_SIZE"), FieldValue::Int(0))?; + + Ok(JVMCallbackOperation::PopFrame()) + } } +struct JavaLangClass {} + +impl JavaLangClass { + pub fn desired_assertion_status_0(_: &mut JVM) -> Result { + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(1))) + } +} + +struct JdkInternalMiscUnsafe {} + +impl JdkInternalMiscUnsafe { + pub fn array_index_scale_0(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 class_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap(); + + let class_reference = wrap_stackframe_error(class, method, frame.load_local_reference(1))?; + let component_class_reference = match jvm.heap_area.object_area.get_object_field(class_reference, "componentType", class_class_index, &jvm.class_store).unwrap() { + FieldValue::Reference(r) => r, + _ => unreachable!(), + }; + + let index_scale: i32 = if component_class_reference == jvm.class_store.primitive_classes.boolean_class { + 1 + } else if component_class_reference == jvm.class_store.primitive_classes.byte_class { + 1 + } else if component_class_reference == jvm.class_store.primitive_classes.short_class { + 2 + } else if component_class_reference == jvm.class_store.primitive_classes.char_class { + 2 + } else if component_class_reference == jvm.class_store.primitive_classes.int_class { + 4 + } else if component_class_reference == jvm.class_store.primitive_classes.float_class { + 4 + } else if component_class_reference == jvm.class_store.primitive_classes.double_class { + 8 + } else if component_class_reference == jvm.class_store.primitive_classes.long_class { + 8 + } else { + std::mem::size_of::() as i32 + }; + + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(index_scale))) + } + + pub fn array_base_offset_0(jvm: &mut JVM) -> Result { + // TODO: Check passed class + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(0))) + } +} + +pub struct JdkInternalUtilSystemPropsRaw {} + +impl JdkInternalUtilSystemPropsRaw { + pub fn platform_properties(jvm: &mut JVM) -> Result { + let array_length = jvm.heap_area.static_area. + get( + &String::from("jdk/internal/util/SystemProps$Raw"), + &String::from("FIXED_LENGTH"), + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }) + .unwrap(); + let array_length = match array_length { + FieldValue::Int(i) => i as usize, + _ => unreachable!() + }; + + 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); + + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference))) + } + + pub fn vm_properties(jvm: &mut JVM) -> Result { + let array_reference = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, 2); + + Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference))) + } +} + + pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Result { let method_name: &str = &m.name; match (class_name, method_name) { @@ -51,7 +154,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(JavaLangClass::desired_assertion_status_0) } ("java/lang/Class", "getClassAccessFlagsRaw0") => { @@ -487,7 +590,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(ignore_call) } ("java/lang/Class", "setSigners") => { @@ -541,7 +644,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(java_lang_object_get_class) + Ok(todo_call) } ("java/lang/Object", "hashCode") => { @@ -746,7 +849,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(JdkInternalMiscUnsafe::array_base_offset_0) } ("jdk/internal/misc/Unsafe", "arrayIndexScale0") => { @@ -761,7 +864,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(JdkInternalMiscUnsafe::array_index_scale_0) } ("jdk/internal/misc/Unsafe", "allocateInstance") => { @@ -2109,6 +2212,34 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul Ok(todo_call) } + ("jdk/internal/util/SystemProps$Raw", "platformProperties") => { + 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(JdkInternalUtilSystemPropsRaw::platform_properties) + } + + ("jdk/internal/util/SystemProps$Raw", "vmProperties") => { + 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(JdkInternalUtilSystemPropsRaw::vm_properties) + } + _ => Err(Error::RunTimeError(format!("Failed to find native implementation for method '{class_name}.{method_name}'"))), } diff --git a/src/native_registry.rs b/src/native_registry.rs index 0925d85..c200200 100644 --- a/src/native_registry.rs +++ b/src/native_registry.rs @@ -1,4 +1,5 @@ +use crate::stackframe::StackFrame; use crate::jvm::Error; use crate::jvm::JVMCallbackOperation; use crate::jvm::JVM; diff --git a/src/stackframe.rs b/src/stackframe.rs index c7b39d1..ba3a8c7 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -74,6 +74,32 @@ impl OperandStack { } } } + + pub fn pop_computational_2(&mut self, index: usize) -> Result { + let absolute_index = self.depth as usize - 1 - index; + let value_top = self.stack[absolute_index]; + let value_bot = self.stack[absolute_index - 1]; + + 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]]; + + Ok(FieldValue::Long(i64::from_ne_bytes(concat_bytes))) + } + (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))) + } + _ => 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:?}'"))) + } + } pub fn pop_computational_1(&mut self, index: usize) -> Result { let absolute_index = self.depth as usize - 1 - index;