diff --git a/src/bytecode.rs b/src/bytecode.rs index 9b69209..b9ded4c 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -39,6 +39,7 @@ impl Bytecode { 0x15 => (Instruction::LoadLocalInt(self.bytes[offset+1]), 2), 0x16 => (Instruction::LoadLocalLong(self.bytes[offset+1]), 2), 0x17 => (Instruction::LoadLocalFloat(self.bytes[offset+1]), 2), + 0x18 => (Instruction::LoadLocalDouble(self.bytes[offset+1]), 2), 0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2), 0x1A => (Instruction::LoadLocalInt0(), 1), 0x1B => (Instruction::LoadLocalInt1(), 1), @@ -66,6 +67,7 @@ impl Bytecode { 0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2), 0x37 => (Instruction::StoreLocalLong(self.bytes[offset+1]), 2), 0x38 => (Instruction::StoreLocalFloat(self.bytes[offset+1]), 2), + 0x39 => (Instruction::StoreLocalDouble(self.bytes[offset+1]), 2), 0x3A => (Instruction::StoreLocalReference(self.bytes[offset+1]), 2), 0x3B => (Instruction::StoreLocalInt0(), 1), 0x3C => (Instruction::StoreLocalInt1(), 1), @@ -101,6 +103,7 @@ impl Bytecode { 0x6C => (Instruction::DivideInt(), 1), 0x6D => (Instruction::DivideLong(), 1), 0x6E => (Instruction::DivideFloat(), 1), + 0x6F => (Instruction::DivideDouble(), 1), 0x70 => (Instruction::ModuloInt(), 1), 0x74 => (Instruction::NegateInt(), 1), @@ -110,6 +113,7 @@ impl Bytecode { 0x7A => (Instruction::ArithmeticShiftIntRight(), 1), 0x7B => (Instruction::ArithmeticShiftLongRight(), 1), 0x7C => (Instruction::LogicalShiftIntRight(), 1), + 0x7D => (Instruction::LogicalShiftLongRight(), 1), 0x7E => (Instruction::AndInt(), 1), 0x7F => (Instruction::AndLong(), 1), @@ -119,16 +123,20 @@ impl Bytecode { 0x85 => (Instruction::ConvertIntToLong(), 1), 0x86 => (Instruction::ConvertIntToFloat(), 1), + 0x87 => (Instruction::ConvertIntToDouble(), 1), 0x88 => (Instruction::ConvertLongToInt(), 1), 0x89 => (Instruction::ConvertLongToFloat(), 1), 0x8B => (Instruction::ConvertFloatToInt(), 1), 0x8D => (Instruction::ConvertFloatToDouble(), 1), + 0x8E => (Instruction::ConvertDoubleToInt(), 1), 0x8F => (Instruction::ConvertDoubleToLong(), 1), 0x91 => (Instruction::ConvertIntToByte(), 1), 0x92 => (Instruction::ConvertIntToChar(), 1), 0x94 => (Instruction::CompareLong(), 1), 0x95 => (Instruction::CompareFloatL(), 1), 0x96 => (Instruction::CompareFloatG(), 1), + 0x97 => (Instruction::CompareDoubleL(), 1), + 0x98 => (Instruction::CompareDoubleG(), 1), 0x99 => { let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; (Instruction::BranchZero(i16::from_be_bytes(bytes)), 3) @@ -238,6 +246,7 @@ impl Bytecode { } 0xAC => (Instruction::ReturnInt(), 1), 0xAD => (Instruction::ReturnLong(), 1), + 0xAF => (Instruction::ReturnDouble(), 1), 0xB0 => (Instruction::ReturnReference(), 1), 0xB1 => (Instruction::ReturnVoid(), 1), @@ -326,6 +335,7 @@ pub enum Instruction { LoadLocalInt(u8) = 0x15, // Load int from indexed local variable LoadLocalLong(u8) = 0x16, // Load long from indexed local variable LoadLocalFloat(u8) = 0x17, // Load float from indexed local variable + LoadLocalDouble(u8) = 0x18, // Load double from indexed local variable LoadLocalReference(u8) = 0x19, // Load reference from indexed local variable LoadLocalInt0() = 0x1A, // Load int from local variable LoadLocalInt1() = 0x1B, // Load int from local variable @@ -354,6 +364,7 @@ pub enum Instruction { StoreLocalInt(u8) = 0x36, // store into indexed local variable StoreLocalLong(u8) = 0x37, // store into indexed local variable StoreLocalFloat(u8) = 0x38, // store into indexed local variable + StoreLocalDouble(u8) = 0x39, // store into indexed local variable StoreLocalReference(u8) = 0x3A, // store into indexed local variable StoreLocalInt0() = 0x3B, // store int into local variable StoreLocalInt1() = 0x3C, // store int into local variable @@ -388,6 +399,7 @@ pub enum Instruction { DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideLong() = 0x6D, // long division DivideFloat() = 0x6E, // float division + DivideDouble() = 0x6F, // double division ModuloInt() = 0x70, // modulo NegateInt() = 0x74, // arithmetic negation @@ -397,6 +409,7 @@ pub enum Instruction { ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign ArithmeticShiftLongRight() = 0x7B, // shift long right, preserve sign LogicalShiftIntRight() = 0x7C, // shift int right with zero extension + LogicalShiftLongRight() = 0x7D, // shift long right with zero extension AndInt() = 0x7E, // bitwise and AndLong() = 0x7F, // bitwise and @@ -406,16 +419,20 @@ pub enum Instruction { ConvertIntToLong() = 0x85, // convert int on stack to long ConvertIntToFloat() = 0x86, // change data type + ConvertIntToDouble() = 0x87, // change data type ConvertLongToInt() = 0x88, // change data type ConvertLongToFloat() = 0x89, // change data type ConvertFloatToInt() = 0x8B, // change data type ConvertFloatToDouble() = 0x8D, // change data type + ConvertDoubleToInt() = 0x8E, // change data type ConvertDoubleToLong() = 0x8F, // change data type ConvertIntToByte() = 0x91, // truncate int to 8 bits ConvertIntToChar() = 0x92, // truncate int to 16 bits CompareLong() = 0x94, // compare long CompareFloatL() = 0x95, // compare float, push -1 if one is NaN CompareFloatG() = 0x96, // compare float, push 1 if one is NaN + CompareDoubleL() = 0x97, // compare float, push -1 if one is NaN + CompareDoubleG() = 0x98, // compare float, push 1 if one is NaN BranchZero(i16) = 0x99, // branch if value == 0 BranchNonZero(i16) = 0x9A, // branch if value != 0 BranchNegative(i16) = 0x9B, // branch if value < 0 @@ -437,6 +454,7 @@ pub enum Instruction { LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // jump based on switch value ReturnInt() = 0xAC, // return integer from function ReturnLong() = 0xAD, // return long from function + ReturnDouble() = 0xAF, // return double from function ReturnReference() = 0xB0, // return top-ref from current function ReturnVoid() = 0xB1, // return void from function diff --git a/src/classfile.rs b/src/classfile.rs index 4ce88d9..7889a29 100644 --- a/src/classfile.rs +++ b/src/classfile.rs @@ -5,8 +5,10 @@ use core::str::Utf8Error; use crate::accessmasks::*; use crate::bytecode::Bytecode; +use crate::classstore::ClassStore; use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantInterfaceMethodRefInfo, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo }; use crate::constantpool::ConstantDoubleInfo; +use crate::heap_area::ObjectReference; #[derive(Debug)] pub enum Error { @@ -191,6 +193,15 @@ impl JavaClassFile { return Ok(&name_entry.utf8); } + pub fn resolve_method_index(&self, name: &str, descriptor: &str) -> Option { + for (index, method_info) in (&self.methods).into_iter().enumerate() { + if method_info.name == *name && method_info.descriptor == (&descriptor.to_string()).try_into().unwrap() { + return Some(index as u16); + } + } + + return None; + } pub fn find_method_index(&self, name: &String) -> Option { @@ -401,21 +412,22 @@ impl JavaClassFile { } } - pub fn is_method_bytecode_protected(&self, method: &MethodInfo, instruction_pointer: u16, exception: crate::heap_area::ObjectReference) -> bool { + pub fn is_method_bytecode_protected(&self, method: &MethodInfo, instruction_pointer: u16, exception_class_index: usize, class_store: &ClassStore) -> Result { let code_attribute = method.get_code_attribute().unwrap(); for exception_entry in &code_attribute.exception_table { if exception_entry.start_pc <= instruction_pointer && exception_entry.end_pc > instruction_pointer { if exception_entry.catch_type == 0 { - return true; + return Ok(true); } else { // Check catch-type - todo!() + let catch_type_name = self.gather_class(exception_entry.catch_type); + return Ok(class_store.are_types_compatible_0(exception_class_index, catch_type_name?)); } } } - false + Ok(false) } } diff --git a/src/classstore.rs b/src/classstore.rs index 19a753c..87393fc 100644 --- a/src/classstore.rs +++ b/src/classstore.rs @@ -140,6 +140,13 @@ impl ClassStore { return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath"))); } + pub fn are_types_compatible_0(&self, my_index: usize, other_name: &str) -> bool { + CompatibleTypesIterator::new(my_index, self) + .filter(|type_name| *type_name == other_name) + .next() + .is_some() + } + pub fn are_types_compatible(&self, my_type: &AbstractTypeDescription, other_type: &AbstractTypeDescription) -> bool { if my_type == other_type { return true; } if my_type.array_level != other_type.array_level { return false; } diff --git a/src/heap_area.rs b/src/heap_area.rs index e6174b4..1f4b24b 100644 --- a/src/heap_area.rs +++ b/src/heap_area.rs @@ -280,6 +280,20 @@ impl ObjectArea { } } + pub fn get_object_field_count(&self, reference: ObjectReference) -> usize { + match self.get_entry(reference) { + CompartmentEntry::Object(o) => o.fields.len(), + _ => unreachable!(), + } + } + + pub fn get_object_field_at(&self, reference: ObjectReference, index: usize) -> ObjectField { + match self.get_entry(reference) { + CompartmentEntry::Object(o) => o.fields[index], + _ => unreachable!(), + } + } + pub fn get_reference_class_ref(&self, reference: ObjectReference, class_store: &ClassStore) -> ObjectReference { match self.get_entry(reference) { CompartmentEntry::Object(o) => class_store.get_class_objectref_from_index(o.class_index), @@ -336,8 +350,8 @@ impl ObjectArea { CompartmentEntry::ByteArray(_) => true, CompartmentEntry::CharArray(_) => true, CompartmentEntry::IntArray(_) => true, - CompartmentEntry::EmptyNext(_) => true, - CompartmentEntry::EmptyTail() => true, + CompartmentEntry::EmptyNext(_) => unreachable!(), + CompartmentEntry::EmptyTail() => unreachable!(), } } @@ -720,7 +734,7 @@ pub struct StaticField { pub value: FieldValue, } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub struct ObjectField { pub value: FieldValue, } diff --git a/src/iterators.rs b/src/iterators.rs index 01946c0..a7983c5 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -58,7 +58,7 @@ impl <'i>CompatibleTypesIterator<'i> { } impl <'i> Iterator for CompatibleTypesIterator<'i>{ - type Item = &'i String; // class index, method index, method info + type Item = &'i String; fn next(&mut self) -> Option { let (class_index, interface_index) = match self.class_stack.pop() { diff --git a/src/jvm.rs b/src/jvm.rs index 62b61ed..d726863 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -495,7 +495,8 @@ impl JVM { if method.is_native() { false } else { - class.is_method_bytecode_protected(method, frame.instruction_pointer as u16, exception) + let exception_type_index = self.heap_area.object_area.get_object_class_index(exception); + class.is_method_bytecode_protected(method, frame.instruction_pointer as u16, exception_type_index, &self.class_store)? } }; @@ -1023,6 +1024,40 @@ impl JVM { } + Instruction::CompareDoubleG() => { + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + + let comparison_result = if value_1.is_nan() || value_2.is_nan() { + 1 + } else if value_1 == value_2 { + 0 + } else if value_1 < value_2 { + -1 + } else { + 1 + }; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(comparison_result)))?; + } + + Instruction::CompareDoubleL() => { + let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + + let comparison_result = if value_1.is_nan() || value_2.is_nan() { + -1 + } else if value_1 == value_2 { + 0 + } else if value_1 < value_2 { + -1 + } else { + 1 + }; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(comparison_result)))?; + } + Instruction::CompareFloatG() => { let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; @@ -1089,6 +1124,17 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?; } + Instruction::ConvertDoubleToInt() => { + let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + let int_value = match double { + f64::INFINITY => i32::MAX, + f64::NEG_INFINITY => i32::MIN, + v @ _ => if v.is_nan() { 0 } else { v as i32 } , + }; + + wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?; + } + Instruction::ConvertDoubleToLong() => { let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; let long = match double { @@ -1114,6 +1160,13 @@ impl JVM { frame.operand_stack.push(StackValue::Int(char_value)).unwrap(); } + Instruction::ConvertIntToDouble() => { + let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; + let double_value = int_value as f64; + + frame.operand_stack.push_double(double_value).unwrap(); + } + Instruction::ConvertIntToFloat() => { let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let float_value = int_value as f32; @@ -1142,6 +1195,14 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(float_value)))?; } + Instruction::DivideDouble() => { + // TODO: Obey all the rules + let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + let divident = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + + frame.operand_stack.push_double(divident / quotient).unwrap(); + } + Instruction::DivideFloat() => { // TODO: Obey all the rules let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; @@ -1733,6 +1794,14 @@ impl JVM { } } + Instruction::LoadLocalDouble(index) => { + load_local_double(class, method, frame, index as usize)?; + } + + Instruction::LoadLocalDouble0() => { + load_local_double(class, method, frame, 0)?; + } + Instruction::LoadLocalFloat(index) => { load_local_float(class, method, frame, index as usize)?; } @@ -1813,6 +1882,16 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(i_result)))?; } + Instruction::LogicalShiftLongRight() => { + let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00111111; + let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?; + let uint = u64::from_ne_bytes(int.to_ne_bytes()); + let u_result = uint >> shift; + let i_result = i64::from_ne_bytes(u_result.to_ne_bytes()); + + wrap_stackframe_error(class, method, frame.operand_stack.push_long(i_result))?; + } + Instruction::LookupSwitch(default_offset, pairs) => { let key = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let jump_offset = match pairs.binary_search_by(|(match_key, _offset)| match_key.cmp(&key)) { @@ -2156,6 +2235,17 @@ impl JVM { self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?; } + Instruction::ReturnDouble() => { + match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) { + (0, AbstractTypeKind::Double()) => (), + _ => return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type))) + } + + let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + + return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Double(double))); + } + Instruction::ReturnInt() => { match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) { (_, AbstractTypeKind::Byte() | AbstractTypeKind::Boolean()| AbstractTypeKind::Int() | AbstractTypeKind::Char() | AbstractTypeKind::Short()) => (), @@ -2265,6 +2355,12 @@ impl JVM { wrap_stackframe_error(class, method, frame.operand_stack.push_long(value_1 - value_2))?; } + Instruction::StoreLocalDouble(index) => { + let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; + + wrap_stackframe_error(class, method, frame.store_local_double(index as u16, double))?; + } + Instruction::StoreLocalFloat(index) => { let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; @@ -2420,6 +2516,14 @@ fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut Ok(()) } +fn load_local_double(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> { + let loaded_value = wrap_stackframe_error(class, method, frame.load_local_double(index as u16))?; + + wrap_stackframe_error(class, method, frame.operand_stack.push_double(loaded_value))?; + + Ok(()) +} + fn load_local_float(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> { let loaded_value = wrap_stackframe_error(class, method, frame.load_local_float(index as u16))?; diff --git a/src/native_methods.rs b/src/native_methods.rs index 8b6e265..efd1faf 100644 --- a/src/native_methods.rs +++ b/src/native_methods.rs @@ -44,6 +44,24 @@ impl EntryPoint { struct JavaLangClass {} impl JavaLangClass { + + fn is_array(jvm: &mut JVM) -> Result { + let frame = { + let frame_index = jvm.stack_frames.len() - 1; + &mut jvm.stack_frames[frame_index] + }; + let this = frame.load_local_reference(0).unwrap(); + let class_class_index = jvm.heap_area.object_area.get_object_class_index(this); + + let component_type = jvm.heap_area.object_area.get_object_field( + this, + "componentType", + class_class_index, + &jvm.class_store, + )?; + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Boolean(component_type.expect_reference() == ObjectReference::NULL))) + } + pub fn get_primitive_class(jvm: &mut JVM) -> Result { let frame = { let frame_index = jvm.stack_frames.len() - 1; @@ -330,6 +348,81 @@ impl JavaLangDouble { } } +struct JavaLangObject {} + +impl JavaLangObject { + + fn get_class(jvm: &mut JVM) -> Result { + let frame = { + let frame_index = jvm.stack_frames.len() - 1; + &mut jvm.stack_frames[frame_index] + }; + let this = frame.load_local_reference(0).unwrap(); + + let class_reference = jvm.heap_area.object_area.get_reference_class_ref(this, &jvm.class_store); + + Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(class_reference))) + } + + fn hashcode(jvm: &mut JVM) -> Result { + let frame = { + let frame_index = jvm.stack_frames.len() - 1; + &mut jvm.stack_frames[frame_index] + }; + if frame.operand_stack.capacity() == 1 { + frame.operand_stack.grow(2); + frame.operand_stack.push(StackValue::Int(91)).unwrap(); + } else { + let new_hashcode_part = frame.operand_stack.pop_int(0).unwrap(); + let old_hashcode_part = frame.operand_stack.pop_int(0).unwrap(); + let combined_hashcode = old_hashcode_part.wrapping_mul(37).wrapping_add(new_hashcode_part); + frame.operand_stack.push(StackValue::Int(combined_hashcode)).unwrap(); + } + + let this = frame.load_local_reference(0).unwrap(); + let this_pointer = &this as *const _; + + return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(this_pointer as i32))) + + //let this_field_count = jvm.heap_area.object_area.get_object_field_count(this); + + //Ok(if this_field_count > frame.instruction_pointer as usize { + // let current_field = jvm.heap_area.object_area.get_object_field_at(this, frame.instruction_pointer as usize); + // let caller_frame = match current_field.value { + // FieldValue::Boolean(b) => { + // // TODO: Maybe load the class + // let (boolean_class_file, boolean_class_index) = jvm.class_store.get_class(&String::from("java/lang/Boolean")).unwrap(); + // StackFrame::new( + // boolean_class_file, + // boolean_class_index, + // boolean_class_file.resolve_method_index("hashCode", "(Z)I").unwrap(), + // &[StackValue::Boolean(b)] + // ) + // }, + // FieldValue::Byte(_) => todo!(), + // FieldValue::Char(_) => todo!(), + // FieldValue::Short(_) => todo!(), + // FieldValue::Int(_) => todo!(), + // FieldValue::Float(_) => todo!(), + // FieldValue::Reference(r) => { + // if jvm.heap_area.object_area.is_array_reference(r) { + + // } else { + + // } + // }, + // FieldValue::Double(_) => todo!(), + // FieldValue::Long(_) => todo!(), + // }; + + // JVMCallbackOperation::PushFrame(caller_frame) + //} else { + // let hashcode = frame.operand_stack.pop_int(0).unwrap(); + // JVMCallbackOperation::ReturnFrame(FieldValue::Int(hashcode)) + //}) + } +} + struct JavaLangRuntime {} impl JavaLangRuntime { @@ -1136,7 +1229,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul argument_types: Box::new([]), return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()}, }, - todo_call + JavaLangClass::is_array ), ( @@ -1299,7 +1392,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul argument_types: Box::new([]), return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Class"))}, }, - todo_call + JavaLangObject::get_class ), ( @@ -1309,7 +1402,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul argument_types: Box::new([]), return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int()}, }, - todo_call + JavaLangObject::hashcode ), ( @@ -3435,6 +3528,75 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul }, todo_call ), + + ( + "java/lang/Module", + "defineModule0", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + todo_call + ), + + ( + "java/lang/Module", + "addReads0", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + todo_call + ), + + ( + "java/lang/Module", + "addExports0", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + todo_call + ), + + ( + "java/lang/Module", + "addExportsToAll0", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())}, + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())}, + ]), + return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() }, + }, + todo_call + ), + + ( + "java/lang/Module", + "addExportsToAllUnnamed0", + MethodDescriptor { + argument_types: Box::new([ + AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())}, + 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 a18f82b..652680c 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -47,6 +47,14 @@ impl OperandStack { } } + pub fn capacity(&self) -> usize { + self.stack.len() + } + + pub fn grow(&mut self, new_size: usize) { + self.stack = vec![StackValue::Empty(); new_size].into_boxed_slice() + } + pub fn clear(&mut self) -> () { self.depth = 0 } @@ -408,6 +416,20 @@ impl StackFrame { } } + pub fn store_local_double(&mut self, index: u16, double: f64) -> Result<(), Error> { + let field0 = self.locals.get(index as usize); + let field1 = self.locals.get((index + 1) as usize); + + match (field0, field1) { + (Some(_), Some(_)) => { + self.locals[index as usize] = StackValue::Double0(double); + self.locals[(index + 1) as usize] = StackValue::Double1(); + Ok(()) + }, + _ => Err(Error::LocalError(format!("Tried to set local at indices {} and {} when max_locals is {}.", index, index+1, self.locals.len()))) + } + } + pub fn load_local_int(&self, index: u16) -> Result { let local = self.locals[index as usize]; match local {