xref: /wasmtime-44.0.1/winch/codegen/src/stack.rs (revision 17091e6f)
114b39bc2SSaúl Cabrera use crate::{isa::reg::Reg, masm::StackSlot};
2835abbcdSSaúl Cabrera use std::collections::VecDeque;
314b39bc2SSaúl Cabrera use wasmparser::{Ieee32, Ieee64};
414b39bc2SSaúl Cabrera use wasmtime_environ::WasmType;
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.
1314b39bc2SSaúl Cabrera     pub ty: WasmType,
1414b39bc2SSaúl Cabrera }
1514b39bc2SSaúl Cabrera 
1614b39bc2SSaúl Cabrera impl TypedReg {
174b288ba8SSaúl Cabrera     /// Create a new [`TypedReg`].
1814b39bc2SSaúl Cabrera     pub fn new(ty: WasmType, 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 {
2514b39bc2SSaúl Cabrera             ty: WasmType::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 {
33a109d2abSSaúl Cabrera             ty: WasmType::I32,
34a109d2abSSaúl Cabrera             reg,
35a109d2abSSaúl Cabrera         }
36a109d2abSSaúl Cabrera     }
37*17091e6fSJeffrey Charles 
38*17091e6fSJeffrey Charles     /// Create an f64 [`TypedReg`].
39*17091e6fSJeffrey Charles     pub fn f64(reg: Reg) -> Self {
40*17091e6fSJeffrey Charles         Self {
41*17091e6fSJeffrey Charles             ty: WasmType::F64,
42*17091e6fSJeffrey Charles             reg,
43*17091e6fSJeffrey Charles         }
44*17091e6fSJeffrey Charles     }
45*17091e6fSJeffrey Charles 
46*17091e6fSJeffrey Charles     /// Create an f32 [`TypedReg`].
47*17091e6fSJeffrey Charles     pub fn f32(reg: Reg) -> Self {
48*17091e6fSJeffrey Charles         Self {
49*17091e6fSJeffrey Charles             ty: WasmType::F32,
50*17091e6fSJeffrey Charles             reg,
51*17091e6fSJeffrey Charles         }
52*17091e6fSJeffrey 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.
6714b39bc2SSaúl Cabrera     pub ty: WasmType,
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.
7414b39bc2SSaúl Cabrera     pub ty: WasmType,
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),
9014b39bc2SSaúl Cabrera     /// A register value.
9114b39bc2SSaúl Cabrera     Reg(TypedReg),
92835abbcdSSaúl Cabrera     /// A local slot.
9314b39bc2SSaúl Cabrera     Local(Local),
94835abbcdSSaúl Cabrera     /// Offset to a memory location.
9514b39bc2SSaúl Cabrera     Memory(Memory),
9614b39bc2SSaúl Cabrera }
9714b39bc2SSaúl Cabrera 
9814b39bc2SSaúl Cabrera impl From<TypedReg> for Val {
9914b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
10014b39bc2SSaúl Cabrera         Val::Reg(tr)
10114b39bc2SSaúl Cabrera     }
10214b39bc2SSaúl Cabrera }
10314b39bc2SSaúl Cabrera 
10414b39bc2SSaúl Cabrera impl From<Local> for Val {
10514b39bc2SSaúl Cabrera     fn from(local: Local) -> Self {
10614b39bc2SSaúl Cabrera         Val::Local(local)
10714b39bc2SSaúl Cabrera     }
10814b39bc2SSaúl Cabrera }
10914b39bc2SSaúl Cabrera 
11014b39bc2SSaúl Cabrera impl From<Memory> for Val {
11114b39bc2SSaúl Cabrera     fn from(mem: Memory) -> Self {
11214b39bc2SSaúl Cabrera         Val::Memory(mem)
11314b39bc2SSaúl Cabrera     }
114835abbcdSSaúl Cabrera }
115835abbcdSSaúl Cabrera 
1164b288ba8SSaúl Cabrera impl TryFrom<u32> for Val {
1174b288ba8SSaúl Cabrera     type Error = anyhow::Error;
1184b288ba8SSaúl Cabrera     fn try_from(value: u32) -> Result<Self, Self::Error> {
1194b288ba8SSaúl Cabrera         i32::try_from(value).map(Val::i32).map_err(Into::into)
1204b288ba8SSaúl Cabrera     }
1214b288ba8SSaúl Cabrera }
1224b288ba8SSaúl Cabrera 
123835abbcdSSaúl Cabrera impl Val {
124835abbcdSSaúl Cabrera     /// Create a new I32 constant value.
125835abbcdSSaúl Cabrera     pub fn i32(v: i32) -> Self {
126835abbcdSSaúl Cabrera         Self::I32(v)
127835abbcdSSaúl Cabrera     }
128835abbcdSSaúl Cabrera 
1297c5c7e4bSSaúl Cabrera     /// Create a new I64 constant value.
1307c5c7e4bSSaúl Cabrera     pub fn i64(v: i64) -> Self {
1317c5c7e4bSSaúl Cabrera         Self::I64(v)
1327c5c7e4bSSaúl Cabrera     }
1337c5c7e4bSSaúl Cabrera 
13414b39bc2SSaúl Cabrera     /// Create a new F32 constant value.
13514b39bc2SSaúl Cabrera     pub fn f32(v: Ieee32) -> Self {
13614b39bc2SSaúl Cabrera         Self::F32(v)
13714b39bc2SSaúl Cabrera     }
13814b39bc2SSaúl Cabrera 
13914b39bc2SSaúl Cabrera     pub fn f64(v: Ieee64) -> Self {
14014b39bc2SSaúl Cabrera         Self::F64(v)
14114b39bc2SSaúl Cabrera     }
14214b39bc2SSaúl Cabrera 
143835abbcdSSaúl Cabrera     /// Create a new Reg value.
14414b39bc2SSaúl Cabrera     pub fn reg(reg: Reg, ty: WasmType) -> Self {
14514b39bc2SSaúl Cabrera         Self::Reg(TypedReg { reg, ty })
146835abbcdSSaúl Cabrera     }
147835abbcdSSaúl Cabrera 
148835abbcdSSaúl Cabrera     /// Create a new Local value.
14914b39bc2SSaúl Cabrera     pub fn local(index: u32, ty: WasmType) -> Self {
15014b39bc2SSaúl Cabrera         Self::Local(Local { index, ty })
15114b39bc2SSaúl Cabrera     }
15214b39bc2SSaúl Cabrera 
15314b39bc2SSaúl Cabrera     /// Create a Memory value.
15414b39bc2SSaúl Cabrera     pub fn mem(ty: WasmType, slot: StackSlot) -> Self {
15514b39bc2SSaúl Cabrera         Self::Memory(Memory { ty, slot })
156835abbcdSSaúl Cabrera     }
157835abbcdSSaúl Cabrera 
158835abbcdSSaúl Cabrera     /// Check whether the value is a register.
159835abbcdSSaúl Cabrera     pub fn is_reg(&self) -> bool {
160835abbcdSSaúl Cabrera         match *self {
161835abbcdSSaúl Cabrera             Self::Reg(_) => true,
162835abbcdSSaúl Cabrera             _ => false,
163835abbcdSSaúl Cabrera         }
164835abbcdSSaúl Cabrera     }
165835abbcdSSaúl Cabrera 
166af4d94c8SSaúl Cabrera     /// Check wheter the value is a memory offset.
167af4d94c8SSaúl Cabrera     pub fn is_mem(&self) -> bool {
168af4d94c8SSaúl Cabrera         match *self {
169af4d94c8SSaúl Cabrera             Self::Memory(_) => true,
170af4d94c8SSaúl Cabrera             _ => false,
171af4d94c8SSaúl Cabrera         }
172af4d94c8SSaúl Cabrera     }
173af4d94c8SSaúl Cabrera 
17455f9a4bdSJeffrey Charles     /// Check whether the value is a constant.
17555f9a4bdSJeffrey Charles     pub fn is_const(&self) -> bool {
17655f9a4bdSJeffrey Charles         match *self {
17755f9a4bdSJeffrey Charles             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) => true,
17855f9a4bdSJeffrey Charles             _ => false,
17955f9a4bdSJeffrey Charles         }
18055f9a4bdSJeffrey Charles     }
18155f9a4bdSJeffrey Charles 
182321294a5SJeffrey Charles     /// Check whether the value is local with a particular index.
183321294a5SJeffrey Charles     pub fn is_local_at_index(&self, index: u32) -> bool {
184321294a5SJeffrey Charles         match *self {
185321294a5SJeffrey Charles             Self::Local(Local { index: i, .. }) if i == index => true,
186321294a5SJeffrey Charles             _ => false,
187321294a5SJeffrey Charles         }
188321294a5SJeffrey Charles     }
189321294a5SJeffrey Charles 
190835abbcdSSaúl Cabrera     /// Get the register representation of the value.
191835abbcdSSaúl Cabrera     ///
192835abbcdSSaúl Cabrera     /// # Panics
193835abbcdSSaúl Cabrera     /// This method will panic if the value is not a register.
194f0162a40SSaúl Cabrera     pub fn unwrap_reg(&self) -> TypedReg {
195835abbcdSSaúl Cabrera         match self {
19614b39bc2SSaúl Cabrera             Self::Reg(tr) => *tr,
197835abbcdSSaúl Cabrera             v => panic!("expected value {:?} to be a register", v),
198835abbcdSSaúl Cabrera         }
199835abbcdSSaúl Cabrera     }
200835abbcdSSaúl Cabrera 
201835abbcdSSaúl Cabrera     /// Get the integer representation of the value.
202835abbcdSSaúl Cabrera     ///
203835abbcdSSaúl Cabrera     /// # Panics
204835abbcdSSaúl Cabrera     /// This method will panic if the value is not an i32.
205f0162a40SSaúl Cabrera     pub fn unwrap_i32(&self) -> i32 {
206835abbcdSSaúl Cabrera         match self {
207835abbcdSSaúl Cabrera             Self::I32(v) => *v,
208835abbcdSSaúl Cabrera             v => panic!("expected value {:?} to be i32", v),
209835abbcdSSaúl Cabrera         }
210835abbcdSSaúl Cabrera     }
211835abbcdSSaúl Cabrera 
2127c5c7e4bSSaúl Cabrera     /// Get the integer representation of the value.
2137c5c7e4bSSaúl Cabrera     ///
2147c5c7e4bSSaúl Cabrera     /// # Panics
2157c5c7e4bSSaúl Cabrera     /// This method will panic if the value is not an i64.
216f0162a40SSaúl Cabrera     pub fn unwrap_i64(&self) -> i64 {
2177c5c7e4bSSaúl Cabrera         match self {
2187c5c7e4bSSaúl Cabrera             Self::I64(v) => *v,
2197c5c7e4bSSaúl Cabrera             v => panic!("expected value {:?} to be i64", v),
2207c5c7e4bSSaúl Cabrera         }
2217c5c7e4bSSaúl Cabrera     }
2227c5c7e4bSSaúl Cabrera 
223f0162a40SSaúl Cabrera     /// Returns the underlying memory value if it is one, panics otherwise.
224f0162a40SSaúl Cabrera     pub fn unwrap_mem(&self) -> Memory {
225f0162a40SSaúl Cabrera         match self {
226f0162a40SSaúl Cabrera             Self::Memory(m) => *m,
227f0162a40SSaúl Cabrera             v => panic!("expected value {:?} to be a Memory", v),
228f0162a40SSaúl Cabrera         }
229f0162a40SSaúl Cabrera     }
230f0162a40SSaúl Cabrera 
231835abbcdSSaúl Cabrera     /// Check whether the value is an i32 constant.
232835abbcdSSaúl Cabrera     pub fn is_i32_const(&self) -> bool {
233835abbcdSSaúl Cabrera         match *self {
234835abbcdSSaúl Cabrera             Self::I32(_) => true,
235835abbcdSSaúl Cabrera             _ => false,
236835abbcdSSaúl Cabrera         }
237835abbcdSSaúl Cabrera     }
2387c5c7e4bSSaúl Cabrera 
2397c5c7e4bSSaúl Cabrera     /// Check whether the value is an i64 constant.
2407c5c7e4bSSaúl Cabrera     pub fn is_i64_const(&self) -> bool {
2417c5c7e4bSSaúl Cabrera         match *self {
2427c5c7e4bSSaúl Cabrera             Self::I64(_) => true,
2437c5c7e4bSSaúl Cabrera             _ => false,
2447c5c7e4bSSaúl Cabrera         }
2457c5c7e4bSSaúl Cabrera     }
24614b39bc2SSaúl Cabrera 
24714b39bc2SSaúl Cabrera     /// Get the type of the value.
24814b39bc2SSaúl Cabrera     pub fn ty(&self) -> WasmType {
24914b39bc2SSaúl Cabrera         match self {
25014b39bc2SSaúl Cabrera             Val::I32(_) => WasmType::I32,
25114b39bc2SSaúl Cabrera             Val::I64(_) => WasmType::I64,
25214b39bc2SSaúl Cabrera             Val::F32(_) => WasmType::F32,
25314b39bc2SSaúl Cabrera             Val::F64(_) => WasmType::F64,
25414b39bc2SSaúl Cabrera             Val::Reg(r) => r.ty,
25514b39bc2SSaúl Cabrera             Val::Memory(m) => m.ty,
25614b39bc2SSaúl Cabrera             Val::Local(l) => l.ty,
25714b39bc2SSaúl Cabrera         }
25814b39bc2SSaúl Cabrera     }
259835abbcdSSaúl Cabrera }
260835abbcdSSaúl Cabrera 
261835abbcdSSaúl Cabrera /// The shadow stack used for compilation.
262835abbcdSSaúl Cabrera #[derive(Default, Debug)]
263835abbcdSSaúl Cabrera pub(crate) struct Stack {
264835abbcdSSaúl Cabrera     inner: VecDeque<Val>,
265835abbcdSSaúl Cabrera }
266835abbcdSSaúl Cabrera 
267835abbcdSSaúl Cabrera impl Stack {
268835abbcdSSaúl Cabrera     /// Allocate a new stack.
269835abbcdSSaúl Cabrera     pub fn new() -> Self {
270835abbcdSSaúl Cabrera         Self {
271835abbcdSSaúl Cabrera             inner: Default::default(),
272835abbcdSSaúl Cabrera         }
273835abbcdSSaúl Cabrera     }
274835abbcdSSaúl Cabrera 
275321294a5SJeffrey Charles     /// Returns true if the stack contains a local with the provided index
276321294a5SJeffrey Charles     /// except if the only time the local appears is the top element.
277321294a5SJeffrey Charles     pub fn contains_latent_local(&self, index: u32) -> bool {
278321294a5SJeffrey Charles         self.inner
279321294a5SJeffrey Charles             .iter()
280321294a5SJeffrey Charles             // Iterate top-to-bottom so we can skip the top element and stop
281321294a5SJeffrey Charles             // when we see a memory element.
282321294a5SJeffrey Charles             .rev()
283321294a5SJeffrey Charles             // The local is not latent if it's the top element because the top
284321294a5SJeffrey Charles             // element will be popped next which materializes the local.
285321294a5SJeffrey Charles             .skip(1)
286321294a5SJeffrey Charles             // Stop when we see a memory element because that marks where we
287321294a5SJeffrey Charles             // spilled up to so there will not be any locals past this point.
288321294a5SJeffrey Charles             .take_while(|v| !v.is_mem())
289321294a5SJeffrey Charles             .any(|v| v.is_local_at_index(index))
290321294a5SJeffrey Charles     }
291321294a5SJeffrey Charles 
292a109d2abSSaúl Cabrera     /// Extend the stack with the given elements.
293a109d2abSSaúl Cabrera     pub fn extend(&mut self, values: impl IntoIterator<Item = Val>) {
294a109d2abSSaúl Cabrera         self.inner.extend(values);
295a109d2abSSaúl Cabrera     }
296a109d2abSSaúl Cabrera 
297a109d2abSSaúl Cabrera     /// Inserts many values at the given index.
298a109d2abSSaúl Cabrera     pub fn insert_many(&mut self, at: usize, values: impl IntoIterator<Item = Val>) {
299a109d2abSSaúl Cabrera         debug_assert!(at <= self.len());
300a109d2abSSaúl Cabrera         // If last, simply extend.
301a109d2abSSaúl Cabrera         if at == self.inner.len() {
302a109d2abSSaúl Cabrera             self.inner.extend(values);
303a109d2abSSaúl Cabrera         } else {
304a109d2abSSaúl Cabrera             let mut tail = self.inner.split_off(at);
305a109d2abSSaúl Cabrera             self.inner.extend(values);
306a109d2abSSaúl Cabrera             self.inner.append(&mut tail);
307a109d2abSSaúl Cabrera         }
30820c58362SSaúl Cabrera     }
30920c58362SSaúl Cabrera 
310af4d94c8SSaúl Cabrera     /// Get the length of the stack.
311af4d94c8SSaúl Cabrera     pub fn len(&self) -> usize {
312af4d94c8SSaúl Cabrera         self.inner.len()
313af4d94c8SSaúl Cabrera     }
314af4d94c8SSaúl Cabrera 
315835abbcdSSaúl Cabrera     /// Push a value to the stack.
316835abbcdSSaúl Cabrera     pub fn push(&mut self, val: Val) {
317835abbcdSSaúl Cabrera         self.inner.push_back(val);
318835abbcdSSaúl Cabrera     }
319835abbcdSSaúl Cabrera 
320835abbcdSSaúl Cabrera     /// Peek into the top in the stack.
3217c5c7e4bSSaúl Cabrera     pub fn peek(&self) -> Option<&Val> {
322835abbcdSSaúl Cabrera         self.inner.back()
323835abbcdSSaúl Cabrera     }
324835abbcdSSaúl Cabrera 
325af4d94c8SSaúl Cabrera     /// Returns an iterator referencing the last n items of the stack,
326af4d94c8SSaúl Cabrera     /// in bottom-most to top-most order.
327af4d94c8SSaúl Cabrera     pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
328af4d94c8SSaúl Cabrera         let len = self.len();
329af4d94c8SSaúl Cabrera         assert!(n <= len);
330af4d94c8SSaúl Cabrera 
331af4d94c8SSaúl Cabrera         let partition = len - n;
332af4d94c8SSaúl Cabrera         self.inner.range(partition..)
333af4d94c8SSaúl Cabrera     }
334af4d94c8SSaúl Cabrera 
335f0162a40SSaúl Cabrera     /// Duplicates the top `n` elements of the stack.
336f0162a40SSaúl Cabrera     // Will be needed for control flow, it's just not integrated yet.
337f0162a40SSaúl Cabrera     #[allow(dead_code)]
338f0162a40SSaúl Cabrera     pub fn dup(&mut self, n: usize) {
339f0162a40SSaúl Cabrera         let len = self.len();
340f0162a40SSaúl Cabrera         assert!(n <= len);
341f0162a40SSaúl Cabrera         let partition = len - n;
342f0162a40SSaúl Cabrera 
343f0162a40SSaúl Cabrera         if n > 0 {
344f0162a40SSaúl Cabrera             for e in partition..len {
345f0162a40SSaúl Cabrera                 if let Some(v) = self.inner.get(e) {
346f0162a40SSaúl Cabrera                     self.push(*v)
347f0162a40SSaúl Cabrera                 }
348f0162a40SSaúl Cabrera             }
349f0162a40SSaúl Cabrera         }
350f0162a40SSaúl Cabrera     }
351f0162a40SSaúl Cabrera 
352835abbcdSSaúl Cabrera     /// Pops the top element of the stack, if any.
353835abbcdSSaúl Cabrera     pub fn pop(&mut self) -> Option<Val> {
354835abbcdSSaúl Cabrera         self.inner.pop_back()
355835abbcdSSaúl Cabrera     }
356835abbcdSSaúl Cabrera 
3577c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i32 const;
358835abbcdSSaúl Cabrera     /// returns `None` otherwise.
359835abbcdSSaúl Cabrera     pub fn pop_i32_const(&mut self) -> Option<i32> {
360835abbcdSSaúl Cabrera         match self.peek() {
361f0162a40SSaúl Cabrera             Some(v) => v.is_i32_const().then(|| self.pop().unwrap().unwrap_i32()),
362835abbcdSSaúl Cabrera             _ => None,
363835abbcdSSaúl Cabrera         }
364835abbcdSSaúl Cabrera     }
365835abbcdSSaúl Cabrera 
3667c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i64 const;
3677c5c7e4bSSaúl Cabrera     /// returns `None` otherwise.
3687c5c7e4bSSaúl Cabrera     pub fn pop_i64_const(&mut self) -> Option<i64> {
3697c5c7e4bSSaúl Cabrera         match self.peek() {
370f0162a40SSaúl Cabrera             Some(v) => v.is_i64_const().then(|| self.pop().unwrap().unwrap_i64()),
3717c5c7e4bSSaúl Cabrera             _ => None,
3727c5c7e4bSSaúl Cabrera         }
3737c5c7e4bSSaúl Cabrera     }
3747c5c7e4bSSaúl Cabrera 
375835abbcdSSaúl Cabrera     /// Pops the element at the top of the stack if it is a register;
376835abbcdSSaúl Cabrera     /// returns `None` otherwise.
37714b39bc2SSaúl Cabrera     pub fn pop_reg(&mut self) -> Option<TypedReg> {
378835abbcdSSaúl Cabrera         match self.peek() {
379f0162a40SSaúl Cabrera             Some(v) => v.is_reg().then(|| self.pop().unwrap().unwrap_reg()),
380835abbcdSSaúl Cabrera             _ => None,
381835abbcdSSaúl Cabrera         }
382835abbcdSSaúl Cabrera     }
383835abbcdSSaúl Cabrera 
384835abbcdSSaúl Cabrera     /// Pops the given register if it is at the top of the stack;
385835abbcdSSaúl Cabrera     /// returns `None` otherwise.
38614b39bc2SSaúl Cabrera     pub fn pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg> {
387835abbcdSSaúl Cabrera         match self.peek() {
38814b39bc2SSaúl Cabrera             Some(v) => {
389f0162a40SSaúl Cabrera                 (v.is_reg() && v.unwrap_reg().reg == reg).then(|| self.pop().unwrap().unwrap_reg())
39014b39bc2SSaúl Cabrera             }
391835abbcdSSaúl Cabrera             _ => None,
392835abbcdSSaúl Cabrera         }
393835abbcdSSaúl Cabrera     }
394835abbcdSSaúl Cabrera 
395835abbcdSSaúl Cabrera     /// Get a mutable reference to the inner stack representation.
396835abbcdSSaúl Cabrera     pub fn inner_mut(&mut self) -> &mut VecDeque<Val> {
397835abbcdSSaúl Cabrera         &mut self.inner
398835abbcdSSaúl Cabrera     }
39950733725SSaúl Cabrera 
40050733725SSaúl Cabrera     /// Calculates the size of, in bytes, of the top n [Memory] entries
40150733725SSaúl Cabrera     /// in the value stack.
40250733725SSaúl Cabrera     pub fn sizeof(&self, top: usize) -> u32 {
40350733725SSaúl Cabrera         self.peekn(top).fold(0, |acc, v| {
40450733725SSaúl Cabrera             if v.is_mem() {
40550733725SSaúl Cabrera                 acc + v.unwrap_mem().slot.size
40650733725SSaúl Cabrera             } else {
40750733725SSaúl Cabrera                 acc
40850733725SSaúl Cabrera             }
40950733725SSaúl Cabrera         })
41050733725SSaúl Cabrera     }
411835abbcdSSaúl Cabrera }
412835abbcdSSaúl Cabrera 
413835abbcdSSaúl Cabrera #[cfg(test)]
414835abbcdSSaúl Cabrera mod tests {
415835abbcdSSaúl Cabrera     use super::{Stack, Val};
416835abbcdSSaúl Cabrera     use crate::isa::reg::Reg;
41714b39bc2SSaúl Cabrera     use wasmtime_environ::WasmType;
418835abbcdSSaúl Cabrera 
419835abbcdSSaúl Cabrera     #[test]
420835abbcdSSaúl Cabrera     fn test_pop_i32_const() {
421835abbcdSSaúl Cabrera         let mut stack = Stack::new();
422835abbcdSSaúl Cabrera         stack.push(Val::i32(33i32));
423835abbcdSSaúl Cabrera         assert_eq!(33, stack.pop_i32_const().unwrap());
424835abbcdSSaúl Cabrera 
42514b39bc2SSaúl Cabrera         stack.push(Val::local(10, WasmType::I32));
426835abbcdSSaúl Cabrera         assert!(stack.pop_i32_const().is_none());
427835abbcdSSaúl Cabrera     }
428835abbcdSSaúl Cabrera 
429835abbcdSSaúl Cabrera     #[test]
430835abbcdSSaúl Cabrera     fn test_pop_reg() {
431835abbcdSSaúl Cabrera         let mut stack = Stack::new();
432835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
43314b39bc2SSaúl Cabrera         stack.push(Val::reg(reg, WasmType::I32));
434835abbcdSSaúl Cabrera         stack.push(Val::i32(4));
435835abbcdSSaúl Cabrera 
436835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_reg());
437835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
43814b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_reg().unwrap().reg);
439835abbcdSSaúl Cabrera     }
440835abbcdSSaúl Cabrera 
441835abbcdSSaúl Cabrera     #[test]
442835abbcdSSaúl Cabrera     fn test_pop_named_reg() {
443835abbcdSSaúl Cabrera         let mut stack = Stack::new();
444835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
44514b39bc2SSaúl Cabrera         stack.push(Val::reg(reg, WasmType::I32));
44614b39bc2SSaúl Cabrera         stack.push(Val::reg(Reg::int(4), WasmType::I32));
447835abbcdSSaúl Cabrera 
448835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_named_reg(reg));
449835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
45014b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_named_reg(reg).unwrap().reg);
451835abbcdSSaúl Cabrera     }
452835abbcdSSaúl Cabrera }
453