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