use crate::ion::IonReader; use crate::runtime::ByteCode; macro_rules! print_op { ($iter:expr, $pc:expr, $fmt:literal $(, $vars:expr ),*) => { let end = $iter.pc(); print!("{:08X} ",$ pc); let mut len = 0; for b in &$iter.bytecode()[$pc..end] { if len > 0 && len % 16 == 0 { println!(concat!(" ; ", $fmt), $($vars),*); print!(" "); } print!("{:02X} ", b); len += 1; } if len <= 16 { for _ in len..16 { print!(" "); } print!(concat!(" ; ", $fmt), $($vars),*); } println!(); }; } pub fn print_disassembly(bytecode: &ByteCode) { let mut iter = ByteCodeIter::new(bytecode); while let Some(op) = iter.next_byte() { let pc = iter.pc() - 1; match op { 0x01 => { // OpType::Jump let target = iter.next_u32(); print_op!(iter, pc, "JMP {:08X}", target); println!(); }, 0x02 => { // OpType::Dup print_op!(iter, pc, "DUP"); }, 0x03 => { // OpType::Dup2 print_op!(iter, pc, "DUP2"); }, 0x04 => { // OpType::SwapPop print_op!(iter, pc, "SWAPPOP"); }, 0x05 => { // OpType::Invoke let function_id = iter.next_varuint(); print_op!(iter, pc, "CALL {:08X}", function_id); }, 0x09 => { // OpType::InvokeDynamic print_op!(iter, pc, "INVOKEDYNAMIC"); }, 0x06 => { // OpType::InvokeGenerator let function_id = iter.next_varuint(); print_op!(iter, pc, "GEN {:08X}", function_id); }, 0x07 => { // OpType::Yield print_op!(iter, pc, "YIELD"); }, 0x08 => { // OpType::Return print_op!(iter, pc, "RET"); println!(); }, 0x10 => { // OpType::Push let buf = &iter.bytecode()[pc+1..]; let mut reader = IonReader::new(buf.iter().copied(), 0); reader.next_value(); iter.skip(reader.offset()); print_op!(iter, pc, "PUSH"); }, 0x11 => { // OpCode::TypePop print_op!(iter, pc, "POP"); }, 0x12 => { // OpCode::TypeLoad let varid = iter.next_varuint(); print_op!(iter, pc, "LOAD {:02x}", varid); }, 0x13 => { // OpCode::TypeStore let varid = iter.next_varuint(); print_op!(iter, pc, "STORE {:02x}", varid); }, 0x14 => { // OpCode::TypeLength let varid = iter.next_varuint(); print_op!(iter, pc, "LEN {:02x}", varid); }, 0x15 => todo!(), // OpCode::BytesAppend 0x16 => todo!(), // OpCode::ListAppend 0x17 => todo!(), // OpCode::ListLoad 0x18 => todo!(), // OpCode::FieldAppend 0x19 => { // OpCode::Iterate print_op!(iter, pc, "ITER"); }, 0x1A => { // OpCode::Next print_op!(iter, pc, "NEXT"); }, 0x1B => { // OpCode::StepIn print_op!(iter, pc, "STEPIN"); }, 0x1C => { // OpCode::StepOut print_op!(iter, pc, "STEPOUT"); }, 0x1D => { // OpCode::LoadValue print_op!(iter, pc, "VALUE"); }, 0x1E => { // OpCode::StructField print_op!(iter, pc, "FIELD"); }, 0x21 => todo!(), // OpCode::IntAdd 0x22 => todo!(), // OpCode::IntSub 0x23 => todo!(), // OpCode::IntMul 0x24 => todo!(), // OpCode::IntDiv 0x41 => todo!(), // OpCode::FloatAdd 0x42 => todo!(), // OpCode::FloatSub 0x43 => todo!(), // OpCode::FloatMul 0x44 => todo!(), // OpCode::FloatDiv 0x51 => todo!(), // OpCode::DecimalAdd 0x52 => todo!(), // OpCode::DecimalSub 0x53 => todo!(), // OpCode::DecimalMul 0x54 => todo!(), // OpCode::DecimalDiv 0x30 => todo!(), // OpCode::IfEq 0x31 => todo!(), // OpCode::IfNe 0x32 => todo!(), // OpCode::IfGe 0x33 => todo!(), // OpCode::IfGt 0x34 => todo!(), // OpCode::IfLe 0x35 => todo!(), // OpCode::IfLt 0x36 => { // OpCode::IfEq2 let next_pc = iter.next_u32(); print_op!(iter, pc, "IFEQ2 {:08X}", next_pc); }, 0x37 => { // OpCode::IfNe2 let next_pc = iter.next_u32(); print_op!(iter, pc, "IFNE2 {:08X}", next_pc); }, 0x38 => { // OpCode::IfGe2 let next_pc = iter.next_u32(); print_op!(iter, pc, "IFGE2 {:08X}", next_pc); }, 0x39 => { // OpCode::IfGt2 let next_pc = iter.next_u32(); print_op!(iter, pc, "IFGT2 {:08X}", next_pc); }, 0x3A => { // OpCode::IfLe2 let next_pc = iter.next_u32(); print_op!(iter, pc, "IFLE2 {:08X}", next_pc); }, 0x3B => { // OpCode::IfLt2 let next_pc = iter.next_u32(); print_op!(iter, pc, "IFLT2 {:08X}", next_pc); }, 0xB1 => { // OpCode::NewList print_op!(iter, pc, "NEWLIST"); }, 0xD1 => { // OpCode::NewStruct print_op!(iter, pc, "NEWSTRUCT"); }, _ => panic!("Invalid opcode {:02x} at {:02x}", op, pc), } } } pub struct ByteCodeIter<'a> { bytecode: &'a ByteCode, pc: usize, } impl <'a> ByteCodeIter<'a> { pub fn new(bytecode: &'a ByteCode) -> ByteCodeIter<'a> { ByteCodeIter { bytecode, pc: 0, } } pub fn pc(&self) -> usize { self.pc } pub fn bytecode(&self) -> &ByteCode { self.bytecode } pub fn skip(&mut self, amt: usize) { self.pc += amt; } pub fn next_byte(&mut self) -> Option { if self.pc < self.bytecode.len() { let b = self.bytecode[self.pc]; self.pc += 1; Some(b) } else { None } } pub fn next_u32(&mut self) -> u32 { let mut v: u32 = 0; for _ in 0..4 { v <<= 8; v |= self.next_byte().expect("Truncated bytecode") as u32; } v } pub fn next_varuint(&mut self) -> usize { let mut b: usize = self.next_byte().expect("Truncated bytecode").into(); let mut v = b & 0x7f; while (b & 0x80) == 0 { b = self.next_byte().expect("Truncated bytecode").into(); v <<= 7; v |= b & 0x7f; } v } }