diff --git a/src/bytecode.rs b/src/bytecode.rs index 7573b21..1df94cd 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -11,7 +11,7 @@ impl Bytecode { match opcode { 0x00 => (Instruction::NoOperation(), 1), - 0x01 => (Instruction::StoreIntoIntArray(), 1), + 0x01 => (Instruction::PushNull(), 1), 0x02 => (Instruction::PushConstIntM1(), 1), 0x03 => (Instruction::PushConstInt0(), 1), 0x04 => (Instruction::PushConstInt1(), 1), @@ -25,7 +25,7 @@ impl Bytecode { 0x10 => (Instruction::LoadByteImmediate(self.bytes[offset+1]), 2), 0x11 => (Instruction::LoadShortImmediate((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2), - 0x13 => (Instruction::LoadWideConstant((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), + 0x13 => (Instruction::LoadCostantWide((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0x1A => (Instruction::LoadLocalInt0(), 1), @@ -59,6 +59,7 @@ impl Bytecode { 0x59 => (Instruction::Duplicate(), 1), 0x68 => (Instruction::MultiplyInt(), 1), + 0x6C => (Instruction::DivideInt(), 1), 0x6D => (Instruction::DivideLong(), 1), 0x7A => (Instruction::ShiftIntRight(), 1), @@ -135,6 +136,18 @@ impl Bytecode { 0xBC => (Instruction::NewPrimitiveArray(self.bytes[offset+1]), 2), 0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xBE => (Instruction::ArrayLength(), 1), + + 0xC2 => (Instruction::EnterMonitor(), 1), + 0xC3 => (Instruction::ExitMonitor(), 1), + + 0xC6 => { + let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; + (Instruction::BranchNull(i16::from_be_bytes(bytes)), 3) + } + 0xC7 => { + let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; + (Instruction::BranchNonNull(i16::from_be_bytes(bytes)), 3) + } _ => (Instruction::Unknown(opcode), 1) } } @@ -167,7 +180,7 @@ impl Debug for Bytecode { #[repr(u8)] pub enum Instruction { NoOperation() = 0x00, // No-Operation - StoreIntoIntArray() = 0x01, // ..., arrayref, index, value + PushNull() = 0x01, // ..., arrayref, index, value PushConstIntM1() = 0x02, // Push -1 PushConstInt0() = 0x03, // Push 0 PushConstInt1() = 0x04, // Push 1 @@ -181,7 +194,7 @@ pub enum Instruction { LoadByteImmediate(u8) = 0x10, // push immediate short LoadShortImmediate(u16) = 0x11, // push immediate short LoadConstant(u8) = 0x12, // Push from constant pool - LoadWideConstant(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 @@ -215,6 +228,7 @@ pub enum Instruction { Duplicate() = 0x59, // duplicate top stack value MultiplyInt() = 0x68, // int multiplication + DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideLong() = 0x6D, // long division ShiftIntRight() = 0x7a, // shift int @@ -252,5 +266,11 @@ pub enum Instruction { NewPrimitiveArray(u8) = 0xBC, // make a primitive array NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference ArrayLength() = 0xBE, // Get length from array reference + + EnterMonitor() = 0xC2, // enter the synchronization monitor of an object + ExitMonitor() = 0xC3, // exit the synchronization monitor of an object + BranchNull(i16) = 0xC6, // branch if Null + BranchNonNull(i16) = 0xC7, // branch if Null + Unknown(u8), } diff --git a/src/classfile.rs b/src/classfile.rs index 014ddc5..5d5e3f7 100644 --- a/src/classfile.rs +++ b/src/classfile.rs @@ -763,6 +763,24 @@ 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!(), + } + } +} + #[derive(Debug, Eq, PartialEq, Clone, Hash)] pub struct AbstractTypeDescription { pub array_level: u8, @@ -786,6 +804,28 @@ impl Into for &AbstractTypeDescription { } impl AbstractTypeDescription { + + pub fn super_component(&self) -> Self { + AbstractTypeDescription { + array_level: 0, + kind: self.kind.clone() + } + } + + pub fn component(&self) -> Self { + AbstractTypeDescription { + array_level: self.array_level - 1, + kind: self.kind.clone() + } + } + + pub fn array(&self) -> Self { + AbstractTypeDescription { + array_level: self.array_level + 1, + kind: self.kind.clone() + } + } + pub fn parse_full(s: &str) -> Result { let (c, parsed) = Self::parse_first(s)?; diff --git a/src/classstore.rs b/src/classstore.rs index 5885324..a9ad0c4 100644 --- a/src/classstore.rs +++ b/src/classstore.rs @@ -17,6 +17,19 @@ pub struct ClassStore { classes: Vec, class_path_fragments: Vec, native_class_names: Vec, + 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, } #[derive(Debug)] @@ -71,6 +84,7 @@ impl ClassStore { classes: Vec::new(), class_path_fragments: vec![current_dir_path], native_class_names: Vec::new(), + primitive_classes: PrimitiveClassStore::default(), } } @@ -121,7 +135,7 @@ impl ClassStore { } }; - return Err(Error::ClassNotFoundError(format!("Could not find class '{}' in classpath", classname))); + return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath"))); } pub fn are_types_compatible(&self, my_type: &AbstractTypeDescription, other_type: &AbstractTypeDescription) -> bool { @@ -209,7 +223,33 @@ impl ClassStore { self.classes[index].class_object } + pub fn get_class_objectref_from_primitive(&self, primitive: AbstractTypeKind) -> Option { + match primitive { + AbstractTypeKind::Boolean() => { + Some(self.primitive_classes.boolean_class) + } + _ => todo!(), + } + } + pub fn get_array_class_ref(&self, type_desc: &AbstractTypeDescription) -> Option { return self.array_classes.get(type_desc).copied(); } + + pub fn class_ref_for_type(&self, r#type: AbstractTypeDescription) -> Option { + match (r#type.array_level, &r#type.kind) { + (0, AbstractTypeKind::Classname(ref name)) => { + let class_index = self.class_idx_from_name(name).unwrap(); + Some(self.get_class_objectref_from_index(class_index)) + } + + (0, _) => { + self.get_class_objectref_from_primitive(r#type.kind) + } + + (1..=u8::MAX, _) => { + self.get_array_class_ref(&r#type) + } + } + } } diff --git a/src/heap_area.rs b/src/heap_area.rs index 57969a2..56abcfa 100644 --- a/src/heap_area.rs +++ b/src/heap_area.rs @@ -93,7 +93,7 @@ impl HeapArea { } -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct ObjectReference(u32); diff --git a/src/jvm.rs b/src/jvm.rs index 6bb2eeb..4804e9b 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -12,6 +12,9 @@ use crate::classstore::ClassStore; use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo}; 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::stackframe; use crate::stackframe::{ StackFrame, StackValue, OperandStack }; @@ -53,6 +56,7 @@ pub struct JVM { pub class_store: ClassStore, pub stack_frames: Vec, pub heap_area: HeapArea, + pub native_registry: NativeRegistry, } impl JVM { @@ -61,9 +65,30 @@ impl JVM { class_store: ClassStore::new(), stack_frames: Vec::new(), heap_area: HeapArea::new(usize::MAX), + native_registry: NativeRegistry::default(), } } + fn load_class(&mut self, class_name: &String) -> Result { + let class_index = self.class_store.load_class(class_name)?; + + let class_file = self.class_store.class_file_from_idx(class_index).unwrap(); + + for (method_name, method_implementation) in class_file.methods.iter() + .filter(|m| m.access_flags & MethodAccessFlag::Native) + .map(| m | (&m.name, native_methods::function_for(class_name, m))) { + + let method_implementation = match method_implementation { + Ok(m) => m, + Err(e) => return Err(e) + }; + + self.native_registry.register(class_name, method_name, method_implementation); + } + + Ok(class_index) + } + fn class_native_class_data() -> JavaClassFile { JavaClassFile { minor_version: 0, @@ -208,6 +233,10 @@ 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, @@ -278,11 +307,11 @@ impl JVM { self.class_store.add_class(entry_class, true)?; // 0 self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1 - self.class_store.load_class(&"java/lang/Object".to_string())?; // 2 - self.class_store.load_class(&"java/lang/Number".to_string())?; // 3 - self.class_store.load_class(&"java/lang/Byte".to_string())?; // 4 - self.class_store.load_class(&"java/lang/String".to_string())?; // 5 - self.class_store.load_class(&"java/lang/Class".to_string())?; // 6 + 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.make_class_class("Ljava/lang/Byte;"); self.make_class_class("Ljava/lang/String;"); @@ -388,7 +417,7 @@ impl JVM { if ! self.class_store.have_class(&class_name) { println!("Loading Class {class_name}"); - self.class_store.load_class(&class_name)?; + self.load_class(&class_name)?; let (file, _) = self.class_store.get_class(&class_name).unwrap(); if file.has_super_class() { waiting_queue.push_back(file.get_super_class_name()?.to_string()); @@ -536,6 +565,25 @@ impl JVM { Ok(()) } + fn native_call(&mut self) -> Result { + let frame = { + let frame_index = self.stack_frames.len() - 1; + &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]; + let class_name = class.get_classname().unwrap(); + + let native_method = match self.native_registry.get(class_name, &method.name) { + Some(m) => m, + None => { + return Err(Error::RunTimeError(format!("Tried to call native method '{class_name}.{}' but there is no such method in the method registry", method.name))); + } + }; + + native_method(self) + } + fn bytecode_loop(&mut self) -> Result { let frame = { @@ -544,6 +592,11 @@ impl JVM { }; 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 { + return self.native_call() + } + let code_attr = method.get_code_attribute().unwrap(); let bytecode = & code_attr.code; @@ -577,6 +630,16 @@ impl JVM { 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::BranchIntEquality(branch_offset) => { + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(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::BranchIntInequality(branch_offset) => { let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; @@ -587,6 +650,24 @@ impl JVM { } } + Instruction::BranchNonNull(branch_offset) => { + let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + + if test_value != ObjectReference::NULL { + 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))?; + + if test_value == ObjectReference::NULL { + 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::BranchZero(branch_offset) => { let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; @@ -596,12 +677,29 @@ impl JVM { } } + Instruction::DivideInt() => { + // TODO: Obey all the rules + let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let divident = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + + frame.operand_stack.push(StackValue::Int(divident / quotient)).unwrap(); + } + Instruction::Duplicate() => { let popped_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?; wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?; wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?; } + Instruction::EnterMonitor() => { + // TODO: Revisit this when doing multi-threading + let _monitored_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + } + Instruction::ExitMonitor() => { + // TODO: Revisit this when doing multi-threading + let _monitored_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + } + Instruction::GetField(fieldref_index) => { let (class_name, field_name, field_descriptor) = class.gather_fieldref(fieldref_index).unwrap(); @@ -742,6 +840,9 @@ impl JVM { ))); } + if callee_method_info.access_flags & MethodAccessFlag::Native { + } + let supplied_descriptor: MethodDescriptor = supplied_descriptor_string.try_into()?; // TODO: Throw exception on fail @@ -759,6 +860,7 @@ impl JVM { let mut arguments = VecDeque::new(); fill_arguments(class, method, &mut arguments, &callee_method_info.descriptor.argument_types, &mut frame.operand_stack)?; + // TODO: Throw errors on abstract methods etc. let new_frame = StackFrame::new( callee_class_file, callee_class_index, @@ -849,11 +951,93 @@ impl JVM { Ok(_) => (), Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), } + } + + Instruction::LoadConstant(index) => { + // TODO: Handle error instead of unwrap + match class.pool_entry(index as u16).unwrap() { + ConstantPoolInfo::Class(_) => { + let class_name = class.gather_class(index as u16).unwrap(); + + 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())); + } + + let class_index = self.class_store.class_idx_from_name(class_name).unwrap(); + let class_object_ref = self.class_store.get_class_objectref_from_index(class_index); + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(class_object_ref)))?; + } + + ConstantPoolInfo::String(_) => { + // TODO: Handle error instead of unwrap + let string_constant = class.gather_string(index as u16).unwrap(); + + let string_obj_ref = self.heap_area.make_handmade_string(string_constant, &self.class_store); + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?; + }, + _ => { + println!("{:?}", class.pool_entry(index as u16).unwrap()); + todo!() + } + } }, - Instruction::LoadWideConstant(wide_index) => { + Instruction::LoadCostantWide(wide_index) => { // TODO: Handle error instead of unwrap match class.pool_entry(wide_index).unwrap() { + ConstantPoolInfo::Class(_) => { + let class_name = class.gather_class(wide_index).unwrap(); + + let class_object_ref = if class_name.starts_with('[') { + let component_name = class_name.trim_start_matches('['); + 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()) + } + }; + + if let Some(array_ref) = self.class_store.get_array_class_ref(&array_type_desc) { + array_ref + } else { + let mut test_type = array_type_desc.super_component(); + let mut test_object_ref = self.class_store.class_ref_for_type(test_type.clone()).unwrap(); + + while let Some(new_test_object_ref) = self.class_store.class_ref_for_type(test_type.array()) { + test_type = test_type.array(); + test_object_ref = new_test_object_ref; + } + + frame.instruction_pointer -= offset as u32; + return Ok(JVMCallbackOperation::MakeArrayClass(test_object_ref, test_type)) + } + } 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())); + } + + let class_index = self.class_store.class_idx_from_name(class_name).unwrap(); + self.class_store.get_class_objectref_from_index(class_index) + }; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(class_object_ref)))?; + } + ConstantPoolInfo::String(_) => { // TODO: Handle error instead of unwrap let string_constant = class.gather_string(wide_index).unwrap(); @@ -862,7 +1046,10 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?; }, - _ => todo!(), + _ => { + println!("{:?}", class.pool_entry(wide_index).unwrap()); + todo!() + } } }, @@ -998,6 +1185,10 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(5)))?; } + Instruction::PushNull() => { + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(ObjectReference::NULL)))?; + } + Instruction::PutStatic(fieldref_index) => { let (target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?; @@ -1042,11 +1233,13 @@ impl JVM { (0..=255, AbstractTypeKind::Classname(_field_type_name)) => { let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; - let value_native_name = self.heap_area.object_area.get_reference_native_class_name(ref_value, &self.class_store); - let parsed_native_name = AbstractTypeDescription::parse_first(value_native_name).unwrap().1; + if ref_value != ObjectReference::NULL { + let value_native_name = self.heap_area.object_area.get_reference_native_class_name(ref_value, &self.class_store); + let parsed_native_name = AbstractTypeDescription::parse_first(value_native_name).unwrap().1; - if ! self.class_store.are_types_compatible(&matched_field.descriptor, &parsed_native_name) { - return Err(Error::RunTimeError(format!("PutStatic: Trying to set a value with type '{parsed_native_name:?}' on a field with type '{:?}'", matched_field.descriptor))); + if ! self.class_store.are_types_compatible(&matched_field.descriptor, &parsed_native_name) { + return Err(Error::RunTimeError(format!("PutStatic: Trying to set a value with type '{parsed_native_name:?}' on a field with type '{:?}'", matched_field.descriptor))); + } } FieldValue::Reference(ref_value) @@ -1070,6 +1263,16 @@ impl JVM { return Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(int))); } + Instruction::ReturnReference() => { + match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) { + (_, AbstractTypeKind::Classname(_)) => (), + _ => return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type))) + } + + let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + + return Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ref_value))); + } Instruction::ReturnVoid() => { let expected_type = AbstractTypeDescription { array_level: 0, @@ -1090,17 +1293,7 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?; }, - Instruction::StoreIntoRArray() => { - let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; - let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; - let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; - - // TODO: Type checking - - self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value)); - } - - Instruction::StoreIntoBArray() => { + Instruction::StoreIntoBArray() => { let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; @@ -1115,6 +1308,16 @@ impl JVM { } } + Instruction::StoreIntoRArray() => { + let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; + + // TODO: Type checking + + self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value)); + } + Instruction::StoreLocalInt(index) => { let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; @@ -1175,7 +1378,7 @@ impl JVM { } -enum JVMCallbackOperation { +pub enum JVMCallbackOperation { PopFrame(), ReturnFrame(StackValue), PushFrame(StackFrame), diff --git a/src/main.rs b/src/main.rs index b17fe97..24a5a86 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,15 +7,17 @@ mod accessmasks; mod constantpool; mod heap_area; mod iterators; +mod native_registry; +mod native_methods; -use std::fs::File; +//use std::fs::File; // -use crate::accessmasks::FieldAccessFlag; +//use crate::accessmasks::FieldAccessFlag; //use crate::stackframe::StackValue; -use crate::classfile::JavaClassFile; +//use crate::classfile::JavaClassFile; fn main() { - //println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/String.class").unwrap()).unwrap().fields.iter().filter(|f| ! (f.access_flags & FieldAccessFlag::Static)).collect::>()); + //println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/System.class").unwrap()).unwrap()); let mut jvm = jvm::JVM::new(); diff --git a/src/native_methods.rs b/src/native_methods.rs new file mode 100644 index 0000000..8aaf95b --- /dev/null +++ b/src/native_methods.rs @@ -0,0 +1,603 @@ + +use crate::classfile::{ AbstractTypeDescription, AbstractTypeKind, MethodDescriptor }; +use crate::native_registry::NativeMethodCallable; +use crate::jvm::JVM; +use crate::jvm::Error; +use crate::jvm::JVMCallbackOperation; + +pub fn ignore_call(_: &mut JVM) -> Result { + Ok(JVMCallbackOperation::PopFrame()) +} + +pub fn todo_call(_: &mut JVM) -> Result { + todo!() +} + +pub fn java_lang_object_get_class(jvm: &mut JVM) -> Result { + todo!() +} + +pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Result { + let method_name: &str = &m.name; + match (class_name, method_name) { + + ("java/lang/Class", "forName0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string()) }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/ClassLoader".to_string()) }, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) }, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Class"))}, + }; + + 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) + } + + ("java/lang/Class", "desiredAssertionStatus0") => { + let expected_descriptor = 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::Boolean()}, + }; + + 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) + } + + ("java/lang/Class", "getClassAccessFlagsRaw0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + }; + + 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) + } + + ("java/lang/Class", "getClassFileVersion0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + }; + + 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) + } + + ("java/lang/Class", "getConstantPool") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("jdk/internal/reflect/ConstantPool".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) + } + + ("java/lang/Class", "getDeclaredClasses0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Class".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) + } + + ("java/lang/Class", "getDeclaredConstructors0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() }, + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/Constructor".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) + } + + ("java/lang/Class", "getDeclaredFields0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() }, + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/Field".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) + } + + ("java/lang/Class", "getDeclaredMethods0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() }, + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/Method".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) + } + + ("java/lang/Class", "getDeclaringClass0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".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) + } + + ("java/lang/Class", "getEnclosingMethod0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".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) + } + + ("java/lang/Class", "getGenericSignature0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, 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) + } + + ("java/lang/Class", "getInterfaces0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Class".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) + } + + ("java/lang/Class", "getNestMembers0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Class".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) + } + + ("java/lang/Class", "getModifiers") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }, + }; + + 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) + } + + ("java/lang/Class", "getNestHost0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".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) + } + + ("java/lang/Class", "getPermittedSubclasses0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Class".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) + } + + ("java/lang/Class", "getPrimitiveClass") => { + let expected_descriptor = 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()) }, + }; + + 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) + } + + ("java/lang/Class", "getProtectionDomain0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/security/ProtectionDomain".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) + } + + ("java/lang/Class", "getRawAnnotations") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() }, + }; + + 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) + } + + ("java/lang/Class", "getRawTypeAnnotations") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() }, + }; + + 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) + } + + ("java/lang/Class", "getRecordComponents0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + ]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/RecordComponent".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) + } + + ("java/lang/Class", "getSimpleBinaryName0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, 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) + } + + ("java/lang/Class", "getSigners") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".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) + } + + ("java/lang/Class", "getSuperclass") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".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) + } + + ("java/lang/Class", "isAssignableFrom") => { + let expected_descriptor = 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::Boolean()}, + }; + + 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) + } + + ("java/lang/Class", "initClassName") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, 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) + } + + ("java/lang/Class", "isArray") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()}, + }; + + 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) + } + + ("java/lang/Class", "isHidden") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()}, + }; + + 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) + } + + ("java/lang/Class", "isInstance") => { + let expected_descriptor = 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()}, + }; + + 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) + } + + ("java/lang/Class", "isInterface") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()}, + }; + + 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) + } + + ("java/lang/Class", "isPrimitive") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()}, + }; + + 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) + } + + ("java/lang/Class", "isRecord0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()}, + }; + + 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) + } + + ("java/lang/Class", "registerNatives") => { + 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(todo_call) + } + + ("java/lang/Class", "setSigners") => { + let expected_descriptor = 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::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(todo_call) + } + + ("java/lang/String", "intern") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/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) + } + + ("java/lang/Object", "clone") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Object"))}, + }; + + 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) + } + + ("java/lang/Object", "getClass") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Class"))}, + }; + + 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(java_lang_object_get_class) + } + + ("java/lang/Object", "hashCode") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int()}, + }; + + 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) + } + + ("java/lang/Object", "notifyAll") => { + 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(todo_call) + } + + ("java/lang/Object", "notify") => { + 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(todo_call) + } + ("java/lang/Object", "wait0") => { + let expected_descriptor = MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long() }, + ]), + 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(todo_call) + } + + + _ => 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 new file mode 100644 index 0000000..0925d85 --- /dev/null +++ b/src/native_registry.rs @@ -0,0 +1,26 @@ + +use crate::jvm::Error; +use crate::jvm::JVMCallbackOperation; +use crate::jvm::JVM; +use std::collections::HashMap; + +#[derive(Debug, Default)] +pub struct NativeRegistry { + methods: HashMap, +} + +impl NativeRegistry { + pub fn get(&self, class_name: &String, method_name: &String) -> Option<&NativeMethodCallable> { + self.methods.get(&MethodPath(class_name.to_string(), method_name.to_string())) + } + + pub fn register(&mut self, class_name: &str, method_name: &str, n: NativeMethodCallable) { + self.methods.insert(MethodPath(class_name.to_string(), method_name.to_string()), n); + } +} + +pub type NativeMethodCallable=fn (&mut JVM) -> Result; + +#[derive(Debug)] +#[derive(Eq, Hash, PartialEq)] +pub struct MethodPath(String, String); diff --git a/src/stackframe.rs b/src/stackframe.rs index 65fa90b..c7b39d1 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -1,4 +1,5 @@ -use crate::classfile::{ JavaClassFile, AttributeData }; +use crate::accessmasks::MethodAccessFlag; +use crate::classfile::{ AttributeData, JavaClassFile }; use crate::heap_area::{ ObjectReference, FieldValue }; #[derive(Copy, Clone, Debug)] @@ -63,6 +64,10 @@ impl OperandStack { self.push(StackValue::Int(b as i32)) } + FieldValue::Int(i) => { + self.push(StackValue::Int(i)) + } + _ => { println!("{value:?}"); todo!(); @@ -244,11 +249,19 @@ pub struct StackFrame { impl StackFrame { pub fn new(classfile: &JavaClassFile, class_index: usize, method_index: u16, arguments: &[StackValue]) -> Self { let method_info = &classfile.methods[method_index as usize]; - let code_data = match &method_info.attributes[method_info.code_attribute_index].data { - AttributeData::Code(data) => data, - _ => unreachable!(), + + let (max_locals, max_stack) = if method_info.access_flags & MethodAccessFlag::Native { + (arguments.len(), 1) + } else { + let code_data = match &method_info.attributes[method_info.code_attribute_index].data { + AttributeData::Code(data) => data, + _ => unreachable!(), + }; + + (code_data.max_locals as usize, code_data.max_stack) }; - let mut locals = vec![StackValue::Empty(); code_data.max_locals.into()].into_boxed_slice(); + + let mut locals = vec![StackValue::Empty(); max_locals].into_boxed_slice(); assert!(locals.len() >= arguments.len()); @@ -258,7 +271,7 @@ impl StackFrame { StackFrame { locals, - operand_stack: OperandStack::new(code_data.max_stack), + operand_stack: OperandStack::new(max_stack), class_index, method_index, instruction_pointer: 0,