use std::collections::BTreeMap;
use crate::decompiler::cfg::BlockId;
use crate::instruction::{OpCode, Operand};
use super::super::form::SsaStmt;
use super::super::variable::SsaVariable;
#[derive(Default)]
pub(super) struct BlockExec {
pub(super) exit_stack: Vec<SsaVariable>,
pub(super) exit_slots: SlotState,
pub(super) stmts: Vec<SsaStmt>,
pub(super) uses: Vec<(SsaVariable, usize)>,
}
pub(super) type SlotState = BTreeMap<String, SsaVariable>;
pub(super) fn phi_var(block: BlockId, depth: usize) -> SsaVariable {
SsaVariable::new(format!("p{}", block.0), depth)
}
pub(super) fn fresh_var(versions: &mut BTreeMap<String, usize>, base: &str) -> SsaVariable {
let slot = versions.entry(base.to_string()).or_insert(0);
let var = SsaVariable::new(base.to_string(), *slot);
*slot += 1;
var
}
pub(super) fn slot_name_for(op: OpCode, operand: &Option<Operand>) -> Option<String> {
use OpCode::*;
let (kind, idx): (&str, usize) = match op {
Ldloc0 => ("loc", 0),
Ldloc1 => ("loc", 1),
Ldloc2 => ("loc", 2),
Ldloc3 => ("loc", 3),
Ldloc4 => ("loc", 4),
Ldloc5 => ("loc", 5),
Ldloc6 => ("loc", 6),
Ldarg0 => ("arg", 0),
Ldarg1 => ("arg", 1),
Ldarg2 => ("arg", 2),
Ldarg3 => ("arg", 3),
Ldarg4 => ("arg", 4),
Ldarg5 => ("arg", 5),
Ldarg6 => ("arg", 6),
Ldsfld0 => ("static", 0),
Ldsfld1 => ("static", 1),
Ldsfld2 => ("static", 2),
Ldsfld3 => ("static", 3),
Ldsfld4 => ("static", 4),
Ldsfld5 => ("static", 5),
Ldsfld6 => ("static", 6),
Stloc0 => ("loc", 0),
Stloc1 => ("loc", 1),
Stloc2 => ("loc", 2),
Stloc3 => ("loc", 3),
Stloc4 => ("loc", 4),
Stloc5 => ("loc", 5),
Stloc6 => ("loc", 6),
Starg0 => ("arg", 0),
Starg1 => ("arg", 1),
Starg2 => ("arg", 2),
Starg3 => ("arg", 3),
Starg4 => ("arg", 4),
Starg5 => ("arg", 5),
Starg6 => ("arg", 6),
Stsfld0 => ("static", 0),
Stsfld1 => ("static", 1),
Stsfld2 => ("static", 2),
Stsfld3 => ("static", 3),
Stsfld4 => ("static", 4),
Stsfld5 => ("static", 5),
Stsfld6 => ("static", 6),
Ldloc | Ldarg | Ldsfld | Stloc | Starg | Stsfld => {
let kind = match op {
Ldloc | Stloc => "loc",
Ldarg | Starg => "arg",
Ldsfld | Stsfld => "static",
_ => return None,
};
match operand {
Some(Operand::U8(n)) => (kind, *n as usize),
_ => return None,
}
}
_ => return None,
};
Some(format!("{kind}{idx}"))
}
pub(super) fn unknown_var() -> SsaVariable {
SsaVariable::new("?".to_string(), 0)
}
pub(super) fn is_unknown(v: &SsaVariable) -> bool {
v.base == "?"
}
pub(super) fn reverse_top(stack: &mut [SsaVariable], n: usize) {
let len = stack.len();
if n <= 1 || n > len {
return;
}
stack[len - n..].reverse();
}