From 72c54d3d6aefa7cd24501d6e8ee60350d7c73f5a Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Sun, 31 Dec 2023 17:56:30 -0800 Subject: Add disassembler output to debug --- src/disasm.rs | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/js.rs | 15 ++-- src/main.rs | 1 + 3 files changed, 225 insertions(+), 5 deletions(-) create mode 100644 src/disasm.rs 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 { + 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 + } +} diff --git a/src/js.rs b/src/js.rs index d924969..c0a96f8 100644 --- a/src/js.rs +++ b/src/js.rs @@ -24,6 +24,7 @@ use boa_interner::Sym; use ion_rs::SymbolTable; +use crate::disasm::print_disassembly; use crate::ion::IonValue; use crate::runtime::Function; use crate::runtime::OpCode; @@ -460,12 +461,12 @@ impl JsCompiler { }, Expression::Parenthesized(expr) => self.get_static_expression(expr.expression()), - + // TODO: Add static evaluation to these. - Expression::Assign(assignment) => None, + Expression::Assign(_) => None, Expression::Unary(_) => None, Expression::Update(_) => None, - Expression::Binary(binary) => None, + Expression::Binary(_) => None, Expression::BinaryInPrivate(_) => None, Expression::Conditional(_) => None, Expression::Call(_) => None, @@ -572,7 +573,6 @@ impl JsCompiler { }, PropertyAccessField::Expr(expr) => { self.compile_expression(expr); - todo!("cast to symbol") }, } let jump_found = self.push_ifeq2(); @@ -630,7 +630,7 @@ impl JsCompiler { } } } - + fn compile_statement(&mut self, statement: &Statement) { match statement { boa_ast::Statement::Block(block) => { @@ -768,6 +768,11 @@ impl JsCompiler { println!(); } println!(); + + println!("Disassembly"); + println!("--------"); + print_disassembly(&self.bytecode); + println!(); } pub fn compile_script(&mut self, script: Script) { diff --git a/src/main.rs b/src/main.rs index 33da842..f241ba5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ use boa_parser::Source; use crate::js::JsCompiler; use crate::runtime::Runtime; +mod disasm; mod js; mod ion; mod runtime; -- cgit v1.2.3