488 lines
28 KiB
Rust
488 lines
28 KiB
Rust
use core::fmt::Debug;
|
|
|
|
pub struct Bytecode {
|
|
pub bytes: Box<[u8]>
|
|
}
|
|
|
|
impl Bytecode {
|
|
|
|
pub fn next_instruction(&self, offset: usize) -> (Instruction, usize) {
|
|
let opcode = self.bytes[offset];
|
|
|
|
match opcode {
|
|
0x00 => (Instruction::NoOperation(), 1),
|
|
0x01 => (Instruction::PushNull(), 1),
|
|
0x02 => (Instruction::PushConstIntM1(), 1),
|
|
0x03 => (Instruction::PushConstInt0(), 1),
|
|
0x04 => (Instruction::PushConstInt1(), 1),
|
|
0x05 => (Instruction::PushConstInt2(), 1),
|
|
0x06 => (Instruction::PushConstInt3(), 1),
|
|
0x07 => (Instruction::PushConstInt4(), 1),
|
|
0x08 => (Instruction::PushConstInt5(), 1),
|
|
0x09 => (Instruction::PushConstLong0(), 1),
|
|
0x0A => (Instruction::PushConstLong1(), 1),
|
|
0x0B => (Instruction::PushConstFloat0(), 1),
|
|
0x0C => (Instruction::PushConstFloat1(), 1),
|
|
0x0D => (Instruction::PushConstFloat2(), 1),
|
|
0x0E => (Instruction::PushConstDouble0(), 1),
|
|
0x0F => (Instruction::PushConstDouble1(), 1),
|
|
|
|
0x10 => (Instruction::LoadByteImmediate(i8::from_be_bytes([self.bytes[offset+1]])), 2),
|
|
0x11 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::LoadShortImmediate(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2),
|
|
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),
|
|
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),
|
|
0x1C => (Instruction::LoadLocalInt2(), 1),
|
|
0x1D => (Instruction::LoadLocalInt3(), 1),
|
|
0x1E => (Instruction::LoadLocalLong0(), 1),
|
|
0x1F => (Instruction::LoadLocalLong1(), 1),
|
|
0x20 => (Instruction::LoadLocalLong2(), 1),
|
|
0x21 => (Instruction::LoadLocalLong3(), 1),
|
|
0x22 => (Instruction::LoadLocalFloat0(), 1),
|
|
0x23 => (Instruction::LoadLocalFloat1(), 1),
|
|
0x24 => (Instruction::LoadLocalFloat2(), 1),
|
|
0x25 => (Instruction::LoadLocalFloat3(), 1),
|
|
0x26 => (Instruction::LoadLocalDouble0(), 1),
|
|
0x27 => (Instruction::LoadLocalDouble1(), 1),
|
|
0x28 => (Instruction::LoadLocalDouble2(), 1),
|
|
0x29 => (Instruction::LoadLocalDouble3(), 1),
|
|
0x2A => (Instruction::LoadLocalReference0(), 1),
|
|
0x2B => (Instruction::LoadLocalReference1(), 1),
|
|
0x2C => (Instruction::LoadLocalReference2(), 1),
|
|
0x2D => (Instruction::LoadLocalReference3(), 1),
|
|
|
|
0x32 => (Instruction::ArrayElement(), 1),
|
|
0x33 => (Instruction::LoadFromBArray(), 1),
|
|
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),
|
|
0x3D => (Instruction::StoreLocalInt2(), 1),
|
|
0x3E => (Instruction::StoreLocalInt3(), 1),
|
|
0x3F => (Instruction::StoreLocalLong0(), 1),
|
|
0x40 => (Instruction::StoreLocalLong1(), 1),
|
|
0x41 => (Instruction::StoreLocalLong2(), 1),
|
|
0x42 => (Instruction::StoreLocalLong3(), 1),
|
|
0x4B => (Instruction::StoreLocalReference0(), 1),
|
|
0x4C => (Instruction::StoreLocalReference1(), 1),
|
|
0x4D => (Instruction::StoreLocalReference2(), 1),
|
|
0x4E => (Instruction::StoreLocalReference3(), 1),
|
|
|
|
0x4F => (Instruction::StoreIntoIArray(), 1),
|
|
0x53 => (Instruction::StoreIntoRArray(), 1),
|
|
0x54 => (Instruction::StoreIntoBArray(), 1),
|
|
0x55 => (Instruction::StoreIntoCArray(), 1),
|
|
|
|
0x57 => (Instruction::Pop(), 1),
|
|
0x59 => (Instruction::Duplicate(), 1),
|
|
0x5A => (Instruction::DuplicateInsertDown(), 1),
|
|
0x5C => (Instruction::DuplicateComputationalValue(), 1),
|
|
|
|
0x60 => (Instruction::AddInt(), 1),
|
|
0x61 => (Instruction::AddLong(), 1),
|
|
0x63 => (Instruction::AddDouble(), 1),
|
|
0x64 => (Instruction::SubtractInt(), 1),
|
|
0x65 => (Instruction::SubtractLong(), 1),
|
|
0x68 => (Instruction::MultiplyInt(), 1),
|
|
0x69 => (Instruction::MultiplyLong(), 1),
|
|
0x6A => (Instruction::MultiplyFloat(), 1),
|
|
0x6C => (Instruction::DivideInt(), 1),
|
|
0x6D => (Instruction::DivideLong(), 1),
|
|
0x6E => (Instruction::DivideFloat(), 1),
|
|
0x6F => (Instruction::DivideDouble(), 1),
|
|
|
|
0x70 => (Instruction::ModuloInt(), 1),
|
|
0x74 => (Instruction::NegateInt(), 1),
|
|
0x75 => (Instruction::NegateLong(), 1),
|
|
0x78 => (Instruction::ArithmeticShiftIntLeft(), 1),
|
|
0x79 => (Instruction::ArithmeticShiftLongLeft(), 1),
|
|
0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
|
|
0x7B => (Instruction::ArithmeticShiftLongRight(), 1),
|
|
0x7C => (Instruction::LogicalShiftIntRight(), 1),
|
|
0x7D => (Instruction::LogicalShiftLongRight(), 1),
|
|
0x7E => (Instruction::AndInt(), 1),
|
|
0x7F => (Instruction::AndLong(), 1),
|
|
|
|
0x80 => (Instruction::OrInt(), 1),
|
|
0x82 => (Instruction::XorInt(), 1),
|
|
0x83 => (Instruction::XorLong(), 1),
|
|
0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3),
|
|
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)
|
|
}
|
|
0x9A => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchNonZero(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0x9B => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchNegative(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0x9C => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchNonNegative(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0x9D => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchPositive(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0x9E => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchNonPositive(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
|
|
0x9F => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchIntEquality(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0xA0 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchIntInequality(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0xA1 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchIntLessThan(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0xA2 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchIntGreaterEquals(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0xA3 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchIntGreaterThan(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0xA4 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchIntLessEquals(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0xA5 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchReferenceEquality(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0xA6 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(Instruction::BranchReferenceInequality(i16::from_be_bytes(bytes)), 3)
|
|
}
|
|
0xA7 => {
|
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
|
(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]];
|
|
let default = i32::from_be_bytes(default_bytes);
|
|
|
|
let npairs_bytes = [self.bytes[offset+padding+5], self.bytes[offset+padding+6], self.bytes[offset+padding+7], self.bytes[offset+padding+8]];
|
|
let npairs = i32::from_be_bytes(npairs_bytes);
|
|
|
|
let mut pairs_vec = Vec::with_capacity(npairs as usize);
|
|
for i in 0..npairs as usize {
|
|
let match_bytes = [self.bytes[offset+padding+8*(1+i)+1], self.bytes[offset+padding+8*(1+i)+2], self.bytes[offset+padding+8*(1+i)+3], self.bytes[offset+padding+8*(1+i)+4]];
|
|
let offset_bytes = [self.bytes[offset+padding+8*(1+i)+5], self.bytes[offset+padding+8*(1+i)+6], self.bytes[offset+padding+8*(1+i)+7], self.bytes[offset+padding+8*(1+i)+8]];
|
|
|
|
pairs_vec.push((i32::from_be_bytes(match_bytes), i32::from_be_bytes(offset_bytes)));
|
|
}
|
|
|
|
(Instruction::LookupSwitch(default, pairs_vec.into()), 1 + padding + 4 + 4 + npairs as usize * 8)
|
|
}
|
|
0xAC => (Instruction::ReturnInt(), 1),
|
|
0xAD => (Instruction::ReturnLong(), 1),
|
|
0xAE => (Instruction::ReturnFloat(), 1),
|
|
0xAF => (Instruction::ReturnDouble(), 1),
|
|
|
|
0xB0 => (Instruction::ReturnReference(), 1),
|
|
0xB1 => (Instruction::ReturnVoid(), 1),
|
|
0xB2 => (Instruction::GetStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
|
0xB3 => (Instruction::PutStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
|
0xB4 => (Instruction::GetField((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
|
0xB5 => (Instruction::PutField((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
|
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), 5), // TODO: Figure out the additional arguments
|
|
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),
|
|
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
|
0xBE => (Instruction::ArrayLength(), 1),
|
|
0xBF => (Instruction::ThrowException(), 1),
|
|
|
|
0xC0 => (Instruction::CheckCast((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
|
0xC1 => (Instruction::InstanceOf((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
|
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)
|
|
}
|
|
}
|
|
|
|
pub fn instructions(&self) -> Box<[Instruction]> {
|
|
let mut v = Vec::with_capacity(self.bytes.len());
|
|
|
|
let mut i = 0;
|
|
while i < self.bytes.len() {
|
|
|
|
let (instruction, offset) = self.next_instruction(i);
|
|
|
|
v.push(instruction);
|
|
i += offset;
|
|
}
|
|
|
|
v.into_boxed_slice()
|
|
}
|
|
}
|
|
|
|
impl Debug for Bytecode {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
f.debug_list()
|
|
.entries(self.instructions())
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
#[repr(u8)]
|
|
pub enum Instruction {
|
|
NoOperation() = 0x00, // No-Operation
|
|
PushNull() = 0x01, // ..., arrayref, index, value
|
|
PushConstIntM1() = 0x02, // Push -1
|
|
PushConstInt0() = 0x03, // Push 0
|
|
PushConstInt1() = 0x04, // Push 1
|
|
PushConstInt2() = 0x05, // Push 2
|
|
PushConstInt3() = 0x06, // Push 3
|
|
PushConstInt4() = 0x07, // Push 4
|
|
PushConstInt5() = 0x08, // Push 5
|
|
PushConstLong0() = 0x09, // Push 0
|
|
PushConstLong1() = 0x0A, // Push 1
|
|
PushConstFloat0() = 0x0B, // Push 0.0f
|
|
PushConstFloat1() = 0x0C, // Push 1.0f
|
|
PushConstFloat2() = 0x0D, // Push 2.0f
|
|
PushConstDouble0() = 0x0E, // Push 0.0
|
|
PushConstDouble1() = 0x0F, // Push 1.0
|
|
|
|
LoadByteImmediate(i8) = 0x10, // push immediate short
|
|
LoadShortImmediate(i16) = 0x11, // push immediate short
|
|
LoadConstant(u8) = 0x12, // Push from constant pool
|
|
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
|
|
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
|
|
LoadLocalInt2() = 0x1C, // Load int from local variable
|
|
LoadLocalInt3() = 0x1D, // Load int from local variable
|
|
LoadLocalLong0() = 0x1E, // load long from local variable
|
|
LoadLocalLong1() = 0x1F, // load long from local variable
|
|
LoadLocalLong2() = 0x20, // load long from local variable
|
|
LoadLocalLong3() = 0x21, // load long from local variable
|
|
|
|
LoadLocalFloat0() = 0x22, // Load local double variable reference onto stack
|
|
LoadLocalFloat1() = 0x23, // Load local double variable reference onto stack
|
|
LoadLocalFloat2() = 0x24, // Load local double variable reference onto stack
|
|
LoadLocalFloat3() = 0x25, // Load local double variable reference onto stack
|
|
LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack
|
|
LoadLocalDouble1() = 0x27, // Load local double variable reference onto stack
|
|
LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack
|
|
LoadLocalDouble3() = 0x29, // Load local double variable reference onto stack
|
|
LoadLocalReference0() = 0x2A, // Load local reference variable reference onto stack
|
|
LoadLocalReference1() = 0x2B, // Load local reference variable reference onto stack
|
|
LoadLocalReference2() = 0x2C, // Load local reference variable reference onto stack
|
|
LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack
|
|
|
|
ArrayElement() = 0x32, // load element from array
|
|
LoadFromBArray() = 0x33, // store into byte array
|
|
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
|
|
StoreLocalInt2() = 0x3D, // store int into local variable
|
|
StoreLocalInt3() = 0x3E, // store int into local variable
|
|
StoreLocalLong0() = 0x3F, // store int into local variable
|
|
StoreLocalLong1() = 0x40, // store int into local variable
|
|
StoreLocalLong2() = 0x41, // store int into local variable
|
|
StoreLocalLong3() = 0x42, // store int into local variable
|
|
StoreLocalReference0() = 0x4B, // store reference into local variable
|
|
StoreLocalReference1() = 0x4C, // store reference into local variable
|
|
StoreLocalReference2() = 0x4D, // store reference into local variable
|
|
StoreLocalReference3() = 0x4E, // store reference into local variable
|
|
|
|
StoreIntoIArray() = 0x4F, // store value into integer array
|
|
StoreIntoRArray() = 0x53, // store value into reference array
|
|
StoreIntoBArray() = 0x54, // store value into byte or boolean array
|
|
StoreIntoCArray() = 0x55, // store value into char array
|
|
Pop() = 0x57, // Pop top stack value
|
|
Duplicate() = 0x59, // duplicate top stack value
|
|
DuplicateInsertDown() = 0x5A, // duplicate top stack value and insert two low
|
|
DuplicateComputationalValue() = 0x5C, // duplicate top computational value
|
|
|
|
AddInt() = 0x60, // int addition
|
|
AddLong() = 0x61, // long addition
|
|
AddDouble() = 0x63, // double addition
|
|
SubtractInt() = 0x64, // int subtraction
|
|
SubtractLong() = 0x65, // long subtraction
|
|
MultiplyInt() = 0x68, // int multiplication
|
|
MultiplyLong() = 0x69, // long multiplication
|
|
MultiplyFloat() = 0x6A, // float multiplication
|
|
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
|
|
NegateLong() = 0x75, // arithmetic negation
|
|
ArithmeticShiftIntLeft() = 0x78, // shift int left, preserve sign
|
|
ArithmeticShiftLongLeft() = 0x79, // shift long left, preserve sign
|
|
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
|
|
|
|
OrInt() = 0x80, // value, value => or
|
|
XorInt() = 0x82, // value, value => xor
|
|
XorLong() = 0x83, // value, value => xor
|
|
IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8
|
|
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
|
|
BranchNonNegative(i16) = 0x9C, // branch if value <= 0
|
|
BranchPositive(i16) = 0x9D, // branch if value > 0
|
|
BranchNonPositive(i16) = 0x9E, // branch if value >= 0
|
|
|
|
BranchIntEquality(i16) = 0x9F,
|
|
BranchIntInequality(i16) = 0xA0,
|
|
BranchIntLessThan(i16) = 0xA1,
|
|
BranchIntGreaterEquals(i16) = 0xA2,
|
|
BranchIntGreaterThan(i16) = 0xA3,
|
|
BranchIntLessEquals(i16) = 0xA4,
|
|
BranchReferenceEquality(i16) = 0xA5,
|
|
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
|
|
ReturnInt() = 0xAC, // return integer from function
|
|
ReturnLong() = 0xAD, // return long from function
|
|
ReturnFloat() = 0xAE, // return float from function
|
|
ReturnDouble() = 0xAF, // return double from function
|
|
|
|
ReturnReference() = 0xB0, // return top-ref from current function
|
|
ReturnVoid() = 0xB1, // return void from function
|
|
GetStatic(u16) = 0xB2, // get static field from class
|
|
PutStatic(u16) = 0xB3, // set static field on class
|
|
GetField(u16) = 0xB4, // get field from class
|
|
PutField(u16) = 0xB5, // set field to a value
|
|
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
|
|
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
|
ArrayLength() = 0xBE, // Get length from array reference
|
|
ThrowException() = 0xBF, // throw the exception
|
|
|
|
CheckCast(u16) = 0xC0, // throw exception on fail
|
|
InstanceOf(u16) = 0xC1, // push integer result for success
|
|
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),
|
|
}
|