xref: /wasmtime-44.0.1/winch/codegen/src/stack.rs (revision b112bb85)
1*b112bb85SNick Fitzgerald use crate::{Result, codegen::CodeGenError, format_err, 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`].
new(ty: WasmValType, reg: Reg) -> Self18496237c2SNick 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`].
i64(reg: Reg) -> Self2314b39bc2SSaú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`].
i32(reg: Reg) -> Self31a109d2abSSaú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`].
f64(reg: Reg) -> Self3917091e6fSJeffrey 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`].
f32(reg: Reg) -> Self4717091e6fSJeffrey Charles     pub fn f32(reg: Reg) -> Self {
4817091e6fSJeffrey Charles         Self {
49496237c2SNick Fitzgerald             ty: WasmValType::F32,
5017091e6fSJeffrey Charles             reg,
5117091e6fSJeffrey Charles         }
5217091e6fSJeffrey Charles     }
53ba950f2cSJeffrey Charles 
54ba950f2cSJeffrey Charles     /// Create a v128 [`TypedReg`].
v128(reg: Reg) -> Self55ba950f2cSJeffrey Charles     pub fn v128(reg: Reg) -> Self {
56ba950f2cSJeffrey Charles         Self {
57ba950f2cSJeffrey Charles             ty: WasmValType::V128,
58ba950f2cSJeffrey Charles             reg,
59ba950f2cSJeffrey Charles         }
60ba950f2cSJeffrey Charles     }
6114b39bc2SSaúl Cabrera }
6214b39bc2SSaúl Cabrera 
6314b39bc2SSaúl Cabrera impl From<TypedReg> for Reg {
from(tr: TypedReg) -> Self6414b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
6514b39bc2SSaúl Cabrera         tr.reg
6614b39bc2SSaúl Cabrera     }
6714b39bc2SSaúl Cabrera }
6814b39bc2SSaúl Cabrera 
6914b39bc2SSaúl Cabrera /// A local value.
7014b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
7114b39bc2SSaúl Cabrera pub struct Local {
7214b39bc2SSaúl Cabrera     /// The index of the local.
7314b39bc2SSaúl Cabrera     pub index: u32,
7414b39bc2SSaúl Cabrera     /// The type of the local.
75496237c2SNick Fitzgerald     pub ty: WasmValType,
7614b39bc2SSaúl Cabrera }
7714b39bc2SSaúl Cabrera 
7814b39bc2SSaúl Cabrera /// A memory value.
7914b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
8014b39bc2SSaúl Cabrera pub struct Memory {
8114b39bc2SSaúl Cabrera     /// The type associated with the memory offset.
82496237c2SNick Fitzgerald     pub ty: WasmValType,
8314b39bc2SSaúl Cabrera     /// The stack slot corresponding to the memory value.
8414b39bc2SSaúl Cabrera     pub slot: StackSlot,
8514b39bc2SSaúl Cabrera }
86835abbcdSSaúl Cabrera 
87835abbcdSSaúl Cabrera /// Value definition to be used within the shadow stack.
88a50c4972SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)]
89835abbcdSSaúl Cabrera pub(crate) enum Val {
90835abbcdSSaúl Cabrera     /// I32 Constant.
91835abbcdSSaúl Cabrera     I32(i32),
927c5c7e4bSSaúl Cabrera     /// I64 Constant.
937c5c7e4bSSaúl Cabrera     I64(i64),
9414b39bc2SSaúl Cabrera     /// F32 Constant.
9514b39bc2SSaúl Cabrera     F32(Ieee32),
9614b39bc2SSaúl Cabrera     /// F64 Constant.
9714b39bc2SSaúl Cabrera     F64(Ieee64),
98fa9a948dSJeffrey Charles     /// V128 Constant.
99fa9a948dSJeffrey Charles     V128(i128),
10014b39bc2SSaúl Cabrera     /// A register value.
10114b39bc2SSaúl Cabrera     Reg(TypedReg),
102835abbcdSSaúl Cabrera     /// A local slot.
10314b39bc2SSaúl Cabrera     Local(Local),
104835abbcdSSaúl Cabrera     /// Offset to a memory location.
10514b39bc2SSaúl Cabrera     Memory(Memory),
10614b39bc2SSaúl Cabrera }
10714b39bc2SSaúl Cabrera 
10814b39bc2SSaúl Cabrera impl From<TypedReg> for Val {
from(tr: TypedReg) -> Self10914b39bc2SSaúl Cabrera     fn from(tr: TypedReg) -> Self {
11014b39bc2SSaúl Cabrera         Val::Reg(tr)
11114b39bc2SSaúl Cabrera     }
11214b39bc2SSaúl Cabrera }
11314b39bc2SSaúl Cabrera 
11414b39bc2SSaúl Cabrera impl From<Local> for Val {
from(local: Local) -> Self11514b39bc2SSaúl Cabrera     fn from(local: Local) -> Self {
11614b39bc2SSaúl Cabrera         Val::Local(local)
11714b39bc2SSaúl Cabrera     }
11814b39bc2SSaúl Cabrera }
11914b39bc2SSaúl Cabrera 
12014b39bc2SSaúl Cabrera impl From<Memory> for Val {
from(mem: Memory) -> Self12114b39bc2SSaúl Cabrera     fn from(mem: Memory) -> Self {
12214b39bc2SSaúl Cabrera         Val::Memory(mem)
12314b39bc2SSaúl Cabrera     }
124835abbcdSSaúl Cabrera }
125835abbcdSSaúl Cabrera 
1264b288ba8SSaúl Cabrera impl TryFrom<u32> for Val {
127*b112bb85SNick Fitzgerald     type Error = crate::Error;
try_from(value: u32) -> Result<Self, Self::Error>1284b288ba8SSaúl Cabrera     fn try_from(value: u32) -> Result<Self, Self::Error> {
1294b288ba8SSaúl Cabrera         i32::try_from(value).map(Val::i32).map_err(Into::into)
1304b288ba8SSaúl Cabrera     }
1314b288ba8SSaúl Cabrera }
1324b288ba8SSaúl Cabrera 
133835abbcdSSaúl Cabrera impl Val {
134835abbcdSSaúl Cabrera     /// Create a new I32 constant value.
i32(v: i32) -> Self135835abbcdSSaúl Cabrera     pub fn i32(v: i32) -> Self {
136835abbcdSSaúl Cabrera         Self::I32(v)
137835abbcdSSaúl Cabrera     }
138835abbcdSSaúl Cabrera 
1397c5c7e4bSSaúl Cabrera     /// Create a new I64 constant value.
i64(v: i64) -> Self1407c5c7e4bSSaúl Cabrera     pub fn i64(v: i64) -> Self {
1417c5c7e4bSSaúl Cabrera         Self::I64(v)
1427c5c7e4bSSaúl Cabrera     }
1437c5c7e4bSSaúl Cabrera 
14414b39bc2SSaúl Cabrera     /// Create a new F32 constant value.
f32(v: Ieee32) -> Self14514b39bc2SSaúl Cabrera     pub fn f32(v: Ieee32) -> Self {
14614b39bc2SSaúl Cabrera         Self::F32(v)
14714b39bc2SSaúl Cabrera     }
14814b39bc2SSaúl Cabrera 
f64(v: Ieee64) -> Self14914b39bc2SSaúl Cabrera     pub fn f64(v: Ieee64) -> Self {
15014b39bc2SSaúl Cabrera         Self::F64(v)
15114b39bc2SSaúl Cabrera     }
15214b39bc2SSaúl Cabrera 
153fa9a948dSJeffrey Charles     /// Create a new V128 constant value.
v128(v: i128) -> Self154fa9a948dSJeffrey Charles     pub fn v128(v: i128) -> Self {
155fa9a948dSJeffrey Charles         Self::V128(v)
156fa9a948dSJeffrey Charles     }
157fa9a948dSJeffrey Charles 
158835abbcdSSaúl Cabrera     /// Create a new Reg value.
reg(reg: Reg, ty: WasmValType) -> Self159496237c2SNick Fitzgerald     pub fn reg(reg: Reg, ty: WasmValType) -> Self {
16014b39bc2SSaúl Cabrera         Self::Reg(TypedReg { reg, ty })
161835abbcdSSaúl Cabrera     }
162835abbcdSSaúl Cabrera 
163835abbcdSSaúl Cabrera     /// Create a new Local value.
local(index: u32, ty: WasmValType) -> Self164496237c2SNick Fitzgerald     pub fn local(index: u32, ty: WasmValType) -> Self {
16514b39bc2SSaúl Cabrera         Self::Local(Local { index, ty })
16614b39bc2SSaúl Cabrera     }
16714b39bc2SSaúl Cabrera 
16814b39bc2SSaúl Cabrera     /// Create a Memory value.
mem(ty: WasmValType, slot: StackSlot) -> Self169496237c2SNick Fitzgerald     pub fn mem(ty: WasmValType, slot: StackSlot) -> Self {
17014b39bc2SSaúl Cabrera         Self::Memory(Memory { ty, slot })
171835abbcdSSaúl Cabrera     }
172835abbcdSSaúl Cabrera 
173835abbcdSSaúl Cabrera     /// Check whether the value is a register.
is_reg(&self) -> bool174835abbcdSSaúl Cabrera     pub fn is_reg(&self) -> bool {
175835abbcdSSaúl Cabrera         match *self {
176835abbcdSSaúl Cabrera             Self::Reg(_) => true,
177835abbcdSSaúl Cabrera             _ => false,
178835abbcdSSaúl Cabrera         }
179835abbcdSSaúl Cabrera     }
180835abbcdSSaúl Cabrera 
1810e9121daSFrankReh     /// Check whether the value is a memory offset.
is_mem(&self) -> bool182af4d94c8SSaúl Cabrera     pub fn is_mem(&self) -> bool {
183af4d94c8SSaúl Cabrera         match *self {
184af4d94c8SSaúl Cabrera             Self::Memory(_) => true,
185af4d94c8SSaúl Cabrera             _ => false,
186af4d94c8SSaúl Cabrera         }
187af4d94c8SSaúl Cabrera     }
188af4d94c8SSaúl Cabrera 
18955f9a4bdSJeffrey Charles     /// Check whether the value is a constant.
is_const(&self) -> bool19055f9a4bdSJeffrey Charles     pub fn is_const(&self) -> bool {
19155f9a4bdSJeffrey Charles         match *self {
192fa9a948dSJeffrey Charles             Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
19355f9a4bdSJeffrey Charles             _ => false,
19455f9a4bdSJeffrey Charles         }
19555f9a4bdSJeffrey Charles     }
19655f9a4bdSJeffrey Charles 
197321294a5SJeffrey Charles     /// Check whether the value is local with a particular index.
is_local_at_index(&self, index: u32) -> bool198321294a5SJeffrey Charles     pub fn is_local_at_index(&self, index: u32) -> bool {
199321294a5SJeffrey Charles         match *self {
200321294a5SJeffrey Charles             Self::Local(Local { index: i, .. }) if i == index => true,
201321294a5SJeffrey Charles             _ => false,
202321294a5SJeffrey Charles         }
203321294a5SJeffrey Charles     }
204321294a5SJeffrey Charles 
205835abbcdSSaúl Cabrera     /// Get the register representation of the value.
206835abbcdSSaúl Cabrera     ///
207835abbcdSSaúl Cabrera     /// # Panics
208835abbcdSSaúl Cabrera     /// This method will panic if the value is not a register.
unwrap_reg(&self) -> TypedReg209f0162a40SSaúl Cabrera     pub fn unwrap_reg(&self) -> TypedReg {
210835abbcdSSaúl Cabrera         match self {
21114b39bc2SSaúl Cabrera             Self::Reg(tr) => *tr,
212a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be a register"),
213835abbcdSSaúl Cabrera         }
214835abbcdSSaúl Cabrera     }
215835abbcdSSaúl Cabrera 
216835abbcdSSaúl Cabrera     /// Get the integer representation of the value.
217835abbcdSSaúl Cabrera     ///
218835abbcdSSaúl Cabrera     /// # Panics
219835abbcdSSaúl Cabrera     /// This method will panic if the value is not an i32.
unwrap_i32(&self) -> i32220f0162a40SSaúl Cabrera     pub fn unwrap_i32(&self) -> i32 {
221835abbcdSSaúl Cabrera         match self {
222835abbcdSSaúl Cabrera             Self::I32(v) => *v,
223a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be i32"),
224835abbcdSSaúl Cabrera         }
225835abbcdSSaúl Cabrera     }
226835abbcdSSaúl Cabrera 
2277c5c7e4bSSaúl Cabrera     /// Get the integer representation of the value.
2287c5c7e4bSSaúl Cabrera     ///
2297c5c7e4bSSaúl Cabrera     /// # Panics
2307c5c7e4bSSaúl Cabrera     /// This method will panic if the value is not an i64.
unwrap_i64(&self) -> i64231f0162a40SSaúl Cabrera     pub fn unwrap_i64(&self) -> i64 {
2327c5c7e4bSSaúl Cabrera         match self {
2337c5c7e4bSSaúl Cabrera             Self::I64(v) => *v,
234a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be i64"),
2357c5c7e4bSSaúl Cabrera         }
2367c5c7e4bSSaúl Cabrera     }
2377c5c7e4bSSaúl Cabrera 
2381ad7a4f6SJeffrey Charles     /// Get the float representation of the value.
2391ad7a4f6SJeffrey Charles     ///
2401ad7a4f6SJeffrey Charles     /// # Panics
2411ad7a4f6SJeffrey Charles     /// This method will panic if the value is not an f32.
unwrap_f32(&self) -> Ieee322421ad7a4f6SJeffrey Charles     pub fn unwrap_f32(&self) -> Ieee32 {
2431ad7a4f6SJeffrey Charles         match self {
2441ad7a4f6SJeffrey Charles             Self::F32(v) => *v,
2451ad7a4f6SJeffrey Charles             v => panic!("expected value {v:?} to be f32"),
2461ad7a4f6SJeffrey Charles         }
2471ad7a4f6SJeffrey Charles     }
2481ad7a4f6SJeffrey Charles 
2491ad7a4f6SJeffrey Charles     /// Get the float representation of the value.
2501ad7a4f6SJeffrey Charles     ///
2511ad7a4f6SJeffrey Charles     /// # Panics
2521ad7a4f6SJeffrey Charles     /// This method will panic if the value is not an f64.
unwrap_f64(&self) -> Ieee642531ad7a4f6SJeffrey Charles     pub fn unwrap_f64(&self) -> Ieee64 {
2541ad7a4f6SJeffrey Charles         match self {
2551ad7a4f6SJeffrey Charles             Self::F64(v) => *v,
2561ad7a4f6SJeffrey Charles             v => panic!("expected value {v:?} to be f64"),
2571ad7a4f6SJeffrey Charles         }
2581ad7a4f6SJeffrey Charles     }
2591ad7a4f6SJeffrey Charles 
260f0162a40SSaúl Cabrera     /// Returns the underlying memory value if it is one, panics otherwise.
unwrap_mem(&self) -> Memory261f0162a40SSaúl Cabrera     pub fn unwrap_mem(&self) -> Memory {
262f0162a40SSaúl Cabrera         match self {
263f0162a40SSaúl Cabrera             Self::Memory(m) => *m,
264a0442ea0SHamir Mahal             v => panic!("expected value {v:?} to be a Memory"),
265f0162a40SSaúl Cabrera         }
266f0162a40SSaúl Cabrera     }
267f0162a40SSaúl Cabrera 
268835abbcdSSaúl Cabrera     /// Check whether the value is an i32 constant.
is_i32_const(&self) -> bool269835abbcdSSaúl Cabrera     pub fn is_i32_const(&self) -> bool {
270835abbcdSSaúl Cabrera         match *self {
271835abbcdSSaúl Cabrera             Self::I32(_) => true,
272835abbcdSSaúl Cabrera             _ => false,
273835abbcdSSaúl Cabrera         }
274835abbcdSSaúl Cabrera     }
2757c5c7e4bSSaúl Cabrera 
2767c5c7e4bSSaúl Cabrera     /// Check whether the value is an i64 constant.
is_i64_const(&self) -> bool2777c5c7e4bSSaúl Cabrera     pub fn is_i64_const(&self) -> bool {
2787c5c7e4bSSaúl Cabrera         match *self {
2797c5c7e4bSSaúl Cabrera             Self::I64(_) => true,
2807c5c7e4bSSaúl Cabrera             _ => false,
2817c5c7e4bSSaúl Cabrera         }
2827c5c7e4bSSaúl Cabrera     }
28314b39bc2SSaúl Cabrera 
2841ad7a4f6SJeffrey Charles     /// Check whether the value is an f32 constant.
is_f32_const(&self) -> bool2851ad7a4f6SJeffrey Charles     pub fn is_f32_const(&self) -> bool {
2861ad7a4f6SJeffrey Charles         match *self {
2871ad7a4f6SJeffrey Charles             Self::F32(_) => true,
2881ad7a4f6SJeffrey Charles             _ => false,
2891ad7a4f6SJeffrey Charles         }
2901ad7a4f6SJeffrey Charles     }
2911ad7a4f6SJeffrey Charles 
2921ad7a4f6SJeffrey Charles     /// Check whether the value is an f64 constant.
is_f64_const(&self) -> bool2931ad7a4f6SJeffrey Charles     pub fn is_f64_const(&self) -> bool {
2941ad7a4f6SJeffrey Charles         match *self {
2951ad7a4f6SJeffrey Charles             Self::F64(_) => true,
2961ad7a4f6SJeffrey Charles             _ => false,
2971ad7a4f6SJeffrey Charles         }
2981ad7a4f6SJeffrey Charles     }
2991ad7a4f6SJeffrey Charles 
30014b39bc2SSaúl Cabrera     /// Get the type of the value.
ty(&self) -> WasmValType301496237c2SNick Fitzgerald     pub fn ty(&self) -> WasmValType {
30214b39bc2SSaúl Cabrera         match self {
303496237c2SNick Fitzgerald             Val::I32(_) => WasmValType::I32,
304496237c2SNick Fitzgerald             Val::I64(_) => WasmValType::I64,
305496237c2SNick Fitzgerald             Val::F32(_) => WasmValType::F32,
306496237c2SNick Fitzgerald             Val::F64(_) => WasmValType::F64,
307fa9a948dSJeffrey Charles             Val::V128(_) => WasmValType::V128,
30814b39bc2SSaúl Cabrera             Val::Reg(r) => r.ty,
30914b39bc2SSaúl Cabrera             Val::Memory(m) => m.ty,
31014b39bc2SSaúl Cabrera             Val::Local(l) => l.ty,
31114b39bc2SSaúl Cabrera         }
31214b39bc2SSaúl Cabrera     }
313835abbcdSSaúl Cabrera }
314835abbcdSSaúl Cabrera 
315835abbcdSSaúl Cabrera /// The shadow stack used for compilation.
316835abbcdSSaúl Cabrera #[derive(Default, Debug)]
317835abbcdSSaúl Cabrera pub(crate) struct Stack {
3181b5c4ae8SSaúl Cabrera     // NB: The 64 is chosen arbitrarily. We can adjust as we see fit.
3191b5c4ae8SSaúl Cabrera     inner: SmallVec<[Val; 64]>,
320835abbcdSSaúl Cabrera }
321835abbcdSSaúl Cabrera 
322835abbcdSSaúl Cabrera impl Stack {
323835abbcdSSaúl Cabrera     /// Allocate a new stack.
new() -> Self324835abbcdSSaúl Cabrera     pub fn new() -> Self {
325835abbcdSSaúl Cabrera         Self {
326835abbcdSSaúl Cabrera             inner: Default::default(),
327835abbcdSSaúl Cabrera         }
328835abbcdSSaúl Cabrera     }
329835abbcdSSaúl Cabrera 
330b93e1bc0SSaúl Cabrera     /// Ensures that there are at least `n` elements in the value stack,
331b93e1bc0SSaúl Cabrera     /// and returns the index calculated by: stack length minus `n`.
ensure_index_at(&self, n: usize) -> Result<usize>332b93e1bc0SSaúl Cabrera     pub fn ensure_index_at(&self, n: usize) -> Result<usize> {
333b93e1bc0SSaúl Cabrera         if self.len() >= n {
334b93e1bc0SSaúl Cabrera             Ok(self.len() - n)
335b93e1bc0SSaúl Cabrera         } else {
336*b112bb85SNick Fitzgerald             Err(format_err!(CodeGenError::missing_values_in_stack()))
337b93e1bc0SSaúl Cabrera         }
338b93e1bc0SSaúl Cabrera     }
339b93e1bc0SSaúl Cabrera 
340321294a5SJeffrey Charles     /// Returns true if the stack contains a local with the provided index
341321294a5SJeffrey Charles     /// except if the only time the local appears is the top element.
contains_latent_local(&self, index: u32) -> bool342321294a5SJeffrey Charles     pub fn contains_latent_local(&self, index: u32) -> bool {
343321294a5SJeffrey Charles         self.inner
344321294a5SJeffrey Charles             .iter()
345321294a5SJeffrey Charles             // Iterate top-to-bottom so we can skip the top element and stop
346321294a5SJeffrey Charles             // when we see a memory element.
347321294a5SJeffrey Charles             .rev()
348321294a5SJeffrey Charles             // The local is not latent if it's the top element because the top
349321294a5SJeffrey Charles             // element will be popped next which materializes the local.
350321294a5SJeffrey Charles             .skip(1)
351321294a5SJeffrey Charles             // Stop when we see a memory element because that marks where we
352321294a5SJeffrey Charles             // spilled up to so there will not be any locals past this point.
353321294a5SJeffrey Charles             .take_while(|v| !v.is_mem())
354321294a5SJeffrey Charles             .any(|v| v.is_local_at_index(index))
355321294a5SJeffrey Charles     }
356321294a5SJeffrey Charles 
357a109d2abSSaúl Cabrera     /// Extend the stack with the given elements.
extend(&mut self, values: impl IntoIterator<Item = Val>)358a109d2abSSaúl Cabrera     pub fn extend(&mut self, values: impl IntoIterator<Item = Val>) {
359a109d2abSSaúl Cabrera         self.inner.extend(values);
360a109d2abSSaúl Cabrera     }
361a109d2abSSaúl Cabrera 
362a109d2abSSaúl Cabrera     /// Inserts many values at the given index.
insert_many(&mut self, at: usize, values: &[Val])3631b5c4ae8SSaúl Cabrera     pub fn insert_many(&mut self, at: usize, values: &[Val]) {
364a109d2abSSaúl Cabrera         debug_assert!(at <= self.len());
3651b5c4ae8SSaúl Cabrera 
3661b5c4ae8SSaúl Cabrera         if at == self.len() {
3671b5c4ae8SSaúl Cabrera             self.inner.extend_from_slice(values);
368a109d2abSSaúl Cabrera         } else {
3691b5c4ae8SSaúl Cabrera             self.inner.insert_from_slice(at, values);
370a109d2abSSaúl Cabrera         }
37120c58362SSaúl Cabrera     }
37220c58362SSaúl Cabrera 
373af4d94c8SSaúl Cabrera     /// Get the length of the stack.
len(&self) -> usize374af4d94c8SSaúl Cabrera     pub fn len(&self) -> usize {
375af4d94c8SSaúl Cabrera         self.inner.len()
376af4d94c8SSaúl Cabrera     }
377af4d94c8SSaúl Cabrera 
378835abbcdSSaúl Cabrera     /// Push a value to the stack.
push(&mut self, val: Val)379835abbcdSSaúl Cabrera     pub fn push(&mut self, val: Val) {
3807690c500STrevor Elliott         self.inner.push(val);
381835abbcdSSaúl Cabrera     }
382835abbcdSSaúl Cabrera 
383835abbcdSSaúl Cabrera     /// Peek into the top in the stack.
peek(&self) -> Option<&Val>3847c5c7e4bSSaúl Cabrera     pub fn peek(&self) -> Option<&Val> {
3857690c500STrevor Elliott         self.inner.last()
386835abbcdSSaúl Cabrera     }
387835abbcdSSaúl Cabrera 
388af4d94c8SSaúl Cabrera     /// Returns an iterator referencing the last n items of the stack,
389af4d94c8SSaúl Cabrera     /// in bottom-most to top-most order.
peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_390af4d94c8SSaúl Cabrera     pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ {
391af4d94c8SSaúl Cabrera         let len = self.len();
392af4d94c8SSaúl Cabrera         assert!(n <= len);
393af4d94c8SSaúl Cabrera 
394af4d94c8SSaúl Cabrera         let partition = len - n;
3957690c500STrevor Elliott         self.inner[partition..].into_iter()
396af4d94c8SSaúl Cabrera     }
397af4d94c8SSaúl Cabrera 
398835abbcdSSaúl Cabrera     /// Pops the top element of the stack, if any.
pop(&mut self) -> Option<Val>399835abbcdSSaúl Cabrera     pub fn pop(&mut self) -> Option<Val> {
4007690c500STrevor Elliott         self.inner.pop()
401835abbcdSSaúl Cabrera     }
402835abbcdSSaúl Cabrera 
4037c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i32 const;
404835abbcdSSaúl Cabrera     /// returns `None` otherwise.
pop_i32_const(&mut self) -> Option<i32>405835abbcdSSaúl Cabrera     pub fn pop_i32_const(&mut self) -> Option<i32> {
406835abbcdSSaúl Cabrera         match self.peek() {
407f0162a40SSaúl Cabrera             Some(v) => v.is_i32_const().then(|| self.pop().unwrap().unwrap_i32()),
408835abbcdSSaúl Cabrera             _ => None,
409835abbcdSSaúl Cabrera         }
410835abbcdSSaúl Cabrera     }
411835abbcdSSaúl Cabrera 
4127c5c7e4bSSaúl Cabrera     /// Pops the element at the top of the stack if it is an i64 const;
4137c5c7e4bSSaúl Cabrera     /// returns `None` otherwise.
pop_i64_const(&mut self) -> Option<i64>4147c5c7e4bSSaúl Cabrera     pub fn pop_i64_const(&mut self) -> Option<i64> {
4157c5c7e4bSSaúl Cabrera         match self.peek() {
416f0162a40SSaúl Cabrera             Some(v) => v.is_i64_const().then(|| self.pop().unwrap().unwrap_i64()),
4177c5c7e4bSSaúl Cabrera             _ => None,
4187c5c7e4bSSaúl Cabrera         }
4197c5c7e4bSSaúl Cabrera     }
4207c5c7e4bSSaúl Cabrera 
4211ad7a4f6SJeffrey Charles     /// Pops the element at the top of the stack if it is an f32 const;
4221ad7a4f6SJeffrey Charles     /// returns `None` otherwise.
pop_f32_const(&mut self) -> Option<Ieee32>4231ad7a4f6SJeffrey Charles     pub fn pop_f32_const(&mut self) -> Option<Ieee32> {
4241ad7a4f6SJeffrey Charles         match self.peek() {
4251ad7a4f6SJeffrey Charles             Some(v) => v.is_f32_const().then(|| self.pop().unwrap().unwrap_f32()),
4261ad7a4f6SJeffrey Charles             _ => None,
4271ad7a4f6SJeffrey Charles         }
4281ad7a4f6SJeffrey Charles     }
4291ad7a4f6SJeffrey Charles 
4301ad7a4f6SJeffrey Charles     /// Pops the element at the top of the stack if it is an f64 const;
4311ad7a4f6SJeffrey Charles     /// returns `None` otherwise.
pop_f64_const(&mut self) -> Option<Ieee64>4321ad7a4f6SJeffrey Charles     pub fn pop_f64_const(&mut self) -> Option<Ieee64> {
4331ad7a4f6SJeffrey Charles         match self.peek() {
4341ad7a4f6SJeffrey Charles             Some(v) => v.is_f64_const().then(|| self.pop().unwrap().unwrap_f64()),
4351ad7a4f6SJeffrey Charles             _ => None,
4361ad7a4f6SJeffrey Charles         }
4371ad7a4f6SJeffrey Charles     }
4381ad7a4f6SJeffrey Charles 
439835abbcdSSaúl Cabrera     /// Pops the element at the top of the stack if it is a register;
440835abbcdSSaúl Cabrera     /// returns `None` otherwise.
pop_reg(&mut self) -> Option<TypedReg>44114b39bc2SSaúl Cabrera     pub fn pop_reg(&mut self) -> Option<TypedReg> {
442835abbcdSSaúl Cabrera         match self.peek() {
443f0162a40SSaúl Cabrera             Some(v) => v.is_reg().then(|| self.pop().unwrap().unwrap_reg()),
444835abbcdSSaúl Cabrera             _ => None,
445835abbcdSSaúl Cabrera         }
446835abbcdSSaúl Cabrera     }
447835abbcdSSaúl Cabrera 
448835abbcdSSaúl Cabrera     /// Pops the given register if it is at the top of the stack;
449835abbcdSSaúl Cabrera     /// returns `None` otherwise.
pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg>45014b39bc2SSaúl Cabrera     pub fn pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg> {
451835abbcdSSaúl Cabrera         match self.peek() {
45214b39bc2SSaúl Cabrera             Some(v) => {
453f0162a40SSaúl Cabrera                 (v.is_reg() && v.unwrap_reg().reg == reg).then(|| self.pop().unwrap().unwrap_reg())
45414b39bc2SSaúl Cabrera             }
455835abbcdSSaúl Cabrera             _ => None,
456835abbcdSSaúl Cabrera         }
457835abbcdSSaúl Cabrera     }
458835abbcdSSaúl Cabrera 
459835abbcdSSaúl Cabrera     /// Get a mutable reference to the inner stack representation.
inner_mut(&mut self) -> &mut SmallVec<[Val; 64]>4601b5c4ae8SSaúl Cabrera     pub fn inner_mut(&mut self) -> &mut SmallVec<[Val; 64]> {
461835abbcdSSaúl Cabrera         &mut self.inner
462835abbcdSSaúl Cabrera     }
46350733725SSaúl Cabrera 
464446a7f5eSSaúl Cabrera     /// Get a reference to the inner stack representation.
inner(&self) -> &SmallVec<[Val; 64]>4651b5c4ae8SSaúl Cabrera     pub fn inner(&self) -> &SmallVec<[Val; 64]> {
466446a7f5eSSaúl Cabrera         &self.inner
467446a7f5eSSaúl Cabrera     }
468446a7f5eSSaúl Cabrera 
46950733725SSaúl Cabrera     /// Calculates the size of, in bytes, of the top n [Memory] entries
47050733725SSaúl Cabrera     /// in the value stack.
sizeof(&self, top: usize) -> u3247150733725SSaúl Cabrera     pub fn sizeof(&self, top: usize) -> u32 {
47250733725SSaúl Cabrera         self.peekn(top).fold(0, |acc, v| {
47350733725SSaúl Cabrera             if v.is_mem() {
47450733725SSaúl Cabrera                 acc + v.unwrap_mem().slot.size
47550733725SSaúl Cabrera             } else {
47650733725SSaúl Cabrera                 acc
47750733725SSaúl Cabrera             }
47850733725SSaúl Cabrera         })
47950733725SSaúl Cabrera     }
480835abbcdSSaúl Cabrera }
481835abbcdSSaúl Cabrera 
482835abbcdSSaúl Cabrera #[cfg(test)]
483835abbcdSSaúl Cabrera mod tests {
484835abbcdSSaúl Cabrera     use super::{Stack, Val};
485835abbcdSSaúl Cabrera     use crate::isa::reg::Reg;
486496237c2SNick Fitzgerald     use wasmtime_environ::WasmValType;
487835abbcdSSaúl Cabrera 
488835abbcdSSaúl Cabrera     #[test]
test_pop_i32_const()489835abbcdSSaúl Cabrera     fn test_pop_i32_const() {
490835abbcdSSaúl Cabrera         let mut stack = Stack::new();
491835abbcdSSaúl Cabrera         stack.push(Val::i32(33i32));
492835abbcdSSaúl Cabrera         assert_eq!(33, stack.pop_i32_const().unwrap());
493835abbcdSSaúl Cabrera 
494496237c2SNick Fitzgerald         stack.push(Val::local(10, WasmValType::I32));
495835abbcdSSaúl Cabrera         assert!(stack.pop_i32_const().is_none());
496835abbcdSSaúl Cabrera     }
497835abbcdSSaúl Cabrera 
498835abbcdSSaúl Cabrera     #[test]
test_pop_reg()499835abbcdSSaúl Cabrera     fn test_pop_reg() {
500835abbcdSSaúl Cabrera         let mut stack = Stack::new();
501835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
502496237c2SNick Fitzgerald         stack.push(Val::reg(reg, WasmValType::I32));
503835abbcdSSaúl Cabrera         stack.push(Val::i32(4));
504835abbcdSSaúl Cabrera 
505835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_reg());
506835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
50714b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_reg().unwrap().reg);
508835abbcdSSaúl Cabrera     }
509835abbcdSSaúl Cabrera 
510835abbcdSSaúl Cabrera     #[test]
test_pop_named_reg()511835abbcdSSaúl Cabrera     fn test_pop_named_reg() {
512835abbcdSSaúl Cabrera         let mut stack = Stack::new();
513835abbcdSSaúl Cabrera         let reg = Reg::int(2usize);
514496237c2SNick Fitzgerald         stack.push(Val::reg(reg, WasmValType::I32));
515496237c2SNick Fitzgerald         stack.push(Val::reg(Reg::int(4), WasmValType::I32));
516835abbcdSSaúl Cabrera 
517835abbcdSSaúl Cabrera         assert_eq!(None, stack.pop_named_reg(reg));
518835abbcdSSaúl Cabrera         let _ = stack.pop().unwrap();
51914b39bc2SSaúl Cabrera         assert_eq!(reg, stack.pop_named_reg(reg).unwrap().reg);
520835abbcdSSaúl Cabrera     }
521835abbcdSSaúl Cabrera }
522