simplify stacksize api
This commit is contained in:
parent
ab67889223
commit
b76ad46a94
|
@ -26,26 +26,6 @@ impl<T> StackWithLimit<T> {
|
||||||
/// Create a StackWithLimit with `limit` max size and `initial_size` of pre-allocated
|
/// Create a StackWithLimit with `limit` max size and `initial_size` of pre-allocated
|
||||||
/// memory.
|
/// memory.
|
||||||
///
|
///
|
||||||
/// ```
|
|
||||||
/// # extern crate wasmi;
|
|
||||||
/// # use wasmi::{StackWithLimit, StackSize, FuncRef};
|
|
||||||
/// StackWithLimit::<FuncRef>::new(
|
|
||||||
/// StackSize::from_element_count(1024).into_initial(),
|
|
||||||
/// StackSize::from_element_count(2048).into_limit(),
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Unlimited
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # extern crate wasmi;
|
|
||||||
/// # use wasmi::{StackWithLimit, StackSize, RuntimeValue};
|
|
||||||
/// StackWithLimit::<RuntimeValue>::new(
|
|
||||||
/// StackSize::from_element_count(1024).into_initial(),
|
|
||||||
/// StackSize::unlimited(),
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// In debug mode, panics if `initial_size` is larger than `limit`.
|
/// In debug mode, panics if `initial_size` is larger than `limit`.
|
||||||
|
@ -63,12 +43,6 @@ impl<T> StackWithLimit<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an new StackWithLimit with `limit` max size and `limit` elements pre-allocated
|
/// Create an new StackWithLimit with `limit` max size and `limit` elements pre-allocated
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # extern crate wasmi;
|
|
||||||
/// # use wasmi::{StackWithLimit, StackSize};
|
|
||||||
/// let bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
|
||||||
/// ```
|
|
||||||
pub fn with_size(size: StackSize<T>) -> StackWithLimit<T> {
|
pub fn with_size(size: StackSize<T>) -> StackWithLimit<T> {
|
||||||
StackWithLimit::new(StackSizeInitial(size), StackSizeLimit(size))
|
StackWithLimit::new(StackSizeInitial(size), StackSizeLimit(size))
|
||||||
}
|
}
|
||||||
|
@ -102,21 +76,11 @@ impl<T> StackWithLimit<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove item from the top of a stack and return it, or `None` if the stack is empty.
|
/// 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove and Return top element. Does not check for emptyness.
|
/// Remove and return top element. Does not check for emptiness.
|
||||||
/// If this is called on a zero length stack, bad things will happen.
|
/// If this is called on a zero length stack, bad things will happen.
|
||||||
/// Do not call this method unless you can prove the stack has length.
|
/// Do not call this method unless you can prove the stack has length.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -132,15 +96,6 @@ impl<T> StackWithLimit<T> {
|
||||||
/// `bstack.nth_from_top(0)` gets the top of the stack
|
/// `bstack.nth_from_top(0)` gets the top of the stack
|
||||||
///
|
///
|
||||||
/// `bstack.nth_from_top(1)` gets the item just below the stack
|
/// `bstack.nth_from_top(1)` gets the item just below the stack
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # extern crate wasmi;
|
|
||||||
/// # use wasmi::{StackWithLimit, StackSize};
|
|
||||||
/// let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
|
||||||
/// bstack.push(4);
|
|
||||||
/// assert_eq!(bstack.nth_from_top(0), Some(&4));
|
|
||||||
/// assert_eq!(bstack.nth_from_top(1), None);
|
|
||||||
/// ```
|
|
||||||
pub fn nth_from_top(&self, depth: usize) -> Option<&T> {
|
pub fn nth_from_top(&self, depth: usize) -> Option<&T> {
|
||||||
// Be cognizant of integer underflow and overflow here. Both are possible in this situation.
|
// Be cognizant of integer underflow and overflow here. Both are possible in this situation.
|
||||||
// len() is unsigned, so if len() == 0, subtraction is a problem
|
// len() is unsigned, so if len() == 0, subtraction is a problem
|
||||||
|
@ -176,54 +131,12 @@ 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));
|
|
||||||
/// bstack.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 stack and returns it.
|
|
||||||
///
|
|
||||||
/// 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!(bstack.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.
|
/// 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()
|
||||||
}
|
}
|
||||||
|
@ -241,55 +154,17 @@ impl<T> StackWithLimit<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get number of items in a stack.
|
/// 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.
|
/// 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Why introduce the extra complexity of StackSizeLimit, StackSizeInitial, and StackSize?
|
|
||||||
// We want to make the user to do the correct thing using the type checker.
|
|
||||||
// Check out the excellent Rust API Guidelines (linked below) for suggestions
|
|
||||||
// about type safety in rust.
|
|
||||||
//
|
|
||||||
// By introducing the new typed arguments, we turn:
|
|
||||||
//
|
|
||||||
// ```
|
|
||||||
// pub fn new(initial_size: usize, limit: usize) -> StackWithLimit<T> { ... }
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// into:
|
|
||||||
//
|
|
||||||
// ```
|
|
||||||
// pub fn new(initial_size: StackSizeInitial<T>, limit: StackSizeLimit<T>) -> StackWithLimit<T> { ... }
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// https://rust-lang-nursery.github.io/api-guidelines/type-safety.html#c-custom-type
|
|
||||||
|
|
||||||
/// Type for communicating the size of some contigous container.
|
/// Type for communicating the size of some contigous container.
|
||||||
/// Used for constructing both [`StackSizeLimit`] and [`StackSizeInitial`].
|
/// Used for constructing both [`StackSizeLimit`] and [`StackSizeInitial`].
|
||||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||||
|
@ -314,13 +189,6 @@ impl<T> Copy for StackSize<T> {}
|
||||||
|
|
||||||
impl<T> StackSize<T> {
|
impl<T> StackSize<T> {
|
||||||
/// Create StackSize based on number of elements.
|
/// Create StackSize based on number of elements.
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # extern crate wasmi;
|
|
||||||
/// # use wasmi::StackSize;
|
|
||||||
/// let ss = StackSize::<(u8, u8)>::from_element_count(10);
|
|
||||||
/// assert_eq!(ss.element_count(), 10);
|
|
||||||
/// ```
|
|
||||||
pub fn from_element_count(num_elements: usize) -> StackSize<T> {
|
pub fn from_element_count(num_elements: usize) -> StackSize<T> {
|
||||||
StackSize {
|
StackSize {
|
||||||
num_elements,
|
num_elements,
|
||||||
|
@ -328,51 +196,12 @@ impl<T> StackSize<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute StackSize based on allowable memory.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # extern crate wasmi;
|
|
||||||
/// # use wasmi::StackSize;
|
|
||||||
/// let ss = StackSize::<(u8, u8)>::from_byte_count(10);
|
|
||||||
/// assert_eq!(ss.element_count(), 10 / 2);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// In debug mode, panics if size of `T` is 0.
|
|
||||||
pub fn from_byte_count(num_bytes: usize) -> StackSize<T> {
|
|
||||||
// This debug_assert should catch logical errors.
|
|
||||||
debug_assert!(::core::mem::size_of::<T>() != 0, "That doesn't make sense.");
|
|
||||||
|
|
||||||
// In case a zero sized T still makes it into prod. We assume unlimited stack
|
|
||||||
// size instead of panicking.
|
|
||||||
let element_count = if ::core::mem::size_of::<T>() != 0 {
|
|
||||||
num_bytes / ::core::mem::size_of::<T>()
|
|
||||||
} else {
|
|
||||||
usize::MAX // Semi-relevant fun fact: Vec::<()>::new().capacity() == usize::MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
StackSize::from_element_count(element_count)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return number the of elements this StackSize indicates.
|
/// Return number the of elements this StackSize indicates.
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use wasmi::StackSize;
|
|
||||||
/// let ss = StackSize::<(u8, u8)>::from_element_count(10);
|
|
||||||
/// assert_eq!(ss.element_count(), 10);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn element_count(&self) -> usize {
|
pub fn element_count(&self) -> usize {
|
||||||
self.num_elements
|
self.num_elements
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create StackSizeLimit out of self
|
/// Create StackSizeLimit out of self
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use wasmi::{StackSize, StackSizeLimit, RuntimeValue};
|
|
||||||
/// let values_limit: StackSizeLimit<RuntimeValue> = StackSize::from_element_count(1024).into_limit();
|
|
||||||
/// ```
|
|
||||||
pub fn into_limit(self) -> StackSizeLimit<T> {
|
pub fn into_limit(self) -> StackSizeLimit<T> {
|
||||||
StackSizeLimit(self)
|
StackSizeLimit(self)
|
||||||
}
|
}
|
||||||
|
@ -381,11 +210,6 @@ impl<T> StackSize<T> {
|
||||||
pub fn into_initial(self) -> StackSizeInitial<T> {
|
pub fn into_initial(self) -> StackSizeInitial<T> {
|
||||||
StackSizeInitial(self)
|
StackSizeInitial(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create StackSizeLimit with no upper bound.
|
|
||||||
pub fn unlimited() -> StackSizeLimit<T> {
|
|
||||||
StackSize::from_element_count(usize::MAX).into_limit()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Max size a stack may become.
|
/// Max size a stack may become.
|
||||||
|
@ -492,4 +316,61 @@ mod test {
|
||||||
assert_eq!(unsafe { bstack.pop_unchecked() }, 0);
|
assert_eq!(unsafe { bstack.pop_unchecked() }, 0);
|
||||||
assert_eq!(unsafe { bstack.pop_unchecked() }, 8);
|
assert_eq!(unsafe { bstack.pop_unchecked() }, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn misc() {
|
||||||
|
// These used to be doctests. They were moved here because StackWithLimit no longer
|
||||||
|
// public. Doctests can't test internal APIs.
|
||||||
|
|
||||||
|
StackWithLimit::<usize>::new(
|
||||||
|
StackSize::from_element_count(1024).into_initial(),
|
||||||
|
StackSize::from_element_count(2048).into_limit(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
||||||
|
|
||||||
|
let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
||||||
|
bstack.push(2).unwrap();
|
||||||
|
assert_eq!(bstack.pop(), Some(2));
|
||||||
|
assert_eq!(bstack.len(), 0);
|
||||||
|
assert_eq!(bstack.pop(), None);
|
||||||
|
|
||||||
|
let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
||||||
|
bstack.push(4).unwrap();
|
||||||
|
assert_eq!(bstack.nth_from_top(0), Some(&4));
|
||||||
|
assert_eq!(bstack.nth_from_top(1), None);
|
||||||
|
|
||||||
|
let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
||||||
|
bstack.push(1).unwrap();
|
||||||
|
bstack.push(2).unwrap();
|
||||||
|
assert_eq!(bstack.top(), Some(&2));
|
||||||
|
bstack.swap(0, 1);
|
||||||
|
assert_eq!(bstack.top(), Some(&1));
|
||||||
|
|
||||||
|
let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
||||||
|
bstack.push(1).unwrap();
|
||||||
|
bstack.push(2).unwrap();
|
||||||
|
assert_eq!(bstack.top(), Some(&2));
|
||||||
|
bstack.swap(0, 1);
|
||||||
|
assert_eq!(bstack.top(), Some(&1));
|
||||||
|
|
||||||
|
let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
||||||
|
assert_eq!(bstack.len(), 0);
|
||||||
|
bstack.push(1).unwrap();
|
||||||
|
bstack.push(2).unwrap();
|
||||||
|
assert_eq!(bstack.len(), 2);
|
||||||
|
|
||||||
|
let mut bstack = StackWithLimit::<i32>::with_size(StackSize::from_element_count(2));
|
||||||
|
assert_eq!(bstack.is_empty(), true);
|
||||||
|
bstack.push(1).unwrap();
|
||||||
|
assert_eq!(bstack.is_empty(), false);
|
||||||
|
|
||||||
|
let ss = StackSize::<(u8, u8)>::from_element_count(10);
|
||||||
|
assert_eq!(ss.element_count(), 10);
|
||||||
|
|
||||||
|
let ss = StackSize::<(u8, u8)>::from_element_count(10);
|
||||||
|
assert_eq!(ss.element_count(), 10);
|
||||||
|
|
||||||
|
let values_limit: StackSizeLimit<usize> = StackSize::from_element_count(1024).into_limit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,8 +404,7 @@ pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef
|
||||||
pub use self::global::{GlobalInstance, GlobalRef};
|
pub use self::global::{GlobalInstance, GlobalRef};
|
||||||
pub use self::func::{FuncInstance, FuncRef, FuncInvocation, ResumableError};
|
pub use self::func::{FuncInstance, FuncRef, FuncInvocation, ResumableError};
|
||||||
pub use self::types::{Signature, ValueType, GlobalDescriptor, TableDescriptor, MemoryDescriptor};
|
pub use self::types::{Signature, ValueType, GlobalDescriptor, TableDescriptor, MemoryDescriptor};
|
||||||
pub use self::common::stack::{StackWithLimit, StackSize, StackSizeLimit, StackSizeInitial};
|
pub use self::runner::{Interpreter, InterpreterStackConfig};
|
||||||
pub use self::runner::Interpreter;
|
|
||||||
|
|
||||||
/// WebAssembly-specific sizes and units.
|
/// WebAssembly-specific sizes and units.
|
||||||
pub mod memory_units {
|
pub mod memory_units {
|
||||||
|
|
113
src/runner.rs
113
src/runner.rs
|
@ -19,11 +19,8 @@ use value::{
|
||||||
};
|
};
|
||||||
use {Signature, Trap, TrapKind, ValueType};
|
use {Signature, Trap, TrapKind, ValueType};
|
||||||
|
|
||||||
/// Maximum number of entries in value stack.
|
const DEFAULT_VALUE_STACK_LIMIT: usize = (1024 * 1024) / 8;
|
||||||
pub const DEFAULT_VALUE_STACK_LIMIT: usize = (1024 * 1024) / ::core::mem::size_of::<RuntimeValue>();
|
const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024;
|
||||||
|
|
||||||
// TODO: Make these parameters changeble.
|
|
||||||
pub const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024;
|
|
||||||
|
|
||||||
/// This is a wrapper around u64 to allow us to treat runtime values as a tag-free `u64`
|
/// This is a wrapper around u64 to allow us to treat runtime values as a tag-free `u64`
|
||||||
/// (where if the runtime value is <64 bits the upper bits are 0). This is safe, since
|
/// (where if the runtime value is <64 bits the upper bits are 0). This is safe, since
|
||||||
|
@ -37,7 +34,7 @@ pub const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024;
|
||||||
/// at these boundaries.
|
/// at these boundaries.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct RuntimeValueInternal(pub u64);
|
struct RuntimeValueInternal(pub u64);
|
||||||
|
|
||||||
impl RuntimeValueInternal {
|
impl RuntimeValueInternal {
|
||||||
pub fn with_type(self, ty: ValueType) -> RuntimeValue {
|
pub fn with_type(self, ty: ValueType) -> RuntimeValue {
|
||||||
|
@ -164,6 +161,54 @@ enum RunResult {
|
||||||
NestedCall(FuncRef),
|
NestedCall(FuncRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stack pre-allocation and size limit settings for [`Interpreter`].
|
||||||
|
///
|
||||||
|
/// Sizes indicate number of elements, not number of bytes.
|
||||||
|
///
|
||||||
|
/// When an interpreter exceeds the size limit on either stack, [`Trapkind::StackOverflow`] is returned.
|
||||||
|
///
|
||||||
|
/// The following example initializes an Interpreter with space pre-allocated for 1024
|
||||||
|
/// values and 1024 function calls. The value stack has a maximum size of
|
||||||
|
/// 2048 and the call stack has unlimited size (bounded only by available addressable memory).
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # extern crate wasmi;
|
||||||
|
/// # use wasmi::{Interpreter, InterpreterStackConfig};
|
||||||
|
/// use std::usize;
|
||||||
|
/// let config = InterpreterStackConfig {
|
||||||
|
/// value_stack_size_initial: 1024,
|
||||||
|
/// value_stack_size_limit: 2048,
|
||||||
|
/// call_stack_size_initial: 1024,
|
||||||
|
/// call_stack_size_limit: usize::MAX,
|
||||||
|
/// };
|
||||||
|
/// let interpreter = Interpreter::with_stacks(config);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`Interpreter`]: struct.Interpreter.html
|
||||||
|
/// [`Trapkind::StackOverflow`]: enum.TrapKind.html
|
||||||
|
#[derive(Clone, PartialEq, PartialOrd, Debug)]
|
||||||
|
pub struct InterpreterStackConfig {
|
||||||
|
/// Number of spots to be pre-allocated for the value stack.
|
||||||
|
pub value_stack_size_initial: usize,
|
||||||
|
/// Maximum nuber of elements allowed in the value stack.
|
||||||
|
pub value_stack_size_limit: usize,
|
||||||
|
/// Number of spots to be pre-allocated for the call stack.
|
||||||
|
pub call_stack_size_initial: usize,
|
||||||
|
/// Maximum nuber of elements allowed in the value stack.
|
||||||
|
pub call_stack_size_limit: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InterpreterStackConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
InterpreterStackConfig {
|
||||||
|
value_stack_size_initial: DEFAULT_VALUE_STACK_LIMIT,
|
||||||
|
value_stack_size_limit: DEFAULT_VALUE_STACK_LIMIT,
|
||||||
|
call_stack_size_initial: DEFAULT_CALL_STACK_LIMIT,
|
||||||
|
call_stack_size_limit: DEFAULT_CALL_STACK_LIMIT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Function interpreter.
|
/// Function interpreter.
|
||||||
pub struct Interpreter {
|
pub struct Interpreter {
|
||||||
value_stack: ValueStack,
|
value_stack: ValueStack,
|
||||||
|
@ -172,36 +217,46 @@ pub struct Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpreter {
|
impl Interpreter {
|
||||||
/// Initialize an interpreter with defaults stack sizes.
|
/// Initialize an interpreter with default stack sizes.
|
||||||
pub fn new() -> Interpreter {
|
pub fn new() -> Interpreter {
|
||||||
Interpreter::with_stacks(
|
Interpreter::with_stacks(InterpreterStackConfig::default())
|
||||||
StackWithLimit::with_size(StackSize::from_element_count(DEFAULT_VALUE_STACK_LIMIT)),
|
|
||||||
StackWithLimit::with_size(StackSize::from_element_count(DEFAULT_CALL_STACK_LIMIT)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize an interpreter that will use `value_stack` and `call_stack`.
|
/// Initialize an interpreter with value stack and call stack configured according to
|
||||||
|
/// `stack_sizes`.
|
||||||
///
|
///
|
||||||
/// `value_stack` `call_stack` determine the allowed stack size during later executions.
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// In debug mode, panics if `stack_sizes.value_stack_size_initial` is larger than
|
||||||
|
/// `stack_sizes.value_stack_size_limit` or if `stack_sizes.frame_stack_size_initial` is larger
|
||||||
|
/// than `stack_sizes.frame_stack_size_limit`.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # extern crate wasmi;
|
/// # extern crate wasmi;
|
||||||
/// use wasmi::{Interpreter, StackWithLimit, StackSize};
|
/// use wasmi::{Interpreter, InterpreterStackConfig};
|
||||||
/// let interpreter = Interpreter::with_stacks(
|
/// let config = InterpreterStackConfig {
|
||||||
/// StackWithLimit::with_size(StackSize::from_byte_count(8192)),
|
/// value_stack_size_initial: 8192,
|
||||||
/// StackWithLimit::with_size(StackSize::from_element_count(2048)),
|
/// value_stack_size_limit: 8192,
|
||||||
/// );
|
/// call_stack_size_initial: 2048,
|
||||||
/// # let value_stack_size = StackSize::from_byte_count(8192);
|
/// call_stack_size_limit: 2048,
|
||||||
/// # let value_stack = StackWithLimit::with_size(value_stack_size);
|
/// };
|
||||||
/// # let interpreter = Interpreter::with_stacks(
|
/// let interpreter = Interpreter::with_stacks(config);
|
||||||
/// # value_stack,
|
|
||||||
/// # StackWithLimit::with_size(StackSize::from_element_count(2048)),
|
|
||||||
/// # );
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with_stacks(
|
pub fn with_stacks(stack_sizes: InterpreterStackConfig) -> Interpreter {
|
||||||
value_stack: StackWithLimit<RuntimeValueInternal>,
|
let InterpreterStackConfig {
|
||||||
call_stack: StackWithLimit<FunctionContext>,
|
value_stack_size_initial,
|
||||||
) -> Interpreter {
|
value_stack_size_limit,
|
||||||
|
call_stack_size_initial,
|
||||||
|
call_stack_size_limit,
|
||||||
|
} = stack_sizes;
|
||||||
|
let value_stack = StackWithLimit::new(
|
||||||
|
StackSize::from_element_count(value_stack_size_initial).into_initial(),
|
||||||
|
StackSize::from_element_count(value_stack_size_limit).into_limit(),
|
||||||
|
); // debug panic may occur here
|
||||||
|
let call_stack = StackWithLimit::new(
|
||||||
|
StackSize::from_element_count(call_stack_size_initial).into_initial(),
|
||||||
|
StackSize::from_element_count(call_stack_size_limit).into_limit(),
|
||||||
|
); // debug panic may occur here
|
||||||
Interpreter {
|
Interpreter {
|
||||||
value_stack: ValueStack(value_stack),
|
value_stack: ValueStack(value_stack),
|
||||||
call_stack,
|
call_stack,
|
||||||
|
@ -1217,7 +1272,7 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function execution context.
|
/// Function execution context.
|
||||||
pub struct FunctionContext {
|
struct FunctionContext {
|
||||||
/// Is context initialized.
|
/// Is context initialized.
|
||||||
pub is_initialized: bool,
|
pub is_initialized: bool,
|
||||||
/// Internal function reference.
|
/// Internal function reference.
|
||||||
|
|
Loading…
Reference in New Issue