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