docs and tests

This commit is contained in:
Andrew Dirksen 2018-11-22 13:10:00 -08:00
parent 47273e15cf
commit 21a8744e94
3 changed files with 84 additions and 19 deletions

View File

@ -80,6 +80,7 @@ impl<T> StackWithLimit<T> {
/// Returns Err(StackOverflow) if stack is already full.
#[inline]
pub fn push(&mut self, value: T) -> Result<(), StackOverflow> {
debug_assert!(self.stack.capacity() <= self.limit);
if self.stack.len() == self.stack.capacity() {
if self.stack.len() == self.limit {
return Err(StackOverflow);
@ -100,6 +101,17 @@ impl<T> StackWithLimit<T> {
Ok(())
}
/// Remove item from the top of a stack and return it, or `None` if the stack is empty.
///
/// ```
/// # extern crate wasmi;
/// # use wasmi::{StackWithLimit, StackSize};
/// let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
/// bstack.push(2);
/// assert_eq!(bstack.pop(), Some(2));
/// assert_eq!(bstack.len(), 0);
/// assert_eq!(bstack.pop(), None);
/// ```
pub fn pop(&mut self) -> Option<T> {
self.stack.pop()
}
@ -159,42 +171,96 @@ impl<T> StackWithLimit<T> {
/// # Panics
///
/// Panics if `a` or `b` are out of bound.
///
/// ```
/// # extern crate wasmi;
/// # use wasmi::{StackWithLimit, StackSize};
/// let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
/// bstack.push(1);
/// bstack.push(2);
/// assert_eq!(bstack.top(), Some(&2));
/// stack.swap(0, 1);
/// assert_eq!(bstack.top(), Some(&1));
/// ```
#[inline]
pub fn swap(&mut self, a: usize, b: usize) {
self.stack.swap(a, b)
}
/// Removes an element from the vector and returns it.
/// Removes an element from the stack and returns it.
///
/// The removed element is replaced by the last element of the vector.
///
/// This does not preserve ordering, but is O(1).
/// The removed element is replaced by the element at the top of the stack.
///
/// # Panics
///
/// Panics if `index` is out of bounds.
///
/// ```
/// # extern crate wasmi;
/// # use wasmi::{StackWithLimit, StackSize};
/// let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
/// bstack.push(1);
/// bstack.push(2);
/// assert_eq!(bstack.top(), Some(&2));
/// assert_eq!(stack.swap_remove(0), 1);
/// assert_eq!(bstack.top(), Some(&2));
/// ```
pub fn swap_remove(&mut self, index: usize) -> T {
self.stack.swap_remove(index)
}
/// Get a reference to the top of the stack, or `None` if the stack is empty.
///
/// ```
/// # extern crate wasmi;
/// # use wasmi::{StackWithLimit, StackSize};
/// let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
/// assert_eq!(bstack.top(), None);
/// bstack.push(2);
/// assert_eq!(bstack.top(), Some(&2));
/// ```
pub fn top(&self) -> Option<&T> {
self.stack.last()
}
/// Get a mutable reference to the top of the stack, or `None` if the stack is empty.
pub fn top_mut(&mut self) -> Option<&mut T> {
self.stack.last_mut()
}
// Same as Vec::[truncate](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.truncate)
/// Shorten the stack, keeping the bottom len elements and dropping the rest.
///
/// If new_size is greater then the current stack size, this has no effect.
pub fn truncate(&mut self, new_size: usize) {
self.stack.truncate(new_size)
}
/// Get number of items in a stack.
///
/// ```
/// # extern crate wasmi;
/// # use wasmi::{StackWithLimit, StackSize};
/// let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
/// assert_eq!(bstack.len(), 0);
/// bstack.push(1);
/// bstack.push(2);
/// assert_eq!(bstack.len(), 2);
/// ```
#[inline]
pub fn len(&self) -> usize {
self.stack.len()
}
/// Check whether the stack is empty.
///
/// ```
/// # extern crate wasmi;
/// # use wasmi::{StackWithLimit, StackSize};
/// let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
/// assert_eq!(bstack.is_empty(), true);
/// bstack.push(1);
/// assert_eq!(bstack.is_empty(), false);
/// ```
pub fn is_empty(&self) -> bool {
self.stack.is_empty()
}

View File

@ -216,6 +216,7 @@ impl Interpreter {
self.state = InterpreterState::Initialized;
}
/// Get current state of interpreter.
pub fn state(&self) -> &InterpreterState {
&self.state
}

View File

@ -1404,13 +1404,14 @@ fn pop_value(
let actual_value = if stack_is_empty && is_stack_polymorphic {
StackValueType::Any
} else {
let value_stack_min = frame_stack.top().expect("Expected a non-empty frame stack.").value_stack_len;
let value_stack_min = frame_stack
.top()
.expect("Expected a non-empty frame stack.")
.value_stack_len;
if value_stack.len() <= value_stack_min {
return Err(Error("Trying to access parent frame stack values.".into()));
}
value_stack
.pop()
.ok_or_else(|| Error("non-empty stack expected".into()))?
value_stack.pop().ok_or_else(underflow_err)?
};
match actual_value {
StackValueType::Specific(stack_value_type) if stack_value_type == value_type => Ok(actual_value),
@ -1456,10 +1457,7 @@ fn pop_label(
// Don't pop frame yet. This is essential since we still might pop values from the value stack
// and this in turn requires current frame to check whether or not we've reached
// unreachable.
let block_type = frame_stack
.top()
.ok_or_else(|| Error("non-empty stack expected".into()))?
.block_type;
let block_type = frame_stack.top().ok_or_else(underflow_err)?.block_type;
match block_type {
BlockType::NoResult => (),
BlockType::Value(required_value_type) => {
@ -1467,9 +1465,7 @@ fn pop_label(
}
}
let frame = frame_stack
.pop()
.ok_or_else(|| Error("non-empty stack expected".into()))?;
let frame = frame_stack.pop().ok_or_else(underflow_err)?;
if value_stack.len() != frame.value_stack_len {
return Err(Error(format!(
"Unexpected stack height {}, expected {}",
@ -1488,9 +1484,7 @@ fn top_label(frame_stack: &StackWithLimit<BlockFrame>) -> &BlockFrame {
}
fn require_label(depth: u32, frame_stack: &StackWithLimit<BlockFrame>) -> Result<&BlockFrame, Error> {
frame_stack
.nth_from_top(depth as usize)
.ok_or_else(|| Error("non-empty stack expected".into()))
frame_stack.nth_from_top(depth as usize).ok_or_else(underflow_err)
}
fn require_target(
@ -1718,3 +1712,7 @@ impl Sink {
self.ins
}
}
fn underflow_err() -> Error {
Error("non-empty stack expected".into())
}