xref: /wasmtime-44.0.1/winch/codegen/src/stack.rs (revision 55f9a4bd)
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     }
3714b39bc2SSaúl Cabrera }
3814b39bc2SSaúl Cabrera 
3914b39bc2SSaúl Cabrera impl From<TypedReg> for Reg {
4014b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
4114b39bc2SSaúl Cabrera         tr.reg
4214b39bc2SSaúl Cabrera     }
4314b39bc2SSaúl Cabrera }
4414b39bc2SSaúl Cabrera 
4514b39bc2SSaúl Cabrera /// A local value.
4614b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
4714b39bc2SSaúl Cabrera pub struct Local {
4814b39bc2SSaúl Cabrera     /// The index of the local.
4914b39bc2SSaúl Cabrera     pub index: u32,
5014b39bc2SSaúl Cabrera     /// The type of the local.
5114b39bc2SSaúl Cabrera     pub ty: WasmType,
5214b39bc2SSaúl Cabrera }
5314b39bc2SSaúl Cabrera 
5414b39bc2SSaúl Cabrera /// A memory value.
5514b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
5614b39bc2SSaúl Cabrera pub struct Memory {
5714b39bc2SSaúl Cabrera     /// The type associated with the memory offset.
5814b39bc2SSaúl Cabrera     pub ty: WasmType,
5914b39bc2SSaúl Cabrera     /// The stack slot corresponding to the memory value.
6014b39bc2SSaúl Cabrera     pub slot: StackSlot,
6114b39bc2SSaúl Cabrera }
62835abbcdSSaúl Cabrera 
63835abbcdSSaúl Cabrera /// Value definition to be used within the shadow stack.
64a50c4972SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
65835abbcdSSaúl Cabrera pub(crate) enum Val {
66835abbcdSSaúl Cabrera     /// I32 Constant.
67835abbcdSSaúl Cabrera     I32(i32),
687c5c7e4bSSaúl Cabrera     /// I64 Constant.
697c5c7e4bSSaúl Cabrera     I64(i64),
7014b39bc2SSaúl Cabrera     /// F32 Constant.
7114b39bc2SSaúl Cabrera     F32(Ieee32),
7214b39bc2SSaúl Cabrera     /// F64 Constant.
7314b39bc2SSaúl Cabrera     F64(Ieee64),
7414b39bc2SSaúl Cabrera     /// A register value.
7514b39bc2SSaúl Cabrera     Reg(TypedReg),
76835abbcdSSaúl Cabrera     /// A local slot.
7714b39bc2SSaúl Cabrera     Local(Local),
78835abbcdSSaúl Cabrera     /// Offset to a memory location.
7914b39bc2SSaúl Cabrera     Memory(Memory),
8014b39bc2SSaúl Cabrera }
8114b39bc2SSaúl Cabrera 
8214b39bc2SSaúl Cabrera impl From<TypedReg> for Val {
8314b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
8414b39bc2SSaúl Cabrera         Val::Reg(tr)
8514b39bc2SSaúl Cabrera     }
8614b39bc2SSaúl Cabrera }
8714b39bc2SSaúl Cabrera 
8814b39bc2SSaúl Cabrera impl From<Local> for Val {
8914b39bc2SSaúl Cabrera     fn from(local: Local) -> Self {
9014b39bc2SSaúl Cabrera         Val::Local(local)
9114b39bc2SSaúl Cabrera     }
9214b39bc2SSaúl Cabrera }
9314b39bc2SSaúl Cabrera 
9414b39bc2SSaúl Cabrera impl From<Memory> for Val {
9514b39bc2SSaúl Cabrera     fn from(mem: Memory) -> Self {
9614b39bc2SSaúl Cabrera         Val::Memory(mem)
9714b39bc2SSaúl Cabrera     }
98835abbcdSSaúl Cabrera }
99835abbcdSSaúl Cabrera 
1004b288ba8SSaúl Cabrera impl TryFrom<u32> for Val {
1014b288ba8SSaúl Cabrera     type Error = anyhow::Error;
1024b288ba8SSaúl Cabrera     fn try_from(value: u32) -> Result<Self, Self::Error> {
1034b288ba8SSaúl Cabrera         i32::try_from(value).map(Val::i32).map_err(Into::into)
1044b288ba8SSaúl Cabrera     }
1054b288ba8SSaúl Cabrera }
1064b288ba8SSaúl Cabrera 
107835abbcdSSaúl Cabrera impl Val {
108835abbcdSSaúl Cabrera     /// Create a new I32 constant value.
109835abbcdSSaúl Cabrera     pub fn i32(v: i32) -> Self {
110835abbcdSSaúl Cabrera         Self::I32(v)
111835abbcdSSaúl Cabrera     }
112835abbcdSSaúl Cabrera 
1137c5c7e4bSSaúl Cabrera     /// Create a new I64 constant value.
1147c5c7e4bSSaúl Cabrera     pub fn i64(v: i64) -> Self {
1157c5c7e4bSSaúl Cabrera         Self::I64(v)
1167c5c7e4bSSaúl Cabrera     }
1177c5c7e4bSSaúl Cabrera 
11814b39bc2SSaúl Cabrera     /// Create a new F32 constant value.
11914b39bc2SSaúl Cabrera     pub fn f32(v: Ieee32) -> Self {
12014b39bc2SSaúl Cabrera         Self::F32(v)
12114b39bc2SSaúl Cabrera     }
12214b39bc2SSaúl Cabrera 
12314b39bc2SSaúl Cabrera     pub fn f64(v: Ieee64) -> Self {
12414b39bc2SSaúl Cabrera         Self::F64(v)
12514b39bc2SSaúl Cabrera     }
12614b39bc2SSaúl Cabrera 
127835abbcdSSaúl Cabrera     /// Create a new Reg value.
12814b39bc2SSaúl Cabrera     pub fn reg(reg: Reg, ty: WasmType) -> Self {
12914b39bc2SSaúl Cabrera         Self::Reg(TypedReg { reg, ty })
130835abbcdSSaúl Cabrera     }
131835abbcdSSaúl Cabrera 
132835abbcdSSaúl Cabrera     /// Create a new Local value.
13314b39bc2SSaúl Cabrera     pub fn local(index: u32, ty: WasmType) -> Self {
13414b39bc2SSaúl Cabrera         Self::Local(Local { index, ty })
13514b39bc2SSaúl Cabrera     }
13614b39bc2SSaúl Cabrera 
13714b39bc2SSaúl Cabrera     /// Create a Memory value.
13814b39bc2SSaúl Cabrera     pub fn mem(ty: WasmType, slot: StackSlot) -> Self {
13914b39bc2SSaúl Cabrera         Self::Memory(Memory { ty, slot })
140835abbcdSSaúl Cabrera     }
141835abbcdSSaúl Cabrera 
142835abbcdSSaúl Cabrera     /// Check whether the value is a register.
143835abbcdSSaúl Cabrera     pub fn is_reg(&self) -> bool {
144835abbcdSSaúl Cabrera         match *self {
145835abbcdSSaúl Cabrera             Self::Reg(_) => true,
146835abbcdSSaúl Cabrera             _ => false,
147835abbcdSSaúl Cabrera         }
148835abbcdSSaúl Cabrera     }
149835abbcdSSaúl Cabrera 
150af4d94c8SSaúl Cabrera     /// Check wheter the value is a memory offset.
151af4d94c8SSaúl Cabrera     pub fn is_mem(&self) -> bool {
152af4d94c8SSaúl Cabrera         match *self {
153af4d94c8SSaúl Cabrera             Self::Memory(_) => true,
154af4d94c8SSaúl Cabrera             _ => false,
155af4d94c8SSaúl Cabrera         }
156af4d94c8SSaúl Cabrera     }
157af4d94c8SSaúl Cabrera 
158*55f9a4bdSJeffrey Charles     /// Check whether the value is a constant.
159*55f9a4bdSJeffrey Charles     pub fn is_const(&self) -> bool {
160*55f9a4bdSJeffrey Charles         match *self {
161*55f9a4bdSJeffrey Charles             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) => true,
162*55f9a4bdSJeffrey Charles             _ => false,
163*55f9a4bdSJeffrey Charles         }
164*55f9a4bdSJeffrey Charles     }
165*55f9a4bdSJeffrey Charles 
166321294a5SJeffrey Charles     /// Check whether the value is local with a particular index.
167321294a5SJeffrey Charles     pub fn is_local_at_index(&self, index: u32) -> bool {
168321294a5SJeffrey Charles         match *self {
169321294a5SJeffrey Charles             Self::Local(Local { index: i, .. }) if i == index => true,
170321294a5SJeffrey Charles             _ => false,
171321294a5SJeffrey Charles         }
172321294a5SJeffrey Charles     }
173321294a5SJeffrey Charles 
174835abbcdSSaúl Cabrera     /// Get the register representation of the value.
175835abbcdSSaúl Cabrera     ///
176835abbcdSSaúl Cabrera     /// # Panics
177835abbcdSSaúl Cabrera     /// This method will panic if the value is not a register.
178f0162a40SSaúl Cabrera     pub fn unwrap_reg(&self) -> TypedReg {
179835abbcdSSaúl Cabrera         match self {
18014b39bc2SSaúl Cabrera             Self::Reg(tr) => *tr,
181835abbcdSSaúl Cabrera             v => panic!("expected value {:?} to be a register", v),
182835abbcdSSaúl Cabrera         }
183835abbcdSSaúl Cabrera     }
184835abbcdSSaúl Cabrera 
185835abbcdSSaúl Cabrera     /// Get the integer representation of the value.
186835abbcdSSaúl Cabrera     ///
187835abbcdSSaúl Cabrera     /// # Panics
188835abbcdSSaúl Cabrera     /// This method will panic if the value is not an i32.
189f0162a40SSaúl Cabrera     pub fn unwrap_i32(&self) -> i32 {
190835abbcdSSaúl Cabrera         match self {
191835abbcdSSaúl Cabrera             Self::I32(v) => *v,
192835abbcdSSaúl Cabrera             v => panic!("expected value {:?} to be i32", v),
193835abbcdSSaúl Cabrera         }
194835abbcdSSaúl Cabrera     }
195835abbcdSSaúl Cabrera 
1967c5c7e4bSSaúl Cabrera     /// Get the integer representation of the value.
1977c5c7e4bSSaúl Cabrera     ///
1987c5c7e4bSSaúl Cabrera     /// # Panics
1997c5c7e4bSSaúl Cabrera     /// This method will panic if the value is not an i64.
200f0162a40SSaúl Cabrera     pub fn unwrap_i64(&self) -> i64 {
2017c5c7e4bSSaúl Cabrera         match self {
2027c5c7e4bSSaúl Cabrera             Self::I64(v) => *v,
2037c5c7e4bSSaúl Cabrera             v => panic!("expected value {:?} to be i64", v),
2047c5c7e4bSSaúl Cabrera         }
2057c5c7e4bSSaúl Cabrera     }
2067c5c7e4bSSaúl Cabrera 
207f0162a40SSaúl Cabrera     /// Returns the underlying memory value if it is one, panics otherwise.
208f0162a40SSaúl Cabrera     pub fn unwrap_mem(&self) -> Memory {
209f0162a40SSaúl Cabrera         match self {
210f0162a40SSaúl Cabrera             Self::Memory(m) => *m,
211f0162a40SSaúl Cabrera             v => panic!("expected value {:?} to be a Memory", v),
212f0162a40SSaúl Cabrera         }
213f0162a40SSaúl Cabrera     }
214f0162a40SSaúl Cabrera 
215835abbcdSSaúl Cabrera     /// Check whether the value is an i32 constant.
216835abbcdSSaúl Cabrera     pub fn is_i32_const(&self) -> bool {
217835abbcdSSaúl Cabrera         match *self {
218835abbcdSSaúl Cabrera             Self::I32(_) => true,
219835abbcdSSaúl Cabrera             _ => false,
220835abbcdSSaúl Cabrera         }
221835abbcdSSaúl Cabrera     }
2227c5c7e4bSSaúl Cabrera 
2237c5c7e4bSSaúl Cabrera     /// Check whether the value is an i64 constant.
2247c5c7e4bSSaúl Cabrera     pub fn is_i64_const(&self) -> bool {
2257c5c7e4bSSaúl Cabrera         match *self {
2267c5c7e4bSSaúl Cabrera             Self::I64(_) => true,
2277c5c7e4bSSaúl Cabrera             _ => false,
2287c5c7e4bSSaúl Cabrera         }
2297c5c7e4bSSaúl Cabrera     }
23014b39bc2SSaúl Cabrera 
23114b39bc2SSaúl Cabrera     /// Get the type of the value.
23214b39bc2SSaúl Cabrera     pub fn ty(&self) -> WasmType {
23314b39bc2SSaúl Cabrera         match self {
23414b39bc2SSaúl Cabrera             Val::I32(_) => WasmType::I32,
23514b39bc2SSaúl Cabrera             Val::I64(_) => WasmType::I64,
23614b39bc2SSaúl Cabrera             Val::F32(_) => WasmType::F32,
23714b39bc2SSaúl Cabrera             Val::F64(_) => WasmType::F64,
23814b39bc2SSaúl Cabrera             Val::Reg(r) => r.ty,
23914b39bc2SSaúl Cabrera             Val::Memory(m) => m.ty,
24014b39bc2SSaúl Cabrera             Val::Local(l) => l.ty,
24114b39bc2SSaúl Cabrera         }
24214b39bc2SSaúl Cabrera     }
243835abbcdSSaúl Cabrera }
244835abbcdSSaúl Cabrera 
245835abbcdSSaúl Cabrera /// The shadow stack used for compilation.
246835abbcdSSaúl Cabrera #[derive(Default, Debug)]
247835abbcdSSaúl Cabrera pub(crate) struct Stack {
248835abbcdSSaúl Cabrera     inner: VecDeque<Val>,
249835abbcdSSaúl Cabrera }
250835abbcdSSaúl Cabrera 
251835abbcdSSaúl Cabrera impl Stack {
252835abbcdSSaúl Cabrera     /// Allocate a new stack.
253835abbcdSSaúl Cabrera     pub fn new() -> Self {
254835abbcdSSaúl Cabrera         Self {
255835abbcdSSaúl Cabrera             inner: Default::default(),
256835abbcdSSaúl Cabrera         }
257835abbcdSSaúl Cabrera     }
258835abbcdSSaúl Cabrera 
259321294a5SJeffrey Charles     /// Returns true if the stack contains a local with the provided index
260321294a5SJeffrey Charles     /// except if the only time the local appears is the top element.
261321294a5SJeffrey Charles     pub fn contains_latent_local(&self, index: u32) -> bool {
262321294a5SJeffrey Charles         self.inner
263321294a5SJeffrey Charles             .iter()
264321294a5SJeffrey Charles             // Iterate top-to-bottom so we can skip the top element and stop
265321294a5SJeffrey Charles             // when we see a memory element.
266321294a5SJeffrey Charles             .rev()
267321294a5SJeffrey Charles             // The local is not latent if it's the top element because the top
268321294a5SJeffrey Charles             // element will be popped next which materializes the local.
269321294a5SJeffrey Charles             .skip(1)
270321294a5SJeffrey Charles             // Stop when we see a memory element because that marks where we
271321294a5SJeffrey Charles             // spilled up to so there will not be any locals past this point.
272321294a5SJeffrey Charles             .take_while(|v| !v.is_mem())
273321294a5SJeffrey Charles             .any(|v| v.is_local_at_index(index))
274321294a5SJeffrey Charles     }
275321294a5SJeffrey Charles 
276a109d2abSSaúl Cabrera     /// Extend the stack with the given elements.
277a109d2abSSaúl Cabrera     pub fn extend(&mut self, values: impl IntoIterator<Item = Val>) {
278a109d2abSSaúl Cabrera         self.inner.extend(values);
279a109d2abSSaúl Cabrera     }
280a109d2abSSaúl Cabrera 
281a109d2abSSaúl Cabrera     /// Inserts many values at the given index.
282a109d2abSSaúl Cabrera     pub fn insert_many(&mut self, at: usize, values: impl IntoIterator<Item = Val>) {
283a109d2abSSaúl Cabrera         debug_assert!(at <= self.len());
284a109d2abSSaúl Cabrera         // If last, simply extend.
285a109d2abSSaúl Cabrera         if at == self.inner.len() {
286a109d2abSSaúl Cabrera             self.inner.extend(values);
287a109d2abSSaúl Cabrera         } else {
288a109d2abSSaúl Cabrera             let mut tail = self.inner.split_off(at);
289a109d2abSSaúl Cabrera             self.inner.extend(values);
290a109d2abSSaúl Cabrera             self.inner.append(&mut tail);
291a109d2abSSaúl Cabrera         }
29220c58362SSaúl Cabrera     }
29320c58362SSaúl Cabrera 
294af4d94c8SSaúl Cabrera     /// Get the length of the stack.
295af4d94c8SSaúl Cabrera     pub fn len(&self) -> usize {
296af4d94c8SSaúl Cabrera         self.inner.len()
297af4d94c8SSaúl Cabrera     }
298af4d94c8SSaúl Cabrera 
299835abbcdSSaúl Cabrera     /// Push a value to the stack.
300835abbcdSSaúl Cabrera     pub fn push(&mut self, val: Val) {
301835abbcdSSaúl Cabrera         self.inner.push_back(val);
302835abbcdSSaúl Cabrera     }
303835abbcdSSaúl Cabrera 
304835abbcdSSaúl Cabrera     /// Peek into the top in the stack.
3057c5c7e4bSSaúl Cabrera     pub fn peek(&self) -> Option<&Val> {
306835abbcdSSaúl Cabrera         self.inner.back()
307835abbcdSSaúl Cabrera     }
308835abbcdSSaúl Cabrera 
309af4d94c8SSaúl Cabrera     /// Returns an iterator referencing the last n items of the stack,
310af4d94c8SSaúl Cabrera     /// in bottom-most to top-most order.
311af4d94c8SSaúl Cabrera     pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
312af4d94c8SSaúl Cabrera         let len = self.len();
313af4d94c8SSaúl Cabrera         assert!(n <= len);
314af4d94c8SSaúl Cabrera 
315af4d94c8SSaúl Cabrera         let partition = len - n;
316af4d94c8SSaúl Cabrera         self.inner.range(partition..)
317af4d94c8SSaúl Cabrera     }
318af4d94c8SSaúl Cabrera 
319f0162a40SSaúl Cabrera     /// Duplicates the top `n` elements of the stack.
320f0162a40SSaúl Cabrera     // Will be needed for control flow, it's just not integrated yet.
321f0162a40SSaúl Cabrera     #[allow(dead_code)]
322f0162a40SSaúl Cabrera     pub fn dup(&mut self, n: usize) {
323f0162a40SSaúl Cabrera         let len = self.len();
324f0162a40SSaúl Cabrera         assert!(n <= len);
325f0162a40SSaúl Cabrera         let partition = len - n;
326f0162a40SSaúl Cabrera 
327f0162a40SSaúl Cabrera         if n > 0 {
328f0162a40SSaúl Cabrera             for e in partition..len {
329f0162a40SSaúl Cabrera                 if let Some(v) = self.inner.get(e) {
330f0162a40SSaúl Cabrera                     self.push(*v)
331f0162a40SSaúl Cabrera                 }
332f0162a40SSaúl Cabrera             }
333f0162a40SSaúl Cabrera         }
334f0162a40SSaúl Cabrera     }
335f0162a40SSaúl Cabrera 
336835abbcdSSaúl Cabrera     /// Pops the top element of the stack, if any.
337835abbcdSSaúl Cabrera     pub fn pop(&mut self) -> Option<Val> {
338835abbcdSSaúl Cabrera         self.inner.pop_back()
339835abbcdSSaúl Cabrera     }
340835abbcdSSaúl Cabrera 
3417c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i32 const;
342835abbcdSSaúl Cabrera     /// returns `None` otherwise.
343835abbcdSSaúl Cabrera     pub fn pop_i32_const(&mut self) -> Option<i32> {
344835abbcdSSaúl Cabrera         match self.peek() {
345f0162a40SSaúl Cabrera             Some(v) => v.is_i32_const().then(|| self.pop().unwrap().unwrap_i32()),
346835abbcdSSaúl Cabrera             _ => None,
347835abbcdSSaúl Cabrera         }
348835abbcdSSaúl Cabrera     }
349835abbcdSSaúl Cabrera 
3507c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i64 const;
3517c5c7e4bSSaúl Cabrera     /// returns `None` otherwise.
3527c5c7e4bSSaúl Cabrera     pub fn pop_i64_const(&mut self) -> Option<i64> {
3537c5c7e4bSSaúl Cabrera         match self.peek() {
354f0162a40SSaúl Cabrera             Some(v) => v.is_i64_const().then(|| self.pop().unwrap().unwrap_i64()),
3557c5c7e4bSSaúl Cabrera             _ => None,
3567c5c7e4bSSaúl Cabrera         }
3577c5c7e4bSSaúl Cabrera     }
3587c5c7e4bSSaúl Cabrera 
359835abbcdSSaúl Cabrera     /// Pops the element at the top of the stack if it is a register;
360835abbcdSSaúl Cabrera     /// returns `None` otherwise.
36114b39bc2SSaúl Cabrera     pub fn pop_reg(&mut self) -> Option<TypedReg> {
362835abbcdSSaúl Cabrera         match self.peek() {
363f0162a40SSaúl Cabrera             Some(v) => v.is_reg().then(|| self.pop().unwrap().unwrap_reg()),
364835abbcdSSaúl Cabrera             _ => None,
365835abbcdSSaúl Cabrera         }
366835abbcdSSaúl Cabrera     }
367835abbcdSSaúl Cabrera 
368835abbcdSSaúl Cabrera     /// Pops the given register if it is at the top of the stack;
369835abbcdSSaúl Cabrera     /// returns `None` otherwise.
37014b39bc2SSaúl Cabrera     pub fn pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg> {
371835abbcdSSaúl Cabrera         match self.peek() {
37214b39bc2SSaúl Cabrera             Some(v) => {
373f0162a40SSaúl Cabrera                 (v.is_reg() && v.unwrap_reg().reg == reg).then(|| self.pop().unwrap().unwrap_reg())
37414b39bc2SSaúl Cabrera             }
375835abbcdSSaúl Cabrera             _ => None,
376835abbcdSSaúl Cabrera         }
377835abbcdSSaúl Cabrera     }
378835abbcdSSaúl Cabrera 
379835abbcdSSaúl Cabrera     /// Get a mutable reference to the inner stack representation.
380835abbcdSSaúl Cabrera     pub fn inner_mut(&mut self) -> &mut VecDeque<Val> {
381835abbcdSSaúl Cabrera         &mut self.inner
382835abbcdSSaúl Cabrera     }
38350733725SSaúl Cabrera 
38450733725SSaúl Cabrera     /// Calculates the size of, in bytes, of the top n [Memory] entries
38550733725SSaúl Cabrera     /// in the value stack.
38650733725SSaúl Cabrera     pub fn sizeof(&self, top: usize) -> u32 {
38750733725SSaúl Cabrera         self.peekn(top).fold(0, |acc, v| {
38850733725SSaúl Cabrera             if v.is_mem() {
38950733725SSaúl Cabrera                 acc + v.unwrap_mem().slot.size
39050733725SSaúl Cabrera             } else {
39150733725SSaúl Cabrera                 acc
39250733725SSaúl Cabrera             }
39350733725SSaúl Cabrera         })
39450733725SSaúl Cabrera     }
395835abbcdSSaúl Cabrera }
396835abbcdSSaúl Cabrera 
397835abbcdSSaúl Cabrera #[cfg(test)]
398835abbcdSSaúl Cabrera mod tests {
399835abbcdSSaúl Cabrera     use super::{Stack, Val};
400835abbcdSSaúl Cabrera     use crate::isa::reg::Reg;
40114b39bc2SSaúl Cabrera     use wasmtime_environ::WasmType;
402835abbcdSSaúl Cabrera 
403835abbcdSSaúl Cabrera     #[test]
404835abbcdSSaúl Cabrera     fn test_pop_i32_const() {
405835abbcdSSaúl Cabrera         let mut stack = Stack::new();
406835abbcdSSaúl Cabrera         stack.push(Val::i32(33i32));
407835abbcdSSaúl Cabrera         assert_eq!(33, stack.pop_i32_const().unwrap());
408835abbcdSSaúl Cabrera 
40914b39bc2SSaúl Cabrera         stack.push(Val::local(10, WasmType::I32));
410835abbcdSSaúl Cabrera         assert!(stack.pop_i32_const().is_none());
411835abbcdSSaúl Cabrera     }
412835abbcdSSaúl Cabrera 
413835abbcdSSaúl Cabrera     #[test]
414835abbcdSSaúl Cabrera     fn test_pop_reg() {
415835abbcdSSaúl Cabrera         let mut stack = Stack::new();
416835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
41714b39bc2SSaúl Cabrera         stack.push(Val::reg(reg, WasmType::I32));
418835abbcdSSaúl Cabrera         stack.push(Val::i32(4));
419835abbcdSSaúl Cabrera 
420835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_reg());
421835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
42214b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_reg().unwrap().reg);
423835abbcdSSaúl Cabrera     }
424835abbcdSSaúl Cabrera 
425835abbcdSSaúl Cabrera     #[test]
426835abbcdSSaúl Cabrera     fn test_pop_named_reg() {
427835abbcdSSaúl Cabrera         let mut stack = Stack::new();
428835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
42914b39bc2SSaúl Cabrera         stack.push(Val::reg(reg, WasmType::I32));
43014b39bc2SSaúl Cabrera         stack.push(Val::reg(Reg::int(4), WasmType::I32));
431835abbcdSSaúl Cabrera 
432835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_named_reg(reg));
433835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
43414b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_named_reg(reg).unwrap().reg);
435835abbcdSSaúl Cabrera     }
436835abbcdSSaúl Cabrera }
437