Add instruction dumper
A vector of instructions and constants can now be decompiled as text on the terminal to give an idea of what the VM is doing. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
127
src/vm/inst.rs
127
src/vm/inst.rs
@@ -1,4 +1,5 @@
|
||||
use crate::{obj::prelude::*, vm::consts::ConstHandle};
|
||||
use crate::{obj::prelude::*, vm::consts::*};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum Inst {
|
||||
@@ -12,7 +13,7 @@ pub enum Inst {
|
||||
PushLocal(Local),
|
||||
|
||||
/// Pop a value from the stack, possibly into a local symbol.
|
||||
Pop(Option<Sym>),
|
||||
Pop(Option<Local>),
|
||||
|
||||
/// Pops a symbol value and an object reference.
|
||||
///
|
||||
@@ -109,3 +110,125 @@ pub enum Inst {
|
||||
/// pushing the result to the stack.
|
||||
BinOr,
|
||||
}
|
||||
|
||||
//
|
||||
// impl Inst
|
||||
//
|
||||
impl Inst {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Inst::PushSym(_) => "PUSH_SYM",
|
||||
Inst::PushConst(_) => "PUSH_CONST",
|
||||
Inst::PushLocal(_) => "PUSH_LOCAL",
|
||||
Inst::Pop(_) => "POP",
|
||||
Inst::GetAttr(_) => "GET_ATTR",
|
||||
Inst::SetAttr(_) => "SET_ATTR",
|
||||
Inst::Jump(_) => "JUMP",
|
||||
Inst::JumpTrue(_) => "JUMP_TRUE",
|
||||
Inst::Call(_) => "CALL",
|
||||
Inst::Index => "INDEX",
|
||||
Inst::Return => "RETURN",
|
||||
Inst::UnNeg => "UN_NEG",
|
||||
Inst::UnPos => "UN_POS",
|
||||
Inst::BinPlus => "BIN_PLUS",
|
||||
Inst::BinMinus => "BIN_MINUS",
|
||||
Inst::BinMul => "BIN_MUL",
|
||||
Inst::BinDiv => "BIN_DIV",
|
||||
Inst::BinEq => "BIN_EQ",
|
||||
Inst::BinNeq => "BIN_NEQ",
|
||||
Inst::BinLt => "BIN_LT",
|
||||
Inst::BinLe => "BIN_LE",
|
||||
Inst::BinGt => "BIN_GT",
|
||||
Inst::BinGe => "BIN_GE",
|
||||
Inst::BinAnd => "BIN_AND",
|
||||
Inst::BinOr => "BIN_OR",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump_inst_body(insts: &Vec<Inst>, const_pool: &ConstPool) {
|
||||
println!("{}", InstFormatter::new(insts, const_pool))
|
||||
}
|
||||
|
||||
//
|
||||
// struct InstFormatter
|
||||
//
|
||||
|
||||
pub struct InstFormatter<'i, 'c> {
|
||||
insts: &'i Vec<Inst>,
|
||||
const_pool: &'c ConstPool,
|
||||
}
|
||||
|
||||
impl<'i, 'c> InstFormatter<'i, 'c> {
|
||||
pub fn new(insts: &'i Vec<Inst>, const_pool: &'c ConstPool) -> Self {
|
||||
Self { insts, const_pool, }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for InstFormatter<'_, '_> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||
// column widths
|
||||
let addr_w = num_digits(self.insts.len(), 16).max(4);
|
||||
let inst_col = 16 - addr_w;
|
||||
let inst_w = 16;
|
||||
|
||||
for (addr, inst) in self.insts.iter().enumerate() {
|
||||
let (param_val, mut param_name) = match inst {
|
||||
Inst::PushSym(sym) | Inst::GetAttr(sym) | Inst::SetAttr(sym) => (
|
||||
sym.index().to_string(),
|
||||
global_sym_lookup(*sym).unwrap().to_string(),
|
||||
),
|
||||
Inst::PushConst(hdl) => (
|
||||
hdl.index().to_string(),
|
||||
{
|
||||
let obj_ref = self.const_pool.get(*hdl);
|
||||
read_obj!(let obj = obj_ref);
|
||||
// XXX weirdness with coercion, can't deref as a &dyn Obj because
|
||||
// RwReadLockGuard is not Obj - but using Deref::deref works
|
||||
let obj: &dyn Obj = std::ops::Deref::deref(obj);
|
||||
format!("{:?}", obj)
|
||||
},
|
||||
),
|
||||
Inst::PushLocal(local) => (
|
||||
local.index().to_string(),
|
||||
"TODO: local name".to_string(),
|
||||
),
|
||||
Inst::Pop(local) => (
|
||||
format!("{:?}", local),
|
||||
"TODO: local name".to_string(),
|
||||
),
|
||||
Inst::Jump(addr) | Inst::JumpTrue(addr) => (
|
||||
addr.to_string(),
|
||||
String::new(),
|
||||
),
|
||||
Inst::Call(argc) => (
|
||||
argc.to_string(),
|
||||
String::new(),
|
||||
),
|
||||
_ => (String::new(), String::new()),
|
||||
};
|
||||
|
||||
if !param_name.is_empty() {
|
||||
param_name = format!("({})", param_name);
|
||||
}
|
||||
|
||||
writeln!(
|
||||
fmt,
|
||||
"{:0addr_w$x}{space: >inst_col$}{: <inst_w$}{} {}",
|
||||
addr,
|
||||
inst.name(),
|
||||
param_val,
|
||||
param_name,
|
||||
space = "",
|
||||
addr_w = addr_w,
|
||||
inst_w = inst_w,
|
||||
inst_col = inst_col,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn num_digits(n: usize, radix: usize) -> usize {
|
||||
((n as f64) + 1.0).log(radix as f64).ceil() as usize
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user