mod vref;
#[cfg(test)]
mod tests;
pub use self::vref::ValueStackRef;
use super::{err_stack_overflow, DEFAULT_MAX_VALUE_STACK_HEIGHT, DEFAULT_MIN_VALUE_STACK_HEIGHT};
use crate::core::TrapCode;
use alloc::vec::Vec;
use core::{fmt, fmt::Debug, iter, mem::size_of};
use wasmi_core::UntypedValue;
#[derive(Clone)]
pub struct ValueStack {
entries: Vec<UntypedValue>,
stack_ptr: usize,
maximum_len: usize,
}
impl Debug for ValueStack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ValueStack")
.field("stack_ptr", &self.stack_ptr)
.field("entries", &&self.entries[..self.stack_ptr])
.finish()
}
}
impl PartialEq for ValueStack {
fn eq(&self, other: &Self) -> bool {
self.stack_ptr == other.stack_ptr
&& self.entries[..self.stack_ptr] == other.entries[..other.stack_ptr]
}
}
impl Eq for ValueStack {}
impl Default for ValueStack {
fn default() -> Self {
let register_len = size_of::<UntypedValue>();
Self::new(
DEFAULT_MIN_VALUE_STACK_HEIGHT / register_len,
DEFAULT_MAX_VALUE_STACK_HEIGHT / register_len,
)
}
}
impl Extend<UntypedValue> for ValueStack {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = UntypedValue>,
{
for item in iter {
self.push(item)
}
}
}
impl FromIterator<UntypedValue> for ValueStack {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = UntypedValue>,
{
let mut stack = ValueStack::default();
stack.extend(iter);
stack
}
}
impl ValueStack {
pub fn empty() -> Self {
Self {
entries: Vec::new(),
stack_ptr: 0,
maximum_len: 0,
}
}
pub fn is_empty(&self) -> bool {
self.entries.capacity() == 0
}
pub fn new(initial_len: usize, maximum_len: usize) -> Self {
assert!(
initial_len > 0,
"cannot initialize the value stack with zero length",
);
assert!(
initial_len <= maximum_len,
"initial value stack length is greater than maximum value stack length",
);
let entries = vec![UntypedValue::default(); initial_len];
Self {
entries,
stack_ptr: 0,
maximum_len,
}
}
fn get_release_unchecked_mut(&mut self, index: usize) -> &mut UntypedValue {
debug_assert!(index < self.capacity());
unsafe { self.entries.get_unchecked_mut(index) }
}
pub fn extend_zeros(&mut self, additional: usize) -> Result<(), TrapCode> {
let cells = self
.entries
.get_mut(self.stack_ptr..self.stack_ptr + additional)
.ok_or(TrapCode::StackOverflow)?;
cells.fill(UntypedValue::default());
self.stack_ptr += additional;
Ok(())
}
pub fn drop(&mut self, depth: usize) {
self.stack_ptr -= depth;
}
pub fn push<T>(&mut self, entry: T)
where
T: Into<UntypedValue>,
{
*self.get_release_unchecked_mut(self.stack_ptr) = entry.into();
self.stack_ptr += 1;
}
fn capacity(&self) -> usize {
self.entries.len()
}
pub fn len(&self) -> usize {
self.stack_ptr
}
pub fn reserve(&mut self, additional: usize) -> Result<(), TrapCode> {
let new_len = self
.len()
.checked_add(additional)
.filter(|&new_len| new_len <= self.maximum_len)
.ok_or_else(err_stack_overflow)?;
if new_len > self.capacity() {
self.entries
.extend(iter::repeat(UntypedValue::default()).take(new_len));
}
Ok(())
}
pub fn drain(&mut self) -> &[UntypedValue] {
let len = self.stack_ptr;
self.stack_ptr = 0;
&self.entries[0..len]
}
pub fn peek_as_slice_mut(&mut self, depth: usize) -> &mut [UntypedValue] {
let start = self.stack_ptr - depth;
let end = self.stack_ptr;
&mut self.entries[start..end]
}
pub fn clear(&mut self) {
self.stack_ptr = 0;
}
}