use std::collections::BTreeMap;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct RegisterIndex(pub usize);
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum WasmAbstractValue {
Runtime,
Const(u64),
}
#[derive(Clone, Debug)]
pub struct MachineState {
pub stack_values: Vec<MachineValue>,
pub register_values: Vec<MachineValue>,
pub prev_frame: BTreeMap<usize, MachineValue>,
pub wasm_stack: Vec<WasmAbstractValue>,
pub wasm_inst_offset: usize,
}
#[derive(Clone, Debug, Default)]
#[allow(dead_code)]
pub struct MachineStateDiff {
pub last: Option<usize>,
pub stack_push: Vec<MachineValue>,
pub stack_pop: usize,
pub reg_diff: Vec<(RegisterIndex, MachineValue)>,
pub prev_frame_diff: BTreeMap<usize, Option<MachineValue>>, pub wasm_stack_push: Vec<WasmAbstractValue>,
pub wasm_stack_pop: usize,
pub wasm_inst_offset: usize, }
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum MachineValue {
Undefined,
Vmctx,
_VmctxDeref(Vec<usize>),
PreserveRegister(RegisterIndex),
CopyStackBPRelative(i32), ExplicitShadow, WasmStack(usize),
WasmLocal(usize),
_TwoHalves(Box<(MachineValue, MachineValue)>), }
#[derive(Clone, Debug)]
#[allow(dead_code)]
pub struct FunctionStateMap {
pub initial: MachineState,
pub local_function_id: usize,
pub locals: Vec<WasmAbstractValue>,
pub shadow_size: usize, pub diffs: Vec<MachineStateDiff>,
pub wasm_function_header_target_offset: Option<SuspendOffset>,
pub wasm_offset_to_target_offset: BTreeMap<usize, SuspendOffset>,
pub loop_offsets: BTreeMap<usize, OffsetInfo>, pub call_offsets: BTreeMap<usize, OffsetInfo>, pub trappable_offsets: BTreeMap<usize, OffsetInfo>, }
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Size {
S8,
S16,
S32,
S64,
}
#[allow(dead_code)]
#[derive(Clone, Copy, Debug)]
pub enum SuspendOffset {
_Loop(usize),
Call(usize),
Trappable(usize),
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub struct OffsetInfo {
pub end_offset: usize,
pub diff_id: usize,
pub activate_offset: usize,
}
impl FunctionStateMap {
pub fn new(
initial: MachineState,
local_function_id: usize,
shadow_size: usize,
locals: Vec<WasmAbstractValue>,
) -> FunctionStateMap {
FunctionStateMap {
initial,
local_function_id,
shadow_size,
locals,
diffs: vec![],
wasm_function_header_target_offset: None,
wasm_offset_to_target_offset: BTreeMap::new(),
loop_offsets: BTreeMap::new(),
call_offsets: BTreeMap::new(),
trappable_offsets: BTreeMap::new(),
}
}
}
impl MachineState {
pub fn diff(&self, old: &MachineState) -> MachineStateDiff {
let first_diff_stack_depth: usize = self
.stack_values
.iter()
.zip(old.stack_values.iter())
.enumerate()
.find(|&(_, (a, b))| a != b)
.map(|x| x.0)
.unwrap_or_else(|| old.stack_values.len().min(self.stack_values.len()));
assert_eq!(self.register_values.len(), old.register_values.len());
let reg_diff: Vec<_> = self
.register_values
.iter()
.zip(old.register_values.iter())
.enumerate()
.filter(|&(_, (a, b))| a != b)
.map(|(i, (a, _))| (RegisterIndex(i), a.clone()))
.collect();
let prev_frame_diff: BTreeMap<usize, Option<MachineValue>> = self
.prev_frame
.iter()
.filter(|(k, v)| {
if let Some(ref old_v) = old.prev_frame.get(k) {
v != old_v
} else {
true
}
})
.map(|(&k, v)| (k, Some(v.clone())))
.chain(
old.prev_frame
.iter()
.filter(|(k, _)| !self.prev_frame.contains_key(k))
.map(|(&k, _)| (k, None)),
)
.collect();
let first_diff_wasm_stack_depth: usize = self
.wasm_stack
.iter()
.zip(old.wasm_stack.iter())
.enumerate()
.find(|&(_, (a, b))| a != b)
.map(|x| x.0)
.unwrap_or_else(|| old.wasm_stack.len().min(self.wasm_stack.len()));
MachineStateDiff {
last: None,
stack_push: self.stack_values[first_diff_stack_depth..].to_vec(),
stack_pop: old.stack_values.len() - first_diff_stack_depth,
reg_diff,
prev_frame_diff,
wasm_stack_push: self.wasm_stack[first_diff_wasm_stack_depth..].to_vec(),
wasm_stack_pop: old.wasm_stack.len() - first_diff_wasm_stack_depth,
wasm_inst_offset: self.wasm_inst_offset,
}
}
}
impl MachineStateDiff {
pub fn _build_state(&self, m: &FunctionStateMap) -> MachineState {
let mut chain: Vec<&MachineStateDiff> = vec![self];
let mut current = self.last;
while let Some(x) = current {
let that = &m.diffs[x];
current = that.last;
chain.push(that);
}
chain.reverse();
let mut state = m.initial.clone();
for x in chain {
for _ in 0..x.stack_pop {
state.stack_values.pop().unwrap();
}
for v in &x.stack_push {
state.stack_values.push(v.clone());
}
for &(index, ref v) in &x.reg_diff {
state.register_values[index.0] = v.clone();
}
for (index, ref v) in &x.prev_frame_diff {
if let Some(ref x) = v {
state.prev_frame.insert(*index, x.clone());
} else {
state.prev_frame.remove(index).unwrap();
}
}
for _ in 0..x.wasm_stack_pop {
state.wasm_stack.pop().unwrap();
}
for v in &x.wasm_stack_push {
state.wasm_stack.push(*v);
}
}
state.wasm_inst_offset = self.wasm_inst_offset;
state
}
}