diff --git a/src/bytecode.rs b/src/bytecode.rs index 5082bf2..c720810 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -34,7 +34,6 @@ impl Bytecode { 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), - 0x15 => (Instruction::LoadLocalInt(self.bytes[offset+1]), 2), 0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2), 0x1A => (Instruction::LoadLocalInt0(), 1), 0x1B => (Instruction::LoadLocalInt1(), 1), @@ -81,10 +80,8 @@ impl Bytecode { 0x7A => (Instruction::ArithmeticShiftIntRight(), 1), 0x7C => (Instruction::LogicalShiftIntRight(), 1), - 0x7E => (Instruction::AndInt(), 1), 0x80 => (Instruction::OrInt(), 1), - 0x82 => (Instruction::XorInt(), 1), 0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3), 0x95 => (Instruction::CompareFloatL(), 1), @@ -151,33 +148,6 @@ impl Bytecode { (Instruction::BranchAlways(i16::from_be_bytes(bytes)), 3) } - 0xAA => { - let padding = 4 - (offset % 4) - 1; - let default_bytes = [self.bytes[offset+padding+1], self.bytes[offset+padding+2], self.bytes[offset+padding+3], self.bytes[offset+padding+4]]; - let default = i32::from_be_bytes(default_bytes); - - let low_bytes = [self.bytes[offset+padding+5], self.bytes[offset+padding+6], self.bytes[offset+padding+7], self.bytes[offset+padding+8]]; - let low = i32::from_be_bytes(low_bytes); - - let high_bytes = [self.bytes[offset+padding+9], self.bytes[offset+padding+10], self.bytes[offset+padding+11], self.bytes[offset+padding+12]]; - let high = i32::from_be_bytes(high_bytes); - - // TODO: Throw - assert!(low <= high); - - let offsets_count = (high - low + 1) as usize; - let mut offsets_vec = Vec::with_capacity(offsets_count); - - for i in 0..offsets_count { - let offset_bytes = [self.bytes[offset+padding+12+(i*4)+1], self.bytes[offset+padding+12+(i*4)+2], self.bytes[offset+padding+12+(i*4)+3], self.bytes[offset+padding+12+(i*4)+4]]; - let offset = i32::from_be_bytes(offset_bytes); - - offsets_vec.push(offset); - } - - (Instruction::TableSwitch(default, low, high, offsets_vec.into()), 1 + padding + 12 + 4 * offsets_count) - } - 0xAB => { let padding = 4 - (offset % 4) - 1; let default_bytes = [self.bytes[offset+padding+1], self.bytes[offset+padding+2], self.bytes[offset+padding+3], self.bytes[offset+padding+4]]; @@ -207,7 +177,6 @@ impl Bytecode { 0xB6 => (Instruction::InvokeVirtual((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xB7 => (Instruction::InvokeSpecial((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xB8 => (Instruction::InvokeStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), - 0xB9 => (Instruction::InvokeInterface((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xBA => (Instruction::InvokeDynamic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16, (self.bytes[offset+3] as u16) << 8 | self.bytes[offset+4] as u16), 5), 0xBB => (Instruction::NewObject((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xBC => (Instruction::NewPrimitiveArray(self.bytes[offset+1]), 2), @@ -279,7 +248,6 @@ pub enum Instruction { 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 - LoadLocalInt(u8) = 0x15, // Load int 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 @@ -326,10 +294,8 @@ pub enum Instruction { ArithmeticShiftIntRight() = 0x7A, // shift int LogicalShiftIntRight() = 0x7C, // shift int right with zero extension - AndInt() = 0x7E, // bitwise and OrInt() = 0x80, // value, value => or - XorInt() = 0x82, // value, value => xor IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8 CompareFloatL() = 0x95, // compare float, push -1 if one is NaN @@ -351,8 +317,7 @@ pub enum Instruction { BranchReferenceInequality(i16) = 0xA6, BranchAlways(i16) = 0xA7, // branch if true - TableSwitch(i32, i32, i32, Box<[i32]>) = 0xAA, // jump based on indexed range - LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // jump based on switch value + LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // offset based on switch value ReturnInt() = 0xAC, // return integer from function ReturnReference() = 0xB0, // return top-ref from current function @@ -364,7 +329,6 @@ pub enum Instruction { InvokeVirtual(u16) = 0xB6, // invoke function on a class InvokeSpecial(u16) = 0xB7, // invoke instance method InvokeStatic(u16) = 0xB8, // invoke static function - InvokeInterface(u16) = 0xB9, // invoke interface function InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference NewPrimitiveArray(u8) = 0xBC, // make a primitive array diff --git a/src/classfile.rs b/src/classfile.rs index a2dd4b6..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, ConstantInterfaceMethodRefInfo, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo }; +use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo }; #[derive(Debug)] pub enum Error { @@ -206,17 +206,6 @@ impl JavaClassFile { return pool_entry(&self.constant_pool, index); } - pub fn pool_interfacemethodref_entry(&self, index: u16) -> Result<&ConstantInterfaceMethodRefInfo, Error> { - let pool_entry = self.pool_entry(index)?; - - let methodref_entry = match pool_entry { - ConstantPoolInfo::InterfaceMethodRef(data) => data, - _ => unreachable!(), - }; - - return Ok(methodref_entry); - } - pub fn pool_methodref_entry(&self, index: u16) -> Result<&ConstantMethodRefInfo, Error> { let pool_entry = self.pool_entry(index)?; @@ -340,19 +329,6 @@ impl JavaClassFile { Ok(class_name) } - pub fn gather_interfacemethodref(&self, index: u16) -> Result<(&String, &String, &String), Error> { - let methodref = self.pool_interfacemethodref_entry(index)?; - let class_entry = self.pool_class_entry(methodref.class_index)?; - let class_name_entry = self.pool_utf8_entry(class_entry.name_index)?; - let name_and_type_entry = self.pool_nameandtype_entry(methodref.name_and_type_index)?; - - let class_name = &class_name_entry.utf8; - let method_name = &self.pool_utf8_entry(name_and_type_entry.name_index)?.utf8; - let method_descriptor = &self.pool_utf8_entry(name_and_type_entry.descriptor_index)?.utf8; - - return Ok((class_name, method_name, method_descriptor)); - } - pub fn gather_methodref(&self, index: u16) -> Result<(&String, &String, &String), Error> { let methodref = self.pool_methodref_entry(index)?; let class_entry = self.pool_class_entry(methodref.class_index)?; @@ -910,13 +886,6 @@ impl AbstractTypeDescription { return Ok((offset, AbstractTypeDescription { array_level, kind })) } - - pub fn for_class_name(name: &str) -> Self { - AbstractTypeDescription { - array_level: 0, - kind: AbstractTypeKind::Classname(name.to_string()), - } - } } #[derive(Debug, Eq, PartialEq)] diff --git a/src/heap_area.rs b/src/heap_area.rs index cc2785e..f8da3a7 100644 --- a/src/heap_area.rs +++ b/src/heap_area.rs @@ -256,7 +256,6 @@ impl ObjectArea { match self.get_entry(reference) { CompartmentEntry::Object(o) => class_store.get_class_objectref_from_index(o.class_index), CompartmentEntry::ReferenceArray(a) => a.class_ref, - CompartmentEntry::ByteArray(a) => a.class_ref, _ => unreachable!(), } } diff --git a/src/jvm.rs b/src/jvm.rs index bb3f02f..dc6ee7b 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -701,14 +701,7 @@ impl JVM { let element = self.heap_area.object_area.get_array_element(array_reference, element_index); wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(element))?; - } - - Instruction::AndInt() => { - 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))?; - - wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 & value_2)))?; - } + }, Instruction::BranchAlways(branch_offset) => { frame.instruction_pointer -= offset as u32; @@ -841,22 +834,16 @@ impl JVM { Instruction::CheckCast(classref_index) => { // TODO: Class loading checks let class_name = class.gather_class(classref_index)?; + 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); + let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store); + let class_description = AbstractTypeDescription::parse_full(native_class_description)?; + let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store); + let object_description = AbstractTypeDescription::parse_full(native_class_name)?; - let instruction_result = if class_name == native_class_name { - 1 - } else { - 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); - let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store); - let class_description = AbstractTypeDescription::parse_full(native_class_description)?; - - let object_description = AbstractTypeDescription::parse_full(native_class_name)?; - if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 } - }; - - if instruction_result == 0 { + if ! self.class_store.are_types_compatible(&object_description, &class_description) { // TODO: Throw Exception return Err(Error::RunTimeError(format!("Trying to cast an object of type {native_class_name} to {class_name}"))) } @@ -985,81 +972,20 @@ impl JVM { Instruction::InstanceOf(classref_index) => { // TODO: Class loading checks let class_name = class.gather_class(classref_index)?; + 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); + let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store); + let class_description = AbstractTypeDescription::parse_full(native_class_description)?; + let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store); + let object_description = AbstractTypeDescription::parse_full(native_class_name)?; - let instruction_result = if class_name == native_class_name { - 1 - } else { - 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); - let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store); - let class_description = AbstractTypeDescription::parse_full(native_class_description)?; - - let object_description = AbstractTypeDescription::parse_full(native_class_name)?; - if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 } - }; - + let instruction_result = if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 }; wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(instruction_result)))?; } - Instruction::InvokeInterface(methodref_index) => { - let (supplied_interface_name, supplied_method_name, supplied_descriptor_string) = class.gather_interfacemethodref(methodref_index)?; - - if ! self.class_store.have_class(supplied_interface_name) { - frame.instruction_pointer -= offset as u32; - return Ok(JVMCallbackOperation::LoadClass(supplied_interface_name.to_string())); - } - if ! self.class_store.was_init(supplied_interface_name).unwrap() { - frame.instruction_pointer -= offset as u32; - return Ok(JVMCallbackOperation::InitClass(supplied_interface_name.to_string())); - } - - let target_interface_class_index = self.class_store.class_idx_from_name(supplied_interface_name).unwrap(); - - let parsed_expected_descriptor: MethodDescriptor = MethodDescriptor::try_from(supplied_descriptor_string)?; - let (class_index, method_index, method_info) = match ClassMethodIterator::new(target_interface_class_index, &self.class_store) - .filter(|(_cid, _mid, minfo)| minfo.name == *supplied_method_name) - .filter(|(_cid, _mid, minfo)| minfo.descriptor == parsed_expected_descriptor) - .next() { - Some(m) => m, - None => { - // TODO: Throw exception - return Err(Error::RunTimeError(format!("InvokeInterface: Failed to find requested method '{}' with descriptor '{}' in the class '{}'", supplied_method_name, supplied_descriptor_string, supplied_interface_name))); - } - }; - - let mut arguments = VecDeque::new(); - fill_arguments(class, method, &mut arguments, &method_info.descriptor.argument_types, &mut frame.operand_stack)?; - let this_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; - arguments.push_front(StackValue::Reference(this_object)); - - let object_class_index = self.heap_area.object_area.get_object_class_index(this_object); - let object_class_file = self.class_store.class_file_from_idx(object_class_index).unwrap(); - let object_class_name = object_class_file.get_classname().unwrap(); - - if object_class_name != supplied_interface_name { - let object_class_description = AbstractTypeDescription::for_class_name(object_class_name); - let supplied_interface_description = AbstractTypeDescription::for_class_name(supplied_interface_name); - - if ! self.class_store.are_types_compatible(&object_class_description, &supplied_interface_description) { - return Err(Error::RunTimeError(format!("Tried to invoke interface method : '{supplied_interface_name}.{supplied_method_name}' on object of type '{object_class_name}'"))); - } - } - - // TODO: I hate this, now I have to find the 'implementation' of a function - let interface_class_file = self.class_store.class_file_from_idx(target_interface_class_index).unwrap(); - let interface_frame = StackFrame::new( - interface_class_file, - target_interface_class_index, - method_index as u16, - arguments.make_contiguous() - ); - - return Ok(JVMCallbackOperation::PushFrame(interface_frame)); - } - Instruction::InvokeSpecial(methodref_index) => { // No instance-based dispatch let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?; @@ -1397,9 +1323,6 @@ impl JVM { load_local_float(class, method, frame, 3)?; } - Instruction::LoadLocalInt(index) => { - load_local_int(class, method, frame, index as usize)?; - } Instruction::LoadLocalInt0() => { load_local_int(class, method, frame, 0)?; } @@ -1814,26 +1737,6 @@ impl JVM { wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Reference(reference)))?; } - Instruction::TableSwitch(default, low, high, offsets) => { - let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; - - frame.instruction_pointer -= offset as u32; - if index < low || index > high { - frame.instruction_pointer = if default < 0 { frame.instruction_pointer - default.abs() as u32} else { frame.instruction_pointer + default.abs() as u32}; - } else { - let offset_index = index - low; - let jump_offset = offsets[offset_index as usize]; - frame.instruction_pointer = if jump_offset < 0 { frame.instruction_pointer - jump_offset.abs() as u32} else { frame.instruction_pointer + jump_offset.abs() as u32}; - } - } - - Instruction::XorInt() => { - 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))?; - - wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 ^ value_2)))?; - } - _ => { return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction))) },