From d7d159d11535f53b85544fb229773d450398ba77 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Tue, 10 Sep 2024 23:28:31 +0200 Subject: [PATCH] Tableswitch implementation --- src/bytecode.rs | 36 +++++++++++++++++++++++++++++++++++- src/jvm.rs | 32 +++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index c720810..5fb1582 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -34,6 +34,7 @@ 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), @@ -80,8 +81,10 @@ 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), @@ -148,6 +151,33 @@ 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]]; @@ -248,6 +278,7 @@ 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 @@ -294,8 +325,10 @@ 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 @@ -317,7 +350,8 @@ pub enum Instruction { BranchReferenceInequality(i16) = 0xA6, BranchAlways(i16) = 0xA7, // branch if true - LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // offset based on switch value + TableSwitch(i32, i32, i32, Box<[i32]>) = 0xAA, // jump based on indexed range + LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // jump based on switch value ReturnInt() = 0xAC, // return integer from function ReturnReference() = 0xB0, // return top-ref from current function diff --git a/src/jvm.rs b/src/jvm.rs index dc6ee7b..03f8a18 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -701,7 +701,14 @@ 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; @@ -1323,6 +1330,9 @@ 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)?; } @@ -1737,6 +1747,26 @@ 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))) },