Skip to content

Commit

Permalink
properly display string and idents in IR dump
Browse files Browse the repository at this point in the history
  • Loading branch information
y21 committed Dec 28, 2023
1 parent 6301322 commit 23a5583
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 23 deletions.
2 changes: 1 addition & 1 deletion cli/src/cmd/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub fn dump(arg: &ArgMatches) -> anyhow::Result<()> {
}

if dump_ir {
let out = dash_decompiler::decompile(&bytecode.cp, &bytecode.instructions)?;
let out = dash_decompiler::decompile(interner, &bytecode.cp, &bytecode.instructions)?;
println!("{out}");
}

Expand Down
62 changes: 42 additions & 20 deletions crates/dash_decompiler/src/decompiler.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use dash_middle::compiler::constant::Constant;
use dash_middle::compiler::instruction::{Instruction, IntrinsicOperation};
use dash_middle::compiler::{FunctionCallMetadata, ObjectMemberKind};
use dash_middle::interner::StringInterner;
use dash_middle::util::Reader;
use std::fmt;
use std::fmt::Write;
use std::rc::Rc;

use crate::DecompileError;

pub struct FunctionDecompiler<'buf> {
pub struct FunctionDecompiler<'interner, 'buf> {
interner: &'interner StringInterner,
reader: Reader<&'buf [u8]>,
constants: &'buf [Constant],
name: &'buf str,
Expand All @@ -17,11 +19,17 @@ pub struct FunctionDecompiler<'buf> {
instr_idx: usize,
}

