1*b93e1bc0SSaúl Cabrera use crate::{codegen::CodeGenError, isa::reg::Reg, masm::StackSlot}; 2*b93e1bc0SSaúl Cabrera use anyhow::{anyhow, Result}; 31b5c4ae8SSaúl Cabrera use smallvec::SmallVec; 414b39bc2SSaúl Cabrera use wasmparser::{Ieee32, Ieee64}; 5496237c2SNick Fitzgerald use wasmtime_environ::WasmValType; 614b39bc2SSaúl Cabrera 714b39bc2SSaúl Cabrera /// A typed register value used to track register values in the value 814b39bc2SSaúl Cabrera /// stack. 914b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)] 1014b39bc2SSaúl Cabrera pub struct TypedReg { 1114b39bc2SSaúl Cabrera /// The physical register. 1214b39bc2SSaúl Cabrera pub reg: Reg, 1314b39bc2SSaúl Cabrera /// The type associated to the physical register. 14496237c2SNick Fitzgerald pub ty: WasmValType, 1514b39bc2SSaúl Cabrera } 1614b39bc2SSaúl Cabrera 1714b39bc2SSaúl Cabrera impl TypedReg { 184b288ba8SSaúl Cabrera /// Create a new [`TypedReg`]. 19496237c2SNick Fitzgerald pub fn new(ty: WasmValType, reg: Reg) -> Self { 2014b39bc2SSaúl Cabrera Self { ty, reg } 2114b39bc2SSaúl Cabrera } 2214b39bc2SSaúl Cabrera 234b288ba8SSaúl Cabrera /// Create an i64 [`TypedReg`]. 2414b39bc2SSaúl Cabrera pub fn i64(reg: Reg) -> Self { 2514b39bc2SSaúl Cabrera Self { 26496237c2SNick Fitzgerald ty: WasmValType::I64, 2714b39bc2SSaúl Cabrera reg, 2814b39bc2SSaúl Cabrera } 2914b39bc2SSaúl Cabrera } 30a109d2abSSaúl Cabrera 31f0162a40SSaúl Cabrera /// Create an i32 [`TypedReg`]. 32a109d2abSSaúl Cabrera pub fn i32(reg: Reg) -> Self { 33a109d2abSSaúl Cabrera Self { 34496237c2SNick Fitzgerald ty: WasmValType::I32, 35a109d2abSSaúl Cabrera reg, 36a109d2abSSaúl Cabrera } 37a109d2abSSaúl Cabrera } 3817091e6fSJeffrey Charles 3917091e6fSJeffrey Charles /// Create an f64 [`TypedReg`]. 4017091e6fSJeffrey Charles pub fn f64(reg: Reg) -> Self { 4117091e6fSJeffrey Charles Self { 42496237c2SNick Fitzgerald ty: WasmValType::F64, 4317091e6fSJeffrey Charles reg, 4417091e6fSJeffrey Charles } 4517091e6fSJeffrey Charles } 4617091e6fSJeffrey Charles 4717091e6fSJeffrey Charles /// Create an f32 [`TypedReg`]. 4817091e6fSJeffrey Charles pub fn f32(reg: Reg) -> Self { 4917091e6fSJeffrey Charles Self { 50496237c2SNick Fitzgerald ty: WasmValType::F32, 5117091e6fSJeffrey Charles reg, 5217091e6fSJeffrey Charles } 5317091e6fSJeffrey Charles } 5414b39bc2SSaúl Cabrera } 5514b39bc2SSaúl Cabrera 5614b39bc2SSaúl Cabrera impl From<TypedReg> for Reg { 5714b39bc2SSaúl Cabrera fn from(tr: TypedReg) -> Self { 5814b39bc2SSaúl Cabrera tr.reg 5914b39bc2SSaúl Cabrera } 6014b39bc2SSaúl Cabrera } 6114b39bc2SSaúl Cabrera 6214b39bc2SSaúl Cabrera /// A local value. 6314b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)] 6414b39bc2SSaúl Cabrera pub struct Local { 6514b39bc2SSaúl Cabrera /// The index of the local. 6614b39bc2SSaúl Cabrera pub index: u32, 6714b39bc2SSaúl Cabrera /// The type of the local. 68496237c2SNick Fitzgerald pub ty: WasmValType, 6914b39bc2SSaúl Cabrera } 7014b39bc2SSaúl Cabrera 7114b39bc2SSaúl Cabrera /// A memory value. 7214b39bc2SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)] 7314b39bc2SSaúl Cabrera pub struct Memory { 7414b39bc2SSaúl Cabrera /// The type associated with the memory offset. 75496237c2SNick Fitzgerald pub ty: WasmValType, 7614b39bc2SSaúl Cabrera /// The stack slot corresponding to the memory value. 7714b39bc2SSaúl Cabrera pub slot: StackSlot, 7814b39bc2SSaúl Cabrera } 79835abbcdSSaúl Cabrera 80835abbcdSSaúl Cabrera /// Value definition to be used within the shadow stack. 81a50c4972SSaúl Cabrera #[derive(Debug, Eq, PartialEq, Copy, Clone)] 82835abbcdSSaúl Cabrera pub(crate) enum Val { 83835abbcdSSaúl Cabrera /// I32 Constant. 84835abbcdSSaúl Cabrera I32(i32), 857c5c7e4bSSaúl Cabrera /// I64 Constant. 867c5c7e4bSSaúl Cabrera I64(i64), 8714b39bc2SSaúl Cabrera /// F32 Constant. 8814b39bc2SSaúl Cabrera F32(Ieee32), 8914b39bc2SSaúl Cabrera /// F64 Constant. 9014b39bc2SSaúl Cabrera F64(Ieee64), 91fa9a948dSJeffrey Charles /// V128 Constant. 92fa9a948dSJeffrey Charles V128(i128), 9314b39bc2SSaúl Cabrera /// A register value. 9414b39bc2SSaúl Cabrera Reg(TypedReg), 95835abbcdSSaúl Cabrera /// A local slot. 9614b39bc2SSaúl Cabrera Local(Local), 97835abbcdSSaúl Cabrera /// Offset to a memory location. 9814b39bc2SSaúl Cabrera Memory(Memory), 9914b39bc2SSaúl Cabrera } 10014b39bc2SSaúl Cabrera 10114b39bc2SSaúl Cabrera impl From<TypedReg> for Val { 10214b39bc2SSaúl Cabrera fn from(tr: TypedReg) -> Self { 10314b39bc2SSaúl Cabrera Val::Reg(tr) 10414b39bc2SSaúl Cabrera } 10514b39bc2SSaúl Cabrera } 10614b39bc2SSaúl Cabrera 10714b39bc2SSaúl Cabrera impl From<Local> for Val { 10814b39bc2SSaúl Cabrera fn from(local: Local) -> Self { 10914b39bc2SSaúl Cabrera Val::Local(local) 11014b39bc2SSaúl Cabrera } 11114b39bc2SSaúl Cabrera } 11214b39bc2SSaúl Cabrera 11314b39bc2SSaúl Cabrera impl From<Memory> for Val { 11414b39bc2SSaúl Cabrera fn from(mem: Memory) -> Self { 11514b39bc2SSaúl Cabrera Val::Memory(mem) 11614b39bc2SSaúl Cabrera } 117835abbcdSSaúl Cabrera } 118835abbcdSSaúl Cabrera 1194b288ba8SSaúl Cabrera impl TryFrom<u32> for Val { 1204b288ba8SSaúl Cabrera type Error = anyhow::Error; 1214b288ba8SSaúl Cabrera fn try_from(value: u32) -> Result<Self, Self::Error> { 1224b288ba8SSaúl Cabrera i32::try_from(value).map(Val::i32).map_err(Into::into) 1234b288ba8SSaúl Cabrera } 1244b288ba8SSaúl Cabrera } 1254b288ba8SSaúl Cabrera 126835abbcdSSaúl Cabrera impl Val { 127835abbcdSSaúl Cabrera /// Create a new I32 constant value. 128835abbcdSSaúl Cabrera pub fn i32(v: i32) -> Self { 129835abbcdSSaúl Cabrera Self::I32(v) 130835abbcdSSaúl Cabrera } 131835abbcdSSaúl Cabrera 1327c5c7e4bSSaúl Cabrera /// Create a new I64 constant value. 1337c5c7e4bSSaúl Cabrera pub fn i64(v: i64) -> Self { 1347c5c7e4bSSaúl Cabrera Self::I64(v) 1357c5c7e4bSSaúl Cabrera } 1367c5c7e4bSSaúl Cabrera 13714b39bc2SSaúl Cabrera /// Create a new F32 constant value. 13814b39bc2SSaúl Cabrera pub fn f32(v: Ieee32) -> Self { 13914b39bc2SSaúl Cabrera Self::F32(v) 14014b39bc2SSaúl Cabrera } 14114b39bc2SSaúl Cabrera 14214b39bc2SSaúl Cabrera pub fn f64(v: Ieee64) -> Self { 14314b39bc2SSaúl Cabrera Self::F64(v) 14414b39bc2SSaúl Cabrera } 14514b39bc2SSaúl Cabrera 146fa9a948dSJeffrey Charles /// Create a new V128 constant value. 147fa9a948dSJeffrey Charles pub fn v128(v: i128) -> Self { 148fa9a948dSJeffrey Charles Self::V128(v) 149fa9a948dSJeffrey Charles } 150fa9a948dSJeffrey Charles 151835abbcdSSaúl Cabrera /// Create a new Reg value. 152496237c2SNick Fitzgerald pub fn reg(reg: Reg, ty: WasmValType) -> Self { 15314b39bc2SSaúl Cabrera Self::Reg(TypedReg { reg, ty }) 154835abbcdSSaúl Cabrera } 155835abbcdSSaúl Cabrera 156835abbcdSSaúl Cabrera /// Create a new Local value. 157496237c2SNick Fitzgerald pub fn local(index: u32, ty: WasmValType) -> Self { 15814b39bc2SSaúl Cabrera Self::Local(Local { index, ty }) 15914b39bc2SSaúl Cabrera } 16014b39bc2SSaúl Cabrera 16114b39bc2SSaúl Cabrera /// Create a Memory value. 162496237c2SNick Fitzgerald pub fn mem(ty: WasmValType, slot: StackSlot) -> Self { 16314b39bc2SSaúl Cabrera Self::Memory(Memory { ty, slot }) 164835abbcdSSaúl Cabrera } 165835abbcdSSaúl Cabrera 166835abbcdSSaúl Cabrera /// Check whether the value is a register. 167835abbcdSSaúl Cabrera pub fn is_reg(&self) -> bool { 168835abbcdSSaúl Cabrera match *self { 169835abbcdSSaúl Cabrera Self::Reg(_) => true, 170835abbcdSSaúl Cabrera _ => false, 171835abbcdSSaúl Cabrera } 172835abbcdSSaúl Cabrera } 173835abbcdSSaúl Cabrera 1740e9121daSFrankReh /// Check whether the value is a memory offset. 175af4d94c8SSaúl Cabrera pub fn is_mem(&self) -> bool { 176af4d94c8SSaúl Cabrera match *self { 177af4d94c8SSaúl Cabrera Self::Memory(_) => true, 178af4d94c8SSaúl Cabrera _ => false, 179af4d94c8SSaúl Cabrera } 180af4d94c8SSaúl Cabrera } 181af4d94c8SSaúl Cabrera 18255f9a4bdSJeffrey Charles /// Check whether the value is a constant. 18355f9a4bdSJeffrey Charles pub fn is_const(&self) -> bool { 18455f9a4bdSJeffrey Charles match *self { 185fa9a948dSJeffrey Charles Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true, 18655f9a4bdSJeffrey Charles _ => false, 18755f9a4bdSJeffrey Charles } 18855f9a4bdSJeffrey Charles } 18955f9a4bdSJeffrey Charles 190321294a5SJeffrey Charles /// Check whether the value is local with a particular index. 191321294a5SJeffrey Charles pub fn is_local_at_index(&self, index: u32) -> bool { 192321294a5SJeffrey Charles match *self { 193321294a5SJeffrey Charles Self::Local(Local { index: i, .. }) if i == index => true, 194321294a5SJeffrey Charles _ => false, 195321294a5SJeffrey Charles } 196321294a5SJeffrey Charles } 197321294a5SJeffrey Charles 198835abbcdSSaúl Cabrera /// Get the register representation of the value. 199835abbcdSSaúl Cabrera /// 200835abbcdSSaúl Cabrera /// # Panics 201835abbcdSSaúl Cabrera /// This method will panic if the value is not a register. 202f0162a40SSaúl Cabrera pub fn unwrap_reg(&self) -> TypedReg { 203835abbcdSSaúl Cabrera match self { 20414b39bc2SSaúl Cabrera Self::Reg(tr) => *tr, 205a0442ea0SHamir Mahal v => panic!("expected value {v:?} to be a register"), 206835abbcdSSaúl Cabrera } 207835abbcdSSaúl Cabrera } 208835abbcdSSaúl Cabrera 209835abbcdSSaúl Cabrera /// Get the integer representation of the value. 210835abbcdSSaúl Cabrera /// 211835abbcdSSaúl Cabrera /// # Panics 212835abbcdSSaúl Cabrera /// This method will panic if the value is not an i32. 213f0162a40SSaúl Cabrera pub fn unwrap_i32(&self) -> i32 { 214835abbcdSSaúl Cabrera match self { 215835abbcdSSaúl Cabrera Self::I32(v) => *v, 216a0442ea0SHamir Mahal v => panic!("expected value {v:?} to be i32"), 217835abbcdSSaúl Cabrera } 218835abbcdSSaúl Cabrera } 219835abbcdSSaúl Cabrera 2207c5c7e4bSSaúl Cabrera /// Get the integer representation of the value. 2217c5c7e4bSSaúl Cabrera /// 2227c5c7e4bSSaúl Cabrera /// # Panics 2237c5c7e4bSSaúl Cabrera /// This method will panic if the value is not an i64. 224f0162a40SSaúl Cabrera pub fn unwrap_i64(&self) -> i64 { 2257c5c7e4bSSaúl Cabrera match self { 2267c5c7e4bSSaúl Cabrera Self::I64(v) => *v, 227a0442ea0SHamir Mahal v => panic!("expected value {v:?} to be i64"), 2287c5c7e4bSSaúl Cabrera } 2297c5c7e4bSSaúl Cabrera } 2307c5c7e4bSSaúl Cabrera 231f0162a40SSaúl Cabrera /// Returns the underlying memory value if it is one, panics otherwise. 232f0162a40SSaúl Cabrera pub fn unwrap_mem(&self) -> Memory { 233f0162a40SSaúl Cabrera match self { 234f0162a40SSaúl Cabrera Self::Memory(m) => *m, 235a0442ea0SHamir Mahal v => panic!("expected value {v:?} to be a Memory"), 236f0162a40SSaúl Cabrera } 237f0162a40SSaúl Cabrera } 238f0162a40SSaúl Cabrera 239835abbcdSSaúl Cabrera /// Check whether the value is an i32 constant. 240835abbcdSSaúl Cabrera pub fn is_i32_const(&self) -> bool { 241835abbcdSSaúl Cabrera match *self { 242835abbcdSSaúl Cabrera Self::I32(_) => true, 243835abbcdSSaúl Cabrera _ => false, 244835abbcdSSaúl Cabrera } 245835abbcdSSaúl Cabrera } 2467c5c7e4bSSaúl Cabrera 2477c5c7e4bSSaúl Cabrera /// Check whether the value is an i64 constant. 2487c5c7e4bSSaúl Cabrera pub fn is_i64_const(&self) -> bool { 2497c5c7e4bSSaúl Cabrera match *self { 2507c5c7e4bSSaúl Cabrera Self::I64(_) => true, 2517c5c7e4bSSaúl Cabrera _ => false, 2527c5c7e4bSSaúl Cabrera } 2537c5c7e4bSSaúl Cabrera } 25414b39bc2SSaúl Cabrera 25514b39bc2SSaúl Cabrera /// Get the type of the value. 256496237c2SNick Fitzgerald pub fn ty(&self) -> WasmValType { 25714b39bc2SSaúl Cabrera match self { 258496237c2SNick Fitzgerald Val::I32(_) => WasmValType::I32, 259496237c2SNick Fitzgerald Val::I64(_) => WasmValType::I64, 260496237c2SNick Fitzgerald Val::F32(_) => WasmValType::F32, 261496237c2SNick Fitzgerald Val::F64(_) => WasmValType::F64, 262fa9a948dSJeffrey Charles Val::V128(_) => WasmValType::V128, 26314b39bc2SSaúl Cabrera Val::Reg(r) => r.ty, 26414b39bc2SSaúl Cabrera Val::Memory(m) => m.ty, 26514b39bc2SSaúl Cabrera Val::Local(l) => l.ty, 26614b39bc2SSaúl Cabrera } 26714b39bc2SSaúl Cabrera } 268835abbcdSSaúl Cabrera } 269835abbcdSSaúl Cabrera 270835abbcdSSaúl Cabrera /// The shadow stack used for compilation. 271835abbcdSSaúl Cabrera #[derive(Default, Debug)] 272835abbcdSSaúl Cabrera pub(crate) struct Stack { 2731b5c4ae8SSaúl Cabrera // NB: The 64 is chosen arbitrarily. We can adjust as we see fit. 2741b5c4ae8SSaúl Cabrera inner: SmallVec<[Val; 64]>, 275835abbcdSSaúl Cabrera } 276835abbcdSSaúl Cabrera 277835abbcdSSaúl Cabrera impl Stack { 278835abbcdSSaúl Cabrera /// Allocate a new stack. 279835abbcdSSaúl Cabrera pub fn new() -> Self { 280835abbcdSSaúl Cabrera Self { 281835abbcdSSaúl Cabrera inner: Default::default(), 282835abbcdSSaúl Cabrera } 283835abbcdSSaúl Cabrera } 284835abbcdSSaúl Cabrera 285*b93e1bc0SSaúl Cabrera /// Ensures that there are at least `n` elements in the value stack, 286*b93e1bc0SSaúl Cabrera /// and returns the index calculated by: stack length minus `n`. 287*b93e1bc0SSaúl Cabrera pub fn ensure_index_at(&self, n: usize) -> Result<usize> { 288*b93e1bc0SSaúl Cabrera if self.len() >= n { 289*b93e1bc0SSaúl Cabrera Ok(self.len() - n) 290*b93e1bc0SSaúl Cabrera } else { 291*b93e1bc0SSaúl Cabrera Err(anyhow!(CodeGenError::missing_values_in_stack())) 292*b93e1bc0SSaúl Cabrera } 293*b93e1bc0SSaúl Cabrera } 294*b93e1bc0SSaúl Cabrera 295321294a5SJeffrey Charles /// Returns true if the stack contains a local with the provided index 296321294a5SJeffrey Charles /// except if the only time the local appears is the top element. 297321294a5SJeffrey Charles pub fn contains_latent_local(&self, index: u32) -> bool { 298321294a5SJeffrey Charles self.inner 299321294a5SJeffrey Charles .iter() 300321294a5SJeffrey Charles // Iterate top-to-bottom so we can skip the top element and stop 301321294a5SJeffrey Charles // when we see a memory element. 302321294a5SJeffrey Charles .rev() 303321294a5SJeffrey Charles // The local is not latent if it's the top element because the top 304321294a5SJeffrey Charles // element will be popped next which materializes the local. 305321294a5SJeffrey Charles .skip(1) 306321294a5SJeffrey Charles // Stop when we see a memory element because that marks where we 307321294a5SJeffrey Charles // spilled up to so there will not be any locals past this point. 308321294a5SJeffrey Charles .take_while(|v| !v.is_mem()) 309321294a5SJeffrey Charles .any(|v| v.is_local_at_index(index)) 310321294a5SJeffrey Charles } 311321294a5SJeffrey Charles 312a109d2abSSaúl Cabrera /// Extend the stack with the given elements. 313a109d2abSSaúl Cabrera pub fn extend(&mut self, values: impl IntoIterator<Item = Val>) { 314a109d2abSSaúl Cabrera self.inner.extend(values); 315a109d2abSSaúl Cabrera } 316a109d2abSSaúl Cabrera 317a109d2abSSaúl Cabrera /// Inserts many values at the given index. 3181b5c4ae8SSaúl Cabrera pub fn insert_many(&mut self, at: usize, values: &[Val]) { 319a109d2abSSaúl Cabrera debug_assert!(at <= self.len()); 3201b5c4ae8SSaúl Cabrera 3211b5c4ae8SSaúl Cabrera if at == self.len() { 3221b5c4ae8SSaúl Cabrera self.inner.extend_from_slice(values); 323a109d2abSSaúl Cabrera } else { 3241b5c4ae8SSaúl Cabrera self.inner.insert_from_slice(at, values); 325a109d2abSSaúl Cabrera } 32620c58362SSaúl Cabrera } 32720c58362SSaúl Cabrera 328af4d94c8SSaúl Cabrera /// Get the length of the stack. 329af4d94c8SSaúl Cabrera pub fn len(&self) -> usize { 330af4d94c8SSaúl Cabrera self.inner.len() 331af4d94c8SSaúl Cabrera } 332af4d94c8SSaúl Cabrera 333835abbcdSSaúl Cabrera /// Push a value to the stack. 334835abbcdSSaúl Cabrera pub fn push(&mut self, val: Val) { 3357690c500STrevor Elliott self.inner.push(val); 336835abbcdSSaúl Cabrera } 337835abbcdSSaúl Cabrera 338835abbcdSSaúl Cabrera /// Peek into the top in the stack. 3397c5c7e4bSSaúl Cabrera pub fn peek(&self) -> Option<&Val> { 3407690c500STrevor Elliott self.inner.last() 341835abbcdSSaúl Cabrera } 342835abbcdSSaúl Cabrera 343af4d94c8SSaúl Cabrera /// Returns an iterator referencing the last n items of the stack, 344af4d94c8SSaúl Cabrera /// in bottom-most to top-most order. 345af4d94c8SSaúl Cabrera pub fn peekn(&self, n: usize) -> impl Iterator<Item = &Val> + '_ { 346af4d94c8SSaúl Cabrera let len = self.len(); 347af4d94c8SSaúl Cabrera assert!(n <= len); 348af4d94c8SSaúl Cabrera 349af4d94c8SSaúl Cabrera let partition = len - n; 3507690c500STrevor Elliott self.inner[partition..].into_iter() 351af4d94c8SSaúl Cabrera } 352af4d94c8SSaúl Cabrera 353835abbcdSSaúl Cabrera /// Pops the top element of the stack, if any. 354835abbcdSSaúl Cabrera pub fn pop(&mut self) -> Option<Val> { 3557690c500STrevor Elliott self.inner.pop() 356835abbcdSSaúl Cabrera } 357835abbcdSSaúl Cabrera 3587c5c7e4bSSaúl Cabrera /// Pops the element at the top of the stack if it is an i32 const; 359835abbcdSSaúl Cabrera /// returns `None` otherwise. 360835abbcdSSaúl Cabrera pub fn pop_i32_const(&mut self) -> Option<i32> { 361835abbcdSSaúl Cabrera match self.peek() { 362f0162a40SSaúl Cabrera Some(v) => v.is_i32_const().then(|| self.pop().unwrap().unwrap_i32()), 363835abbcdSSaúl Cabrera _ => None, 364835abbcdSSaúl Cabrera } 365835abbcdSSaúl Cabrera } 366835abbcdSSaúl Cabrera 3677c5c7e4bSSaúl Cabrera /// Pops the element at the top of the stack if it is an i64 const; 3687c5c7e4bSSaúl Cabrera /// returns `None` otherwise. 3697c5c7e4bSSaúl Cabrera pub fn pop_i64_const(&mut self) -> Option<i64> { 3707c5c7e4bSSaúl Cabrera match self.peek() { 371f0162a40SSaúl Cabrera Some(v) => v.is_i64_const().then(|| self.pop().unwrap().unwrap_i64()), 3727c5c7e4bSSaúl Cabrera _ => None, 3737c5c7e4bSSaúl Cabrera } 3747c5c7e4bSSaúl Cabrera } 3757c5c7e4bSSaúl Cabrera 376835abbcdSSaúl Cabrera /// Pops the element at the top of the stack if it is a register; 377835abbcdSSaúl Cabrera /// returns `None` otherwise. 37814b39bc2SSaúl Cabrera pub fn pop_reg(&mut self) -> Option<TypedReg> { 379835abbcdSSaúl Cabrera match self.peek() { 380f0162a40SSaúl Cabrera Some(v) => v.is_reg().then(|| self.pop().unwrap().unwrap_reg()), 381835abbcdSSaúl Cabrera _ => None, 382835abbcdSSaúl Cabrera } 383835abbcdSSaúl Cabrera } 384835abbcdSSaúl Cabrera 385835abbcdSSaúl Cabrera /// Pops the given register if it is at the top of the stack; 386835abbcdSSaúl Cabrera /// returns `None` otherwise. 38714b39bc2SSaúl Cabrera pub fn pop_named_reg(&mut self, reg: Reg) -> Option<TypedReg> { 388835abbcdSSaúl Cabrera match self.peek() { 38914b39bc2SSaúl Cabrera Some(v) => { 390f0162a40SSaúl Cabrera (v.is_reg() && v.unwrap_reg().reg == reg).then(|| self.pop().unwrap().unwrap_reg()) 39114b39bc2SSaúl Cabrera } 392835abbcdSSaúl Cabrera _ => None, 393835abbcdSSaúl Cabrera } 394835abbcdSSaúl Cabrera } 395835abbcdSSaúl Cabrera 396835abbcdSSaúl Cabrera /// Get a mutable reference to the inner stack representation. 3971b5c4ae8SSaúl Cabrera pub fn inner_mut(&mut self) -> &mut SmallVec<[Val; 64]> { 398835abbcdSSaúl Cabrera &mut self.inner 399835abbcdSSaúl Cabrera } 40050733725SSaúl Cabrera 401446a7f5eSSaúl Cabrera /// Get a reference to the inner stack representation. 4021b5c4ae8SSaúl Cabrera pub fn inner(&self) -> &SmallVec<[Val; 64]> { 403446a7f5eSSaúl Cabrera &self.inner 404446a7f5eSSaúl Cabrera } 405446a7f5eSSaúl Cabrera 40650733725SSaúl Cabrera /// Calculates the size of, in bytes, of the top n [Memory] entries 40750733725SSaúl Cabrera /// in the value stack. 40850733725SSaúl Cabrera pub fn sizeof(&self, top: usize) -> u32 { 40950733725SSaúl Cabrera self.peekn(top).fold(0, |acc, v| { 41050733725SSaúl Cabrera if v.is_mem() { 41150733725SSaúl Cabrera acc + v.unwrap_mem().slot.size 41250733725SSaúl Cabrera } else { 41350733725SSaúl Cabrera acc 41450733725SSaúl Cabrera } 41550733725SSaúl Cabrera }) 41650733725SSaúl Cabrera } 417835abbcdSSaúl Cabrera } 418835abbcdSSaúl Cabrera 419835abbcdSSaúl Cabrera #[cfg(test)] 420835abbcdSSaúl Cabrera mod tests { 421835abbcdSSaúl Cabrera use super::{Stack, Val}; 422835abbcdSSaúl Cabrera use crate::isa::reg::Reg; 423496237c2SNick Fitzgerald use wasmtime_environ::WasmValType; 424835abbcdSSaúl Cabrera 425835abbcdSSaúl Cabrera #[test] 426835abbcdSSaúl Cabrera fn test_pop_i32_const() { 427835abbcdSSaúl Cabrera let mut stack = Stack::new(); 428835abbcdSSaúl Cabrera stack.push(Val::i32(33i32)); 429835abbcdSSaúl Cabrera assert_eq!(33, stack.pop_i32_const().unwrap()); 430835abbcdSSaúl Cabrera 431496237c2SNick Fitzgerald stack.push(Val::local(10, WasmValType::I32)); 432835abbcdSSaúl Cabrera assert!(stack.pop_i32_const().is_none()); 433835abbcdSSaúl Cabrera } 434835abbcdSSaúl Cabrera 435835abbcdSSaúl Cabrera #[test] 436835abbcdSSaúl Cabrera fn test_pop_reg() { 437835abbcdSSaúl Cabrera let mut stack = Stack::new(); 438835abbcdSSaúl Cabrera let reg = Reg::int(2usize); 439496237c2SNick Fitzgerald stack.push(Val::reg(reg, WasmValType::I32)); 440835abbcdSSaúl Cabrera stack.push(Val::i32(4)); 441835abbcdSSaúl Cabrera 442835abbcdSSaúl Cabrera assert_eq!(None, stack.pop_reg()); 443835abbcdSSaúl Cabrera let _ = stack.pop().unwrap(); 44414b39bc2SSaúl Cabrera assert_eq!(reg, stack.pop_reg().unwrap().reg); 445835abbcdSSaúl Cabrera } 446835abbcdSSaúl Cabrera 447835abbcdSSaúl Cabrera #[test] 448835abbcdSSaúl Cabrera fn test_pop_named_reg() { 449835abbcdSSaúl Cabrera let mut stack = Stack::new(); 450835abbcdSSaúl Cabrera let reg = Reg::int(2usize); 451496237c2SNick Fitzgerald stack.push(Val::reg(reg, WasmValType::I32)); 452496237c2SNick Fitzgerald stack.push(Val::reg(Reg::int(4), WasmValType::I32)); 453835abbcdSSaúl Cabrera 454835abbcdSSaúl Cabrera assert_eq!(None, stack.pop_named_reg(reg)); 455835abbcdSSaúl Cabrera let _ = stack.pop().unwrap(); 45614b39bc2SSaúl Cabrera assert_eq!(reg, stack.pop_named_reg(reg).unwrap().reg); 457835abbcdSSaúl Cabrera } 458835abbcdSSaúl Cabrera } 459