xref: /wasmtime-44.0.1/winch/codegen/src/stack.rs (revision a0442ea0)
114b39bc2SSaúl Cabrera use crate::{isa::reg::Reg, masm::StackSlot};
21b5c4ae8SSaúl Cabrera use smallvec::SmallVec;
314b39bc2SSaúl Cabrera use wasmparser::{Ieee32, Ieee64};
4496237c2SNick Fitzgerald use wasmtime_environ::WasmValType;
514b39bc2SSaúl Cabrera 
614b39bc2SSaúl Cabrera /// A typed register value used to track register values in the value
714b39bc2SSaúl Cabrera /// stack.
814b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
914b39bc2SSaúl Cabrera pub struct TypedReg {
1014b39bc2SSaúl Cabrera     /// The physical register.
1114b39bc2SSaúl Cabrera     pub reg: Reg,
1214b39bc2SSaúl Cabrera     /// The type associated to the physical register.
13496237c2SNick Fitzgerald     pub ty: WasmValType,
1414b39bc2SSaúl Cabrera }
1514b39bc2SSaúl Cabrera 
1614b39bc2SSaúl Cabrera impl TypedReg {
174b288ba8SSaúl Cabrera     /// Create a new [`TypedReg`].
18496237c2SNick Fitzgerald     pub fn new(ty: WasmValType, reg: Reg) -> Self {
1914b39bc2SSaúl Cabrera         Self { ty, reg }
2014b39bc2SSaúl Cabrera     }
2114b39bc2SSaúl Cabrera 
224b288ba8SSaúl Cabrera     /// Create an i64 [`TypedReg`].
2314b39bc2SSaúl Cabrera     pub fn i64(reg: Reg) -> Self {
2414b39bc2SSaúl Cabrera         Self {
25496237c2SNick Fitzgerald             ty: WasmValType::I64,
2614b39bc2SSaúl Cabrera             reg,
2714b39bc2SSaúl Cabrera         }
2814b39bc2SSaúl Cabrera     }
29a109d2abSSaúl Cabrera 
30f0162a40SSaúl Cabrera     /// Create an i32 [`TypedReg`].
31a109d2abSSaúl Cabrera     pub fn i32(reg: Reg) -> Self {
32a109d2abSSaúl Cabrera         Self {
33496237c2SNick Fitzgerald             ty: WasmValType::I32,
34a109d2abSSaúl Cabrera             reg,
35a109d2abSSaúl Cabrera         }
36a109d2abSSaúl Cabrera     }
3717091e6fSJeffrey Charles 
3817091e6fSJeffrey Charles     /// Create an f64 [`TypedReg`].
3917091e6fSJeffrey Charles     pub fn f64(reg: Reg) -> Self {
4017091e6fSJeffrey Charles         Self {
41496237c2SNick Fitzgerald             ty: WasmValType::F64,
4217091e6fSJeffrey Charles             reg,
4317091e6fSJeffrey Charles         }
4417091e6fSJeffrey Charles     }
4517091e6fSJeffrey Charles 
4617091e6fSJeffrey Charles     /// Create an f32 [`TypedReg`].
4717091e6fSJeffrey Charles     pub fn f32(reg: Reg) -> Self {
4817091e6fSJeffrey Charles         Self {
49496237c2SNick Fitzgerald             ty: WasmValType::F32,
5017091e6fSJeffrey Charles             reg,
5117091e6fSJeffrey Charles         }
5217091e6fSJeffrey Charles     }
5314b39bc2SSaúl Cabrera }
5414b39bc2SSaúl Cabrera 
5514b39bc2SSaúl Cabrera impl From<TypedReg> for Reg {
5614b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
5714b39bc2SSaúl Cabrera         tr.reg
5814b39bc2SSaúl Cabrera     }
5914b39bc2SSaúl Cabrera }
6014b39bc2SSaúl Cabrera 
6114b39bc2SSaúl Cabrera /// A local value.
6214b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
6314b39bc2SSaúl Cabrera pub struct Local {
6414b39bc2SSaúl Cabrera     /// The index of the local.
6514b39bc2SSaúl Cabrera     pub index: u32,
6614b39bc2SSaúl Cabrera     /// The type of the local.
67496237c2SNick Fitzgerald     pub ty: WasmValType,
6814b39bc2SSaúl Cabrera }
6914b39bc2SSaúl Cabrera 
7014b39bc2SSaúl Cabrera /// A memory value.
7114b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
7214b39bc2SSaúl Cabrera pub struct Memory {
7314b39bc2SSaúl Cabrera     /// The type associated with the memory offset.
74496237c2SNick Fitzgerald     pub ty: WasmValType,
7514b39bc2SSaúl Cabrera     /// The stack slot corresponding to the memory value.
7614b39bc2SSaúl Cabrera     pub slot: StackSlot,
7714b39bc2SSaúl Cabrera }
78835abbcdSSaúl Cabrera 
79835abbcdSSaúl Cabrera /// Value definition to be used within the shadow stack.
80a50c4972SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
81835abbcdSSaúl Cabrera pub(crate) enum Val {
82835abbcdSSaúl Cabrera     /// I32 Constant.
83835abbcdSSaúl Cabrera     I32(i32),
847c5c7e4bSSaúl Cabrera     /// I64 Constant.
857c5c7e4bSSaúl Cabrera     I64(i64),
8614b39bc2SSaúl Cabrera     /// F32 Constant.
8714b39bc2SSaúl Cabrera     F32(Ieee32),
8814b39bc2SSaúl Cabrera     /// F64 Constant.
8914b39bc2SSaúl Cabrera     F64(Ieee64),
90fa9a948dSJeffrey Charles     /// V128 Constant.
91fa9a948dSJeffrey Charles     V128(i128),
9214b39bc2SSaúl Cabrera     /// A register value.
9314b39bc2SSaúl Cabrera     Reg(TypedReg),
94835abbcdSSaúl Cabrera     /// A local slot.
9514b39bc2SSaúl Cabrera     Local(Local),
96835abbcdSSaúl Cabrera     /// Offset to a memory location.
9714b39bc2SSaúl Cabrera     Memory(Memory),
9814b39bc2SSaúl Cabrera }
9914b39bc2SSaúl Cabrera 
10014b39bc2SSaúl Cabrera impl From<TypedReg> for Val {
10114b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
10214b39bc2SSaúl Cabrera         Val::Reg(tr)
10314b39bc2SSaúl Cabrera     }
10414b39bc2SSaúl Cabrera }
10514b39bc2SSaúl Cabrera 
10614b39bc2SSaúl Cabrera impl From<Local> for Val {
10714b39bc2SSaúl Cabrera     fn from(local: Local) -> Self {
10814b39bc2SSaúl Cabrera         Val::Local(local)
10914b39bc2SSaúl Cabrera     }
11014b39bc2SSaúl Cabrera }
11114b39bc2SSaúl Cabrera 
11214b39bc2SSaúl Cabrera impl From<Memory> for Val {
11314b39bc2SSaúl Cabrera     fn from(mem: Memory) -> Self {
11414b39bc2SSaúl Cabrera         Val::Memory(mem)
11514b39bc2SSaúl Cabrera     }
116835abbcdSSaúl Cabrera }
117835abbcdSSaúl Cabrera 
1184b288ba8SSaúl Cabrera impl TryFrom<u32> for Val {
1194b288ba8SSaúl Cabrera     type Error = anyhow::Error;
1204b288ba8SSaúl Cabrera     fn try_from(value: u32) -> Result<Self, Self::Error> {
1214b288ba8SSaúl Cabrera         i32::try_from(value).map(Val::i32).map_err(Into::into)
1224b288ba8SSaúl Cabrera     }
1234b288ba8SSaúl Cabrera }
1244b288ba8SSaúl Cabrera 
125835abbcdSSaúl Cabrera impl Val {
126835abbcdSSaúl Cabrera     /// Create a new I32 constant value.
127835abbcdSSaúl Cabrera     pub fn i32(v: i32) -> Self {
128835abbcdSSaúl Cabrera         Self::I32(v)
129835abbcdSSaúl Cabrera     }
130835abbcdSSaúl Cabrera 
1317c5c7e4bSSaúl Cabrera     /// Create a new I64 constant value.
1327c5c7e4bSSaúl Cabrera     pub fn i64(v: i64) -> Self {
1337c5c7e4bSSaúl Cabrera         Self::I64(v)
1347c5c7e4bSSaúl Cabrera     }
1357c5c7e4bSSaúl Cabrera 
13614b39bc2SSaúl Cabrera     /// Create a new F32 constant value.
13714b39bc2SSaúl Cabrera     pub fn f32(v: Ieee32) -> Self {
13814b39bc2SSaúl Cabrera         Self::F32(v)
13914b39bc2SSaúl Cabrera     }
14014b39bc2SSaúl Cabrera 
14114b39bc2SSaúl Cabrera     pub fn f64(v: Ieee64) -> Self {
14214b39bc2SSaúl Cabrera         Self::F64(v)
14314b39bc2SSaúl Cabrera     }
14414b39bc2SSaúl Cabrera 
145fa9a948dSJeffrey Charles     /// Create a new V128 constant value.
146fa9a948dSJeffrey Charles     pub fn v128(v: i128) -> Self {
147fa9a948dSJeffrey Charles         Self::V128(v)
148fa9a948dSJeffrey Charles     }
149fa9a948dSJeffrey Charles 
150835abbcdSSaúl Cabrera     /// Create a new Reg value.
151496237c2SNick Fitzgerald     pub fn reg(reg: Reg, ty: WasmValType) -> Self {
15214b39bc2SSaúl Cabrera         Self::Reg(TypedReg { reg, ty })
153835abbcdSSaúl Cabrera     }
154835abbcdSSaúl Cabrera 
155835abbcdSSaúl Cabrera     /// Create a new Local value.
156496237c2SNick Fitzgerald     pub fn local(index: u32, ty: WasmValType) -> Self {
15714b39bc2SSaúl Cabrera         Self::Local(Local { index, ty })
15814b39bc2SSaúl Cabrera     }
15914b39bc2SSaúl Cabrera 
16014b39bc2SSaúl Cabrera     /// Create a Memory value.
161496237c2SNick Fitzgerald     pub fn mem(ty: WasmValType, slot: StackSlot) -> Self {
16214b39bc2SSaúl Cabrera         Self::Memory(Memory { ty, slot })
163835abbcdSSaúl Cabrera     }
164835abbcdSSaúl Cabrera 
165835abbcdSSaúl Cabrera     /// Check whether the value is a register.
166835abbcdSSaúl Cabrera     pub fn is_reg(&self) -> bool {
167835abbcdSSaúl Cabrera         match *self {
168835abbcdSSaúl Cabrera             Self::Reg(_) => true,
169835abbcdSSaúl Cabrera             _ => false,
170835abbcdSSaúl Cabrera         }
171835abbcdSSaúl Cabrera     }
172835abbcdSSaúl Cabrera 
1730e9121daSFrankReh     /// Check whether the value is a memory offset.
174af4d94c8SSaúl Cabrera     pub fn is_mem(&self) -> bool {
175af4d94c8SSaúl Cabrera         match *self {
176af4d94c8SSaúl Cabrera             Self::Memory(_) => true,
177af4d94c8SSaúl Cabrera             _ => false,
178af4d94c8SSaúl Cabrera         }
179af4d94c8SSaúl Cabrera     }
180af4d94c8SSaúl Cabrera 
18155f9a4bdSJeffrey Charles     /// Check whether the value is a constant.
18255f9a4bdSJeffrey Charles     pub fn is_const(&self) -> bool {
18355f9a4bdSJeffrey Charles         match *self {
184fa9a948dSJeffrey Charles             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
18555f9a4bdSJeffrey Charles             _ => false,
18655f9a4bdSJeffrey Charles         }
18755f9a4bdSJeffrey Charles     }
18855f9a4bdSJeffrey Charles 
189321294a5SJeffrey Charles     /// Check whether the value is local with a particular index.
190321294a5SJeffrey Charles     pub fn is_local_at_index(&self, index: u32) -> bool {
191321294a5SJeffrey Charles         match *self {
192321294a5SJeffrey Charles             Self::Local(Local { index: i, .. }) if i == index => true,
193321294a5SJeffrey Charles             _ => false,
194321294a5SJeffrey Charles         }
195321294a5SJeffrey Charles     }
196321294a5SJeffrey Charles 
197835abbcdSSaúl Cabrera     /// Get the register representation of the value.
198835abbcdSSaúl Cabrera     ///
199835abbcdSSaúl Cabrera     /// # Panics
200835abbcdSSaúl Cabrera     /// This method will panic if the value is not a register.
201f0162a40SSaúl Cabrera     pub fn unwrap_reg(&self) -> TypedReg {
202835abbcdSSaúl Cabrera         match self {
20314b39bc2SSaúl Cabrera             Self::Reg(tr) => *tr,
204*a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be a register"),
205835abbcdSSaúl Cabrera         }
206835abbcdSSaúl Cabrera     }
207835abbcdSSaúl Cabrera 
208835abbcdSSaúl Cabrera     /// Get the integer representation of the value.
209835abbcdSSaúl Cabrera     ///
210835abbcdSSaúl Cabrera     /// # Panics
211835abbcdSSaúl Cabrera     /// This method will panic if the value is not an i32.
212f0162a40SSaúl Cabrera     pub fn unwrap_i32(&self) -> i32 {
213835abbcdSSaúl Cabrera         match self {
214835abbcdSSaúl Cabrera             Self::I32(v) => *v,
215*a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be i32"),
216835abbcdSSaúl Cabrera         }
217835abbcdSSaúl Cabrera     }
218835abbcdSSaúl Cabrera 
2197c5c7e4bSSaúl Cabrera     /// Get the integer representation of the value.
2207c5c7e4bSSaúl Cabrera     ///
2217c5c7e4bSSaúl Cabrera     /// # Panics
2227c5c7e4bSSaúl Cabrera     /// This method will panic if the value is not an i64.
223f0162a40SSaúl Cabrera     pub fn unwrap_i64(&self) -> i64 {
2247c5c7e4bSSaúl Cabrera         match self {
2257c5c7e4bSSaúl Cabrera             Self::I64(v) => *v,
226*a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be i64"),
2277c5c7e4bSSaúl Cabrera         }
2287c5c7e4bSSaúl Cabrera     }
2297c5c7e4bSSaúl Cabrera 
230f0162a40SSaúl Cabrera     /// Returns the underlying memory value if it is one, panics otherwise.
231f0162a40SSaúl Cabrera     pub fn unwrap_mem(&self) -> Memory {
232f0162a40SSaúl Cabrera         match self {
233f0162a40SSaúl Cabrera             Self::Memory(m) => *m,
234*a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be a Memory"),
235f0162a40SSaúl Cabrera         }
236f0162a40SSaúl Cabrera     }
237f0162a40SSaúl Cabrera 
238835abbcdSSaúl Cabrera     /// Check whether the value is an i32 constant.
239835abbcdSSaúl Cabrera     pub fn is_i32_const(&self) -> bool {
240835abbcdSSaúl Cabrera         match *self {
241835abbcdSSaúl Cabrera             Self::I32(_) => true,
242835abbcdSSaúl Cabrera             _ => false,
243835abbcdSSaúl Cabrera         }
244835abbcdSSaúl Cabrera     }
2457c5c7e4bSSaúl Cabrera 
2467c5c7e4bSSaúl Cabrera     /// Check whether the value is an i64 constant.
2477c5c7e4bSSaúl Cabrera     pub fn is_i64_const(&self) -> bool {
2487c5c7e4bSSaúl Cabrera         match *self {
2497c5c7e4bSSaúl Cabrera             Self::I64(_) => true,
2507c5c7e4bSSaúl Cabrera             _ => false,
2517c5c7e4bSSaúl Cabrera         }
2527c5c7e4bSSaúl Cabrera     }
25314b39bc2SSaúl Cabrera 
25414b39bc2SSaúl Cabrera     /// Get the type of the value.
255496237c2SNick Fitzgerald     pub fn ty(&self) -> WasmValType {
25614b39bc2SSaúl Cabrera         match self {
257496237c2SNick Fitzgerald             Val::I32(_) => WasmValType::I32,
258496237c2SNick Fitzgerald             Val::I64(_) => WasmValType::I64,
259496237c2SNick Fitzgerald             Val::F32(_) => WasmValType::F32,
260496237c2SNick Fitzgerald             Val::F64(_) => WasmValType::F64,
261fa9a948dSJeffrey Charles             Val::V128(_) => WasmValType::V128,
26214b39bc2SSaúl Cabrera             Val::Reg(r) => r.ty,
26314b39bc2SSaúl Cabrera             Val::Memory(m) => m.ty,
26414b39bc2SSaúl Cabrera             Val::Local(l) => l.ty,
26514b39bc2SSaúl Cabrera         }
26614b39bc2SSaúl Cabrera     }
267835abbcdSSaúl Cabrera }
268835abbcdSSaúl Cabrera 
269835abbcdSSaúl Cabrera /// The shadow stack used for compilation.
270835abbcdSSaúl Cabrera #[derive(Default, Debug)]
271835abbcdSSaúl Cabrera pub(crate) struct Stack {
2721b5c4ae8SSaúl Cabrera     // NB: The 64 is chosen arbitrarily. We can adjust as we see fit.
2731b5c4ae8SSaúl Cabrera     inner: SmallVec<[Val; 64]>,
274835abbcdSSaúl Cabrera }
275835abbcdSSaúl Cabrera 
276835abbcdSSaúl Cabrera impl Stack {
277835abbcdSSaúl Cabrera     /// Allocate a new stack.
278835abbcdSSaúl Cabrera     pub fn new() -> Self {
279835abbcdSSaúl Cabrera         Self {
280835abbcdSSaúl Cabrera             inner: Default::default(),
281835abbcdSSaúl Cabrera         }
282835abbcdSSaúl Cabrera     }
283835abbcdSSaúl Cabrera 
284321294a5SJeffrey Charles     /// Returns true if the stack contains a local with the provided index
285321294a5SJeffrey Charles     /// except if the only time the local appears is the top element.
286321294a5SJeffrey Charles     pub fn contains_latent_local(&self, index: u32) -> bool {
287321294a5SJeffrey Charles         self.inner
288321294a5SJeffrey Charles             .iter()
289321294a5SJeffrey Charles             // Iterate top-to-bottom so we can skip the top element and stop
290321294a5SJeffrey Charles             // when we see a memory element.
291321294a5SJeffrey Charles             .rev()
292321294a5SJeffrey Charles             // The local is not latent if it's the top element because the top
293321294a5SJeffrey Charles             // element will be popped next which materializes the local.
294321294a5SJeffrey Charles             .skip(1)
295321294a5SJeffrey Charles             // Stop when we see a memory element because that marks where we
296321294a5SJeffrey Charles             // spilled up to so there will not be any locals past this point.
297321294a5SJeffrey Charles             .take_while(|v| !v.is_mem())
298321294a5SJeffrey Charles             .any(|v| v.is_local_at_index(index))
299321294a5SJeffrey Charles     }
300321294a5SJeffrey Charles 
301a109d2abSSaúl Cabrera     /// Extend the stack with the given elements.
302a109d2abSSaúl Cabrera     pub fn extend(&mut self, values: impl IntoIterator<Item = Val>) {
303a109d2abSSaúl Cabrera         self.inner.extend(values);
304a109d2abSSaúl Cabrera     }
305a109d2abSSaúl Cabrera 
306a109d2abSSaúl Cabrera     /// Inserts many values at the given index.
3071b5c4ae8SSaúl Cabrera     pub fn insert_many(&mut self, at: usize, values: &[Val]) {
308a109d2abSSaúl Cabrera         debug_assert!(at <= self.len());
3091b5c4ae8SSaúl Cabrera 
3101b5c4ae8SSaúl Cabrera         if at == self.len() {
3111b5c4ae8SSaúl Cabrera             self.inner.extend_from_slice(values);
312a109d2abSSaúl Cabrera         } else {
3131b5c4ae8SSaúl Cabrera             self.inner.insert_from_slice(at, values);
314a109d2abSSaúl Cabrera         }
31520c58362SSaúl Cabrera     }
31620c58362SSaúl Cabrera 
317af4d94c8SSaúl Cabrera     /// Get the length of the stack.
318af4d94c8SSaúl Cabrera     pub fn len(&self) -> usize {
319af4d94c8SSaúl Cabrera         self.inner.len()
320af4d94c8SSaúl Cabrera     }
321af4d94c8SSaúl Cabrera 
322835abbcdSSaúl Cabrera     /// Push a value to the stack.
323835abbcdSSaúl Cabrera     pub fn push(&mut self, val: Val) {
3247690c500STrevor Elliott         self.inner.push(val);
325835abbcdSSaúl Cabrera     }
326835abbcdSSaúl Cabrera 
327835abbcdSSaúl Cabrera     /// Peek into the top in the stack.
3287c5c7e4bSSaúl Cabrera     pub fn peek(&self) -> Option<&Val> {
3297690c500STrevor Elliott         self.inner.last()
330835abbcdSSaúl Cabrera     }
331835abbcdSSaúl Cabrera 
332af4d94c8SSaúl Cabrera     /// Returns an iterator referencing the last n items of the stack,
333af4d94c8SSaúl Cabrera     /// in bottom-most to top-most order.
334af4d94c8SSaúl Cabrera     pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
335af4d94c8SSaúl Cabrera         let len = self.len();
336af4d94c8SSaúl Cabrera         assert!(n <= len);
337af4d94c8SSaúl Cabrera 
338af4d94c8SSaúl Cabrera         let partition = len - n;
3397690c500STrevor Elliott         self.inner[partition..].into_iter()
340af4d94c8SSaúl Cabrera     }
341af4d94c8SSaúl Cabrera 
342835abbcdSSaúl Cabrera     /// Pops the top element of the stack, if any.
343835abbcdSSaúl Cabrera     pub fn pop(&mut self) -> Option<Val> {
3447690c500STrevor Elliott         self.inner.pop()
345835abbcdSSaúl Cabrera     }
346835abbcdSSaúl Cabrera 
3477c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i32 const;
348835abbcdSSaúl Cabrera     /// returns `None` otherwise.
349835abbcdSSaúl Cabrera     pub fn pop_i32_const(&mut self) -> Option<i32> {
350835abbcdSSaúl Cabrera         match self.peek() {
351f0162a40SSaúl Cabrera             Some(v) => v.is_i32_const().then(|| self.pop().unwrap().unwrap_i32()),
352835abbcdSSaúl Cabrera             _ => None,
353835abbcdSSaúl Cabrera         }
354835abbcdSSaúl Cabrera     }
355835abbcdSSaúl Cabrera 
3567c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i64 const;
3577c5c7e4bSSaúl Cabrera     /// returns `None` otherwise.
3587c5c7e4bSSaúl Cabrera     pub fn pop_i64_const(&mut self) -> Option<i64> {
3597c5c7e4bSSaúl Cabrera         match self.peek() {
360f0162a40SSaúl Cabrera             Some(v) => v.is_i64_const().then(|| self.pop().unwrap().unwrap_i64()),
3617c5c7e4bSSaúl Cabrera             _ => None,
3627c5c7e4bSSaúl Cabrera         }
3637c5c7e4bSSaúl Cabrera     }
3647c5c7e4bSSaúl Cabrera 
365835abbcdSSaúl Cabrera     /// Pops the element at the top of the stack if it is a register;
366835abbcdSSaúl Cabrera     /// returns `None` otherwise.
36714b39bc2SSaúl Cabrera     pub fn pop_reg(&mut self) -> Option<TypedReg> {
368835abbcdSSaúl Cabrera         match self.peek() {
369f0162a40SSaúl Cabrera             Some(v) => v.is_reg().then(|| self.pop().unwrap().unwrap_reg()),
370835abbcdSSaúl Cabrera             _ => None,
371835abbcdSSaúl Cabrera         }
372835abbcdSSaúl Cabrera     }
373835abbcdSSaúl Cabrera 
374835abbcdSSaúl Cabrera     /// Pops the given register if it is at the top of the stack;
375835abbcdSSaúl Cabrera     /// returns `None` otherwise.
37614b39bc2SSaúl Cabrera     pub fn pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg> {
377835abbcdSSaúl Cabrera         match self.peek() {
37814b39bc2SSaúl Cabrera             Some(v) => {
379f0162a40SSaúl Cabrera                 (v.is_reg() && v.unwrap_reg().reg == reg).then(|| self.pop().unwrap().unwrap_reg())
38014b39bc2SSaúl Cabrera             }
381835abbcdSSaúl Cabrera             _ => None,
382835abbcdSSaúl Cabrera         }
383835abbcdSSaúl Cabrera     }
384835abbcdSSaúl Cabrera 
385835abbcdSSaúl Cabrera     /// Get a mutable reference to the inner stack representation.
3861b5c4ae8SSaúl Cabrera     pub fn inner_mut(&mut self) -> &mut SmallVec<[Val; 64]> {
387835abbcdSSaúl Cabrera         &mut self.inner
388835abbcdSSaúl Cabrera     }
38950733725SSaúl Cabrera 
390446a7f5eSSaúl Cabrera     /// Get a reference to the inner stack representation.
3911b5c4ae8SSaúl Cabrera     pub fn inner(&self) -> &SmallVec<[Val; 64]> {
392446a7f5eSSaúl Cabrera         &self.inner
393446a7f5eSSaúl Cabrera     }
394446a7f5eSSaúl Cabrera 
39550733725SSaúl Cabrera     /// Calculates the size of, in bytes, of the top n [Memory] entries
39650733725SSaúl Cabrera     /// in the value stack.
39750733725SSaúl Cabrera     pub fn sizeof(&self, top: usize) -> u32 {
39850733725SSaúl Cabrera         self.peekn(top).fold(0, |acc, v| {
39950733725SSaúl Cabrera             if v.is_mem() {
40050733725SSaúl Cabrera                 acc + v.unwrap_mem().slot.size
40150733725SSaúl Cabrera             } else {
40250733725SSaúl Cabrera                 acc
40350733725SSaúl Cabrera             }
40450733725SSaúl Cabrera         })
40550733725SSaúl Cabrera     }
406835abbcdSSaúl Cabrera }
407835abbcdSSaúl Cabrera 
408835abbcdSSaúl Cabrera #[cfg(test)]
409835abbcdSSaúl Cabrera mod tests {
410835abbcdSSaúl Cabrera     use super::{Stack, Val};
411835abbcdSSaúl Cabrera     use crate::isa::reg::Reg;
412496237c2SNick Fitzgerald     use wasmtime_environ::WasmValType;
413835abbcdSSaúl Cabrera 
414835abbcdSSaúl Cabrera     #[test]
415835abbcdSSaúl Cabrera     fn test_pop_i32_const() {
416835abbcdSSaúl Cabrera         let mut stack = Stack::new();
417835abbcdSSaúl Cabrera         stack.push(Val::i32(33i32));
418835abbcdSSaúl Cabrera         assert_eq!(33, stack.pop_i32_const().unwrap());
419835abbcdSSaúl Cabrera 
420496237c2SNick Fitzgerald         stack.push(Val::local(10, WasmValType::I32));
421835abbcdSSaúl Cabrera         assert!(stack.pop_i32_const().is_none());
422835abbcdSSaúl Cabrera     }
423835abbcdSSaúl Cabrera 
424835abbcdSSaúl Cabrera     #[test]
425835abbcdSSaúl Cabrera     fn test_pop_reg() {
426835abbcdSSaúl Cabrera         let mut stack = Stack::new();
427835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
428496237c2SNick Fitzgerald         stack.push(Val::reg(reg, WasmValType::I32));
429835abbcdSSaúl Cabrera         stack.push(Val::i32(4));
430835abbcdSSaúl Cabrera 
431835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_reg());
432835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
43314b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_reg().unwrap().reg);
434835abbcdSSaúl Cabrera     }
435835abbcdSSaúl Cabrera 
436835abbcdSSaúl Cabrera     #[test]
437835abbcdSSaúl Cabrera     fn test_pop_named_reg() {
438835abbcdSSaúl Cabrera         let mut stack = Stack::new();
439835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
440496237c2SNick Fitzgerald         stack.push(Val::reg(reg, WasmValType::I32));
441496237c2SNick Fitzgerald         stack.push(Val::reg(Reg::int(4), WasmValType::I32));
442835abbcdSSaúl Cabrera 
443835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_named_reg(reg));
444835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
44514b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_named_reg(reg).unwrap().reg);
446835abbcdSSaúl Cabrera     }
447835abbcdSSaúl Cabrera }
448