summaryrefslogtreecommitdiff
path: root/src/disasm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/disasm.rs')
-rw-r--r--src/disasm.rs214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/disasm.rs b/src/disasm.rs
new file mode 100644
index 0000000..985a88a
--- /dev/null
+++ b/src/disasm.rs
@@ -0,0 +1,214 @@
+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);
+ },
+ 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");
+ },
+ 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<u8> {
+ 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
+ }
+}