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. /// Returns Err(StackOverflow) if stack is already full.
#[inline] #[inline]
pub fn push(&mut self, value: T) -> Result<(), StackOverflow> { 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.stack.capacity() {
if self.stack.len() == self.limit { if self.stack.len() == self.limit {
return Err(StackOverflow); return Err(StackOverflow);
@ -100,6 +101,17 @@ impl<T> StackWithLimit<T> {
Ok(()) 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> { pub fn pop(&mut self) -> Option<T> {
self.stack.pop() self.stack.pop()
} }
@ -159,42 +171,96 @@ impl<T> StackWithLimit<T> {
/// # Panics /// # Panics
/// ///
/// Panics if `a` or `b` are out of bound. /// 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] #[inline]
pub fn swap(&mut self, a: usize, b: usize) { pub fn swap(&mut self, a: usize, b: usize) {
self.stack.swap(a, b) 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. /// The removed element is replaced by the element at the top of the stack.
///
/// This does not preserve ordering, but is O(1).
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if `index` is out of bounds. /// 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 { pub fn swap_remove(&mut self, index: usize) -> T {
self.stack.swap_remove(index) 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> { pub fn top(&self) -> Option<&T> {
self.stack.last() 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> { pub fn top_mut(&mut self) -> Option<&mut T> {
self.stack.last_mut() 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) { pub fn truncate(&mut self, new_size: usize) {
self.stack.truncate(new_size) 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] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.stack.len() 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 { pub fn is_empty(&self) -> bool {
self.stack.is_empty() self.stack.is_empty()
} }

View File

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

View File

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