impl<'buf> FunctionDecompiler<'buf> {
pub fn new(buf: &'buf [u8], constants: &'buf [Constant], name: &'buf str) -> Self {
impl<'interner, 'buf> FunctionDecompiler<'interner, 'buf> {
pub fn new(
interner: &'interner StringInterner,
buf: &'buf [u8],
constants: &'buf [Constant],
name: &'buf str,
) -> Self {
Self {
reader: Reader::new(buf),
constants,
interner,
out: format!("function {name}:\n"),
name,
instr_idx: 0,
Expand Down Expand Up @@ -102,6 +110,10 @@ impl<'buf> FunctionDecompiler<'buf> {
self.reader.read_u32_ne().ok_or(DecompileError::AbruptEof)
}

fn display(&self, constant: &'buf Constant) -> DisplayConstant<'interner, 'buf> {
DisplayConstant(self.interner, constant)
}

pub fn run(mut self) -> Result<String, DecompileError> {
let mut functions = Vec::new();

Expand Down Expand Up @@ -132,15 +144,15 @@ impl<'buf> FunctionDecompiler<'buf> {
if let Constant::Function(fun) = constant {
functions.push(Rc::clone(fun));
}
self.handle_op_instr("constant", &[&DisplayConstant(constant)]);
self.handle_op_instr("constant", &[&self.display(constant)]);
}
Instruction::ConstantW => {
let b = self.read_u16()?;
let constant = &self.constants[b as usize];
if let Constant::Function(fun) = constant {
functions.push(Rc::clone(fun));
}
self.handle_op_instr("constant", &[&DisplayConstant(constant)]);
self.handle_op_instr("constant", &[&self.display(constant)]);
}
Instruction::LdLocal => {
let b = self.read()?;
Expand Down Expand Up @@ -178,11 +190,11 @@ impl<'buf> FunctionDecompiler<'buf> {
}
Instruction::LdGlobal => {
let b = self.read()?;
self.handle_op_instr("ldglobal", &[&DisplayConstant(&self.constants[b as usize])]);
self.handle_op_instr("ldglobal", &[&self.display(&self.constants[b as usize])]);
}
Instruction::LdGlobalW => {
let b = self.read_u16()?;
self.handle_op_instr("ldglobalw", &[&DisplayConstant(&self.constants[b as usize])]);
self.handle_op_instr("ldglobalw", &[&self.display(&self.constants[b as usize])]);
}
Instruction::StoreLocal => self.handle_inc_op_instr2("storelocal")?,
Instruction::StoreLocalW => self.handle_inc_op_instr2("storelocalw")?,
Expand All @@ -199,12 +211,12 @@ impl<'buf> FunctionDecompiler<'buf> {
Instruction::StaticPropAccess => {
let b = self.read()?;
let _preserve_this = self.read()?;
self.handle_op_instr("staticpropaccess", &[&DisplayConstant(&self.constants[b as usize])]);
self.handle_op_instr("staticpropaccess", &[&self.display(&self.constants[b as usize])]);
}
Instruction::StaticPropAccessW => {
let b = self.read_u16()?;
let _preserve_this = self.read()?;
self.handle_op_instr("staticpropaccessw", &[&DisplayConstant(&self.constants[b as usize])]);
self.handle_op_instr("staticpropaccessw", &[&self.display(&self.constants[b as usize])]);
}
Instruction::Ret => {
self.read_u16()?; // intentionally ignored
Expand All @@ -218,12 +230,12 @@ impl<'buf> FunctionDecompiler<'buf> {
Instruction::StoreGlobal => {
let b = self.read()?;
let _kind = self.read();
self.handle_op_instr("storeglobal", &[&DisplayConstant(&self.constants[b as usize])]);
self.handle_op_instr("storeglobal", &[&self.display(&self.constants[b as usize])]);
}
Instruction::StoreGlobalW => {
let b = self.read_u16()?;
let _kind = self.read();
self.handle_op_instr("storeglobalw", &[&DisplayConstant(&self.constants[b as usize])]);
self.handle_op_instr("storeglobalw", &[&self.display(&self.constants[b as usize])]);
}
Instruction::DynamicPropAccess => {
let b = self.read()?;
Expand All @@ -244,7 +256,7 @@ impl<'buf> FunctionDecompiler<'buf> {
}
ObjectMemberKind::Static | ObjectMemberKind::Getter | ObjectMemberKind::Setter => {
let cid = self.read_u16()?;
props.push(DisplayConstant(&self.constants[cid as usize]).to_string());
props.push(self.display(&self.constants[cid as usize]).to_string());
}
ObjectMemberKind::Spread => {
props.push(String::from("<spread>"));
Expand All @@ -259,7 +271,7 @@ impl<'buf> FunctionDecompiler<'buf> {
Instruction::StaticPropAssign => {
let _k = self.read()?;
let b = self.read_u16()?;
self.handle_op_instr("staticpropassign", &[&DisplayConstant(&self.constants[b as usize])]);
self.handle_op_instr("staticpropassign", &[&self.display(&self.constants[b as usize])]);
}
Instruction::DynamicPropAssign => {
let _k = self.read()?;
Expand Down Expand Up @@ -417,7 +429,13 @@ impl<'buf> FunctionDecompiler<'buf> {

for fun in functions {
let out = fun.buffer.with(|buffer| {
FunctionDecompiler::new(buffer, &fun.constants, &format!("{}::{:?}", self.name, fun.name)).run()
FunctionDecompiler::new(
self.interner,
buffer,
&fun.constants,
&format!("{}::{:?}", self.name, fun.name),
)
.run()
})?;
self.out.push('\n');
self.out.push_str(&out);
Expand All @@ -427,15 +445,19 @@ impl<'buf> FunctionDecompiler<'buf> {
}
}

struct DisplayConstant<'c>(&'c Constant);
impl fmt::Display for DisplayConstant<'_> {
struct DisplayConstant<'i, 'a>(&'i StringInterner, &'a Constant);
impl fmt::Display for DisplayConstant<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
match self.1 {
Constant::Number(n) => write!(f, "{n}"),
Constant::String(s) => write!(f, "\"{s}\""),
Constant::String(s) => write!(f, "\"{}\"", self.0.resolve(*s)),
Constant::Boolean(b) => write!(f, "{b}"),
Constant::Identifier(ident) => write!(f, "{ident}"),
Constant::Function(fun) => write!(f, "<function {:?}>", fun.name),
Constant::Identifier(ident) => write!(f, "{}", self.0.resolve(*ident)),
Constant::Function(fun) => write!(
f,
"<function {}>",
fun.name.map(|v| self.0.resolve(v)).unwrap_or("<anon>")
),
Constant::Null => f.write_str("null"),
Constant::Undefined => f.write_str("undefined"),
Constant::Regex(_, _, source) => write!(f, "{source}"),
Expand Down
9 changes: 7 additions & 2 deletions crates/dash_decompiler/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use dash_middle::compiler::constant::Constant;
use dash_middle::compiler::instruction::Instruction;
use dash_middle::interner::StringInterner;
use decompiler::FunctionDecompiler;
use thiserror::Error;

Expand All @@ -19,6 +20,10 @@ pub enum DecompileError {
InvalidIntrinsicOp(u8),
}

pub fn decompile(constants: &[Constant], instructions: &[u8]) -> Result<String, DecompileError> {
FunctionDecompiler::new(instructions, constants, "<main>").run()
pub fn decompile(
interner: &StringInterner,
constants: &[Constant],
instructions: &[u8],
) -> Result<String, DecompileError> {
FunctionDecompiler::new(interner, instructions, constants, "<main>").run()
}

0 comments on commit 23a5583

Please sign in to comment.