wasmer_compiler_singlepass/
common_decl.rs

1use std::collections::BTreeMap;
2
3#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
4pub struct RegisterIndex(pub usize);
5
6/// Whether a value is determined at compile-time or run-time.
7#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
8pub enum WasmAbstractValue {
9    /// This value is only known at runtime.
10    Runtime,
11    /// A constant value.
12    Const(u64),
13}
14
15/// A container for the state of a running wasm instance.
16#[derive(Clone, Debug)]
17pub struct MachineState {
18    /// Stack values.
19    pub stack_values: Vec<MachineValue>,
20    /// Register values.
21    pub register_values: Vec<MachineValue>,
22    /// Previous frame.
23    pub prev_frame: BTreeMap<usize, MachineValue>,
24    /// Wasm stack.
25    pub wasm_stack: Vec<WasmAbstractValue>,
26    /// Wasm instruction offset.
27    pub wasm_inst_offset: usize,
28}
29
30/// A diff of two `MachineState`s.
31///
32/// A `MachineStateDiff` can only be applied after the `MachineStateDiff` its `last` field
33/// points to is already applied.
34#[derive(Clone, Debug, Default)]
35#[allow(dead_code)]
36pub struct MachineStateDiff {
37    /// Link to the previous diff this diff is based on, or `None` if this is the first diff.
38    pub last: Option<usize>,
39
40    /// What values are pushed onto the stack?
41    pub stack_push: Vec<MachineValue>,
42
43    /// How many values are popped from the stack?
44    pub stack_pop: usize,
45
46    /// Register diff.
47    pub reg_diff: Vec<(RegisterIndex, MachineValue)>,
48
49    /// Changes in the previous frame's data.
50    pub prev_frame_diff: BTreeMap<usize, Option<MachineValue>>, // None for removal
51
52    /// Values pushed to the Wasm stack.
53    pub wasm_stack_push: Vec<WasmAbstractValue>,
54
55    /// # of values popped from the Wasm stack.
56    pub wasm_stack_pop: usize,
57
58    /// Wasm instruction offset.
59    pub wasm_inst_offset: usize, // absolute value; not a diff.
60}
61
62/// A kind of machine value.
63#[derive(Clone, Debug, Eq, PartialEq, Hash)]
64pub enum MachineValue {
65    /// Undefined.
66    Undefined,
67    /// Vmctx.
68    Vmctx,
69    /// Vmctx Deref.
70    _VmctxDeref(Vec<usize>),
71    /// Preserve Register.
72    PreserveRegister(RegisterIndex),
73    /// Copy Stack BP Relative.
74    CopyStackBPRelative(i32), // relative to Base Pointer, in byte offset
75    /// Explicit Shadow.
76    ExplicitShadow, // indicates that all values above this are above the shadow region
77    /// Wasm Stack.
78    WasmStack(usize),
79    /// Wasm Local.
80    WasmLocal(usize),
81    /// Two Halves.
82    _TwoHalves(Box<(MachineValue, MachineValue)>), // 32-bit values. TODO: optimize: add another type for inner "half" value to avoid boxing?
83}
84
85/// A map of function states.
86#[derive(Clone, Debug)]
87#[allow(dead_code)]
88pub struct FunctionStateMap {
89    /// Initial.
90    pub initial: MachineState,
91    /// Local Function Id.
92    pub local_function_id: usize,
93    /// Locals.
94    pub locals: Vec<WasmAbstractValue>,
95    /// Shadow size.
96    pub shadow_size: usize, // for single-pass backend, 32 bytes on x86-64
97    /// Diffs.
98    pub diffs: Vec<MachineStateDiff>,
99    /// Wasm Function Header target offset.
100    pub wasm_function_header_target_offset: Option<SuspendOffset>,
101    /// Wasm offset to target offset
102    pub wasm_offset_to_target_offset: BTreeMap<usize, SuspendOffset>,
103    /// Loop offsets.
104    pub loop_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
105    /// Call offsets.
106    pub call_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
107    /// Trappable offsets.
108    pub trappable_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
109}
110
111#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
112pub enum Size {
113    S8,
114    S16,
115    S32,
116    S64,
117}
118
119/// A kind of suspend offset.
120#[allow(dead_code)]
121#[derive(Clone, Copy, Debug)]
122pub enum SuspendOffset {
123    /// A loop.
124    _Loop(usize),
125    /// A call.
126    Call(usize),
127    /// A trappable.
128    Trappable(usize),
129}
130
131/// Description of a machine code range following an offset.
132#[allow(dead_code)]
133#[derive(Clone, Debug)]
134pub struct OffsetInfo {
135    /// Exclusive range-end offset.
136    pub end_offset: usize,
137    /// Index pointing to the `MachineStateDiff` entry.
138    pub diff_id: usize,
139    /// Offset at which execution can be continued.
140    pub activate_offset: usize,
141}
142
143impl FunctionStateMap {
144    /// Creates a new `FunctionStateMap` with the given parameters.
145    pub fn new(
146        initial: MachineState,
147        local_function_id: usize,
148        shadow_size: usize,
149        locals: Vec<WasmAbstractValue>,
150    ) -> FunctionStateMap {
151        FunctionStateMap {
152            initial,
153            local_function_id,
154            shadow_size,
155            locals,
156            diffs: vec![],
157            wasm_function_header_target_offset: None,
158            wasm_offset_to_target_offset: BTreeMap::new(),
159            loop_offsets: BTreeMap::new(),
160            call_offsets: BTreeMap::new(),
161            trappable_offsets: BTreeMap::new(),
162        }
163    }
164}
165
166impl MachineState {
167    /// Creates a `MachineStateDiff` from self and the given `&MachineState`.
168    pub fn diff(&self, old: &MachineState) -> MachineStateDiff {
169        let first_diff_stack_depth: usize = self
170            .stack_values
171            .iter()
172            .zip(old.stack_values.iter())
173            .enumerate()
174            .find(|&(_, (a, b))| a != b)
175            .map(|x| x.0)
176            .unwrap_or_else(|| old.stack_values.len().min(self.stack_values.len()));
177        assert_eq!(self.register_values.len(), old.register_values.len());
178        let reg_diff: Vec<_> = self
179            .register_values
180            .iter()
181            .zip(old.register_values.iter())
182            .enumerate()
183            .filter(|&(_, (a, b))| a != b)
184            .map(|(i, (a, _))| (RegisterIndex(i), a.clone()))
185            .collect();
186        let prev_frame_diff: BTreeMap<usize, Option<MachineValue>> = self
187            .prev_frame
188            .iter()
189            .filter(|(k, v)| {
190                if let Some(ref old_v) = old.prev_frame.get(k) {
191                    v != old_v
192                } else {
193                    true
194                }
195            })
196            .map(|(&k, v)| (k, Some(v.clone())))
197            .chain(
198                old.prev_frame
199                    .iter()
200                    .filter(|(k, _)| !self.prev_frame.contains_key(k))
201                    .map(|(&k, _)| (k, None)),
202            )
203            .collect();
204        let first_diff_wasm_stack_depth: usize = self
205            .wasm_stack
206            .iter()
207            .zip(old.wasm_stack.iter())
208            .enumerate()
209            .find(|&(_, (a, b))| a != b)
210            .map(|x| x.0)
211            .unwrap_or_else(|| old.wasm_stack.len().min(self.wasm_stack.len()));
212        MachineStateDiff {
213            last: None,
214            stack_push: self.stack_values[first_diff_stack_depth..].to_vec(),
215            stack_pop: old.stack_values.len() - first_diff_stack_depth,
216            reg_diff,
217
218            prev_frame_diff,
219
220            wasm_stack_push: self.wasm_stack[first_diff_wasm_stack_depth..].to_vec(),
221            wasm_stack_pop: old.wasm_stack.len() - first_diff_wasm_stack_depth,
222
223            wasm_inst_offset: self.wasm_inst_offset,
224        }
225    }
226}
227
228impl MachineStateDiff {
229    /// Creates a `MachineState` from the given `&FunctionStateMap`.
230    pub fn _build_state(&self, m: &FunctionStateMap) -> MachineState {
231        let mut chain: Vec<&MachineStateDiff> = vec![self];
232        let mut current = self.last;
233        while let Some(x) = current {
234            let that = &m.diffs[x];
235            current = that.last;
236            chain.push(that);
237        }
238        chain.reverse();
239        let mut state = m.initial.clone();
240        for x in chain {
241            for _ in 0..x.stack_pop {
242                state.stack_values.pop().unwrap();
243            }
244            for v in &x.stack_push {
245                state.stack_values.push(v.clone());
246            }
247            for &(index, ref v) in &x.reg_diff {
248                state.register_values[index.0] = v.clone();
249            }
250            for (index, ref v) in &x.prev_frame_diff {
251                if let Some(x) = v {
252                    state.prev_frame.insert(*index, x.clone());
253                } else {
254                    state.prev_frame.remove(index).unwrap();
255                }
256            }
257            for _ in 0..x.wasm_stack_pop {
258                state.wasm_stack.pop().unwrap();
259            }
260            for v in &x.wasm_stack_push {
261                state.wasm_stack.push(*v);
262            }
263        }
264        state.wasm_inst_offset = self.wasm_inst_offset;
265        state
266    }
267}