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