Tableswitch implementation
This commit is contained in:
parent
b053461e74
commit
d7d159d115
2 changed files with 66 additions and 2 deletions
|
@ -34,6 +34,7 @@ impl Bytecode {
|
||||||
0x13 => (Instruction::LoadCostantWide((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),
|
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),
|
0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2),
|
||||||
0x1A => (Instruction::LoadLocalInt0(), 1),
|
0x1A => (Instruction::LoadLocalInt0(), 1),
|
||||||
0x1B => (Instruction::LoadLocalInt1(), 1),
|
0x1B => (Instruction::LoadLocalInt1(), 1),
|
||||||
|
@ -80,8 +81,10 @@ impl Bytecode {
|
||||||
|
|
||||||
0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
|
0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
|
||||||
0x7C => (Instruction::LogicalShiftIntRight(), 1),
|
0x7C => (Instruction::LogicalShiftIntRight(), 1),
|
||||||
|
0x7E => (Instruction::AndInt(), 1),
|
||||||
|
|
||||||
0x80 => (Instruction::OrInt(), 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),
|
0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3),
|
||||||
|
|
||||||
0x95 => (Instruction::CompareFloatL(), 1),
|
0x95 => (Instruction::CompareFloatL(), 1),
|
||||||
|
@ -148,6 +151,33 @@ impl Bytecode {
|
||||||
(Instruction::BranchAlways(i16::from_be_bytes(bytes)), 3)
|
(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 => {
|
0xAB => {
|
||||||
let padding = 4 - (offset % 4) - 1;
|
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_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
|
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
|
||||||
// double or long or whatever
|
// double or long or whatever
|
||||||
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
|
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
|
LoadLocalReference(u8) = 0x19, // Load reference from indexed local variable
|
||||||
LoadLocalInt0() = 0x1A, // Load int from local variable
|
LoadLocalInt0() = 0x1A, // Load int from local variable
|
||||||
LoadLocalInt1() = 0x1B, // Load int from local variable
|
LoadLocalInt1() = 0x1B, // Load int from local variable
|
||||||
|
@ -294,8 +325,10 @@ pub enum Instruction {
|
||||||
|
|
||||||
ArithmeticShiftIntRight() = 0x7A, // shift int
|
ArithmeticShiftIntRight() = 0x7A, // shift int
|
||||||
LogicalShiftIntRight() = 0x7C, // shift int right with zero extension
|
LogicalShiftIntRight() = 0x7C, // shift int right with zero extension
|
||||||
|
AndInt() = 0x7E, // bitwise and
|
||||||
|
|
||||||
OrInt() = 0x80, // value, value => or
|
OrInt() = 0x80, // value, value => or
|
||||||
|
XorInt() = 0x82, // value, value => xor
|
||||||
IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8
|
IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8
|
||||||
|
|
||||||
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
|
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
|
||||||
|
@ -317,7 +350,8 @@ pub enum Instruction {
|
||||||
BranchReferenceInequality(i16) = 0xA6,
|
BranchReferenceInequality(i16) = 0xA6,
|
||||||
|
|
||||||
BranchAlways(i16) = 0xA7, // branch if true
|
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
|
ReturnInt() = 0xAC, // return integer from function
|
||||||
|
|
||||||
ReturnReference() = 0xB0, // return top-ref from current function
|
ReturnReference() = 0xB0, // return top-ref from current function
|
||||||
|
|
32
src/jvm.rs
32
src/jvm.rs
|
@ -701,7 +701,14 @@ impl JVM {
|
||||||
let element = self.heap_area.object_area.get_array_element(array_reference, element_index);
|
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))?;
|
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) => {
|
Instruction::BranchAlways(branch_offset) => {
|
||||||
frame.instruction_pointer -= offset as u32;
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
@ -1323,6 +1330,9 @@ impl JVM {
|
||||||
load_local_float(class, method, frame, 3)?;
|
load_local_float(class, method, frame, 3)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::LoadLocalInt(index) => {
|
||||||
|
load_local_int(class, method, frame, index as usize)?;
|
||||||
|
}
|
||||||
Instruction::LoadLocalInt0() => {
|
Instruction::LoadLocalInt0() => {
|
||||||
load_local_int(class, method, frame, 0)?;
|
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)))?;
|
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)))
|
return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction)))
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue