summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/tinywasm/Cargo.toml4
-rw-r--r--crates/tinywasm/src/config.rs115
-rw-r--r--crates/tinywasm/src/engine.rs140
-rw-r--r--crates/tinywasm/src/func.rs264
-rw-r--r--crates/tinywasm/src/imports.rs8
-rw-r--r--crates/tinywasm/src/instance.rs14
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs252
-rw-r--r--crates/tinywasm/src/interpreter/mod.rs8
-rw-r--r--crates/tinywasm/src/interpreter/num_helpers.rs1
-rw-r--r--crates/tinywasm/src/interpreter/stack/block_stack.rs10
-rw-r--r--crates/tinywasm/src/interpreter/stack/call_stack.rs11
-rw-r--r--crates/tinywasm/src/interpreter/stack/mod.rs17
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs23
-rw-r--r--crates/tinywasm/src/lib.rs34
-rw-r--r--crates/tinywasm/src/store/mod.rs168
15 files changed, 526 insertions, 543 deletions
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index d1a0839..1ff4032 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -20,6 +20,7 @@ log={workspace=true, optional=true}
tinywasm-parser={version="0.9.0-alpha.0", path="../parser", default-features=false, optional=true}
tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false}
libm={version="0.2", default-features=false}
+allocator-api2={version="0.4", optional=true}
[dev-dependencies]
wasm-testsuite.workspace=true
@@ -48,6 +49,9 @@ archive=["tinywasm-types/archive"]
# canonicalize all NaN values to a single representation
canonicalize_nans=[]
+# support for the allocator-api2 crate
+allocator-api2=["dep:allocator-api2"]
+
[[test]]
name="test-wasm-1"
harness=false
diff --git a/crates/tinywasm/src/config.rs b/crates/tinywasm/src/config.rs
deleted file mode 100644
index 70ca4db..0000000
--- a/crates/tinywasm/src/config.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-use core::fmt;
-
-/// Default initial size for the 32-bit value stack (i32, f32 values).
-pub const DEFAULT_VALUE_STACK_32_INIT_SIZE: usize = 32 * 1024; // 32KB
-
-/// Default initial size for the 64-bit value stack (i64, f64 values).
-pub const DEFAULT_VALUE_STACK_64_INIT_SIZE: usize = 16 * 1024; // 16KB
-
-/// Default initial size for the 128-bit value stack (v128 values).
-pub const DEFAULT_VALUE_STACK_128_INIT_SIZE: usize = 8 * 1024; // 8KB
-
-/// Default initial size for the reference value stack (funcref, externref values).
-pub const DEFAULT_VALUE_STACK_REF_INIT_SIZE: usize = 1024; // 1KB
-
-/// Default initial size for the block stack.
-pub const DEFAULT_BLOCK_STACK_INIT_SIZE: usize = 128;
-
-/// Configuration for the WebAssembly interpreter's stack preallocation.
-///
-/// This struct allows you to configure how much space is preallocated for the
-/// different parts of the stack that the interpreter uses to store values.
-#[derive(Debug, Clone)]
-pub struct StackConfig {
- value_stack_32_init_size: Option<usize>,
- value_stack_64_init_size: Option<usize>,
- value_stack_128_init_size: Option<usize>,
- value_stack_ref_init_size: Option<usize>,
- block_stack_init_size: Option<usize>,
-}
-
-impl StackConfig {
- /// Create a new stack configuration with default settings.
- pub fn new() -> Self {
- Self {
- value_stack_32_init_size: None,
- value_stack_64_init_size: None,
- value_stack_128_init_size: None,
- value_stack_ref_init_size: None,
- block_stack_init_size: None,
- }
- }
-
- /// Get the initial size for the 32-bit value stack.
- pub fn value_stack_32_init_size(&self) -> usize {
- self.value_stack_32_init_size.unwrap_or(DEFAULT_VALUE_STACK_32_INIT_SIZE)
- }
-
- /// Get the initial size for the 64-bit value stack.
- pub fn value_stack_64_init_size(&self) -> usize {
- self.value_stack_64_init_size.unwrap_or(DEFAULT_VALUE_STACK_64_INIT_SIZE)
- }
-
- /// Get the initial size for the 128-bit value stack.
- pub fn value_stack_128_init_size(&self) -> usize {
- self.value_stack_128_init_size.unwrap_or(DEFAULT_VALUE_STACK_128_INIT_SIZE)
- }
-
- /// Get the initial size for the reference value stack.
- pub fn value_stack_ref_init_size(&self) -> usize {
- self.value_stack_ref_init_size.unwrap_or(DEFAULT_VALUE_STACK_REF_INIT_SIZE)
- }
-
- /// Get the initial size for the block stack.
- pub fn block_stack_init_size(&self) -> usize {
- self.block_stack_init_size.unwrap_or(DEFAULT_BLOCK_STACK_INIT_SIZE)
- }
-
- /// Set the initial capacity for the 32-bit value stack.
- pub fn with_value_stack_32_init_size(mut self, capacity: usize) -> Self {
- self.value_stack_32_init_size = Some(capacity);
- self
- }
-
- /// Set the initial capacity for the 64-bit value stack.
- pub fn with_value_stack_64_init_size(mut self, capacity: usize) -> Self {
- self.value_stack_64_init_size = Some(capacity);
- self
- }
-
- /// Set the initial capacity for the 128-bit value stack.
- pub fn with_value_stack_128_init_size(mut self, capacity: usize) -> Self {
- self.value_stack_128_init_size = Some(capacity);
- self
- }
-
- /// Set the initial capacity for the reference value stack.
- pub fn with_value_stack_ref_init_size(mut self, capacity: usize) -> Self {
- self.value_stack_ref_init_size = Some(capacity);
- self
- }
-
- /// Set the initial capacity for the block stack.
- pub fn with_block_stack_init_size(mut self, capacity: usize) -> Self {
- self.block_stack_init_size = Some(capacity);
- self
- }
-}
-
-impl Default for StackConfig {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl fmt::Display for StackConfig {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "StackConfig {{ ")?;
- write!(f, "value_stack_32: {}, ", self.value_stack_32_init_size())?;
- write!(f, "value_stack_64: {}, ", self.value_stack_64_init_size())?;
- write!(f, "value_stack_128: {}, ", self.value_stack_128_init_size())?;
- write!(f, "value_stack_ref: {}, ", self.value_stack_ref_init_size())?;
- write!(f, "block_stack: {} }}", self.block_stack_init_size())?;
- Ok(())
- }
-}
diff --git a/crates/tinywasm/src/engine.rs b/crates/tinywasm/src/engine.rs
new file mode 100644
index 0000000..a70ed58
--- /dev/null
+++ b/crates/tinywasm/src/engine.rs
@@ -0,0 +1,140 @@
+use core::fmt::Debug;
+
+use alloc::sync::Arc;
+
+/// Global configuration for the WebAssembly interpreter
+///
+/// Can be cheaply cloned and shared across multiple executions and threads.
+#[derive(Clone)]
+pub struct Engine {
+ pub(crate) inner: Arc<EngineInner>,
+}
+
+impl Debug for Engine {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.debug_struct("Engine").finish()
+ }
+}
+
+impl Engine {
+ /// Create a new engine with the given configuration
+ pub fn new(config: Config) -> Self {
+ Self { inner: Arc::new(EngineInner { config }) }
+ }
+
+ /// Get a reference to the engine's configuration
+ pub fn config(&self) -> &Config {
+ &self.inner.config
+ }
+}
+
+impl Default for Engine {
+ fn default() -> Engine {
+ Engine::new(Config::default())
+ }
+}
+
+pub(crate) struct EngineInner {
+ pub(crate) config: Config,
+ // pub(crate) allocator: Box<dyn Allocator + Send + Sync>,
+}
+
+// pub(crate) trait Allocator {}
+// pub(crate) struct DefaultAllocator;
+// impl Allocator for DefaultAllocator {}
+
+/// Default initial size for the 32-bit value stack (i32, f32 values).
+pub const DEFAULT_VALUE_STACK_32_INIT_SIZE: usize = 32 * 1024; // 32KB
+
+/// Default initial size for the 64-bit value stack (i64, f64 values).
+pub const DEFAULT_VALUE_STACK_64_INIT_SIZE: usize = 16 * 1024; // 16KB
+
+/// Default initial size for the 128-bit value stack (v128 values).
+pub const DEFAULT_VALUE_STACK_128_INIT_SIZE: usize = 8 * 1024; // 8KB
+
+/// Default initial size for the reference value stack (funcref, externref values).
+pub const DEFAULT_VALUE_STACK_REF_INIT_SIZE: usize = 1024; // 1KB
+
+/// Default initial size for the block stack.
+pub const DEFAULT_BLOCK_STACK_INIT_SIZE: usize = 128;
+
+/// Default initial size for the call stack.
+pub const DEFAULT_CALL_STACK_INIT_SIZE: usize = 128;
+
+/// Configuration for the WebAssembly interpreter
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub struct Config {
+ /// Initial size of the 32-bit value stack (i32, f32 values).
+ pub stack_32_init_size: usize,
+ /// Initial size of the 64-bit value stack (i64, f64 values).
+ pub stack_64_init_size: usize,
+ /// Initial size of the 128-bit value stack (v128 values).
+ pub stack_128_init_size: usize,
+ /// Initial size of the reference value stack (funcref, externref values).
+ pub stack_ref_init_size: usize,
+ /// Optional maximum sizes for the stacks. If set, the interpreter will enforce these limits and return an error if they are exceeded.
+ pub stack_32_max_size: Option<usize>,
+ /// Optional maximum sizes for the stacks. If set, the interpreter will enforce these limits and return an error if they are exceeded.
+ pub stack_64_max_size: Option<usize>,
+ /// Optional maximum sizes for the stacks. If set, the interpreter will enforce these limits and return an error if they are exceeded.
+ pub stack_128_max_size: Option<usize>,
+ /// Optional maximum sizes for the stacks. If set, the interpreter will enforce these limits and return an error if they are exceeded.
+ pub stack_ref_max_size: Option<usize>,
+
+ /// Initial size of the call stack.
+ pub call_stack_init_size: usize,
+ /// The maximum size of the call stack. If set, the interpreter will enforce this limit and return an error if it is exceeded.
+ pub call_stack_max_size: Option<usize>,
+
+ /// Initial size of the control stack (block stack).
+ pub block_stack_init_size: usize,
+ /// Optional maximum size for the control stack (block stack). If set, the interpreter will enforce this limit and return an error if it is exceeded.
+ pub block_stack_max_size: Option<usize>,
+}
+
+impl Config {
+ /// Create a new stack configuration with default settings.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Set the same maximum size for all stacks. If set, the interpreter will enforce this limit and return an error if it is exceeded.
+ pub fn with_max_stack_size(mut self, max_size: usize) -> Self {
+ self.stack_32_max_size = Some(max_size);
+ self.stack_64_max_size = Some(max_size);
+ self.stack_128_max_size = Some(max_size);
+ self.stack_ref_max_size = Some(max_size);
+ self.block_stack_max_size = Some(max_size);
+ self
+ }
+
+ /// Set the same initial size for all stacks.
+ pub fn with_initial_stack_size(mut self, init_size: usize) -> Self {
+ self.stack_32_init_size = init_size;
+ self.stack_64_init_size = init_size;
+ self.stack_128_init_size = init_size;
+ self.stack_ref_init_size = init_size;
+ self.block_stack_init_size = init_size;
+ self
+ }
+}
+
+impl Default for Config {
+ fn default() -> Self {
+ Self {
+ stack_32_init_size: DEFAULT_VALUE_STACK_32_INIT_SIZE,
+ stack_64_init_size: DEFAULT_VALUE_STACK_64_INIT_SIZE,
+ stack_128_init_size: DEFAULT_VALUE_STACK_128_INIT_SIZE,
+ stack_ref_init_size: DEFAULT_VALUE_STACK_REF_INIT_SIZE,
+ block_stack_init_size: DEFAULT_BLOCK_STACK_INIT_SIZE,
+ call_stack_init_size: DEFAULT_CALL_STACK_INIT_SIZE,
+ call_stack_max_size: None,
+ stack_32_max_size: None,
+ stack_64_max_size: None,
+ stack_128_max_size: None,
+ stack_ref_max_size: None,
+ block_stack_max_size: None,
+ }
+ }
+}
diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs
index e8055d1..87713bb 100644
--- a/crates/tinywasm/src/func.rs
+++ b/crates/tinywasm/src/func.rs
@@ -1,7 +1,7 @@
-use crate::interpreter::stack::{CallFrame, Stack};
-use crate::{Error, FuncContext, Result, Store};
+use crate::interpreter::stack::CallFrame;
+use crate::{Error, FuncContext, InterpreterRuntime, Result, Store};
use crate::{Function, log, unlikely};
-use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec};
+use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};
use tinywasm_types::{ExternRef, FuncRef, FuncType, ModuleInstanceAddr, ValType, WasmValue};
#[derive(Debug)]
@@ -10,9 +10,6 @@ pub struct FuncHandle {
pub(crate) module_addr: ModuleInstanceAddr,
pub(crate) addr: u32,
pub(crate) ty: FuncType,
-
- /// The name of the function, if it has one
- pub name: Option<String>,
}
impl FuncHandle {
@@ -48,35 +45,32 @@ impl FuncHandle {
return Err(Error::Other("Type mismatch".into()));
}
- let func_inst = store.get_func(self.addr);
+ let func_inst = store.state.get_func(self.addr);
let wasm_func = match &func_inst.func {
Function::Host(host_func) => {
let host_func = host_func.clone();
let ctx = FuncContext { store, module_addr: self.module_addr };
return host_func.call(ctx, params);
}
- Function::Wasm(wasm_func) => wasm_func,
+ Function::Wasm(wasm_func) => wasm_func.clone(),
};
// 6. Let f be the dummy frame
- let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, 0);
+ let callframe = CallFrame::new(wasm_func, func_inst.owner, params, 0);
// 7. Push the frame f to the call stack
// & 8. Push the values to the stack (Not needed since the call frame owns the values)
- let mut stack = Stack::new(call_frame, &store.config);
+ store.stack.initialize(callframe);
// 9. Invoke the function instance
- let runtime = store.runtime();
- runtime.exec(store, &mut stack)?;
+ InterpreterRuntime::exec(store)?;
// Once the function returns:
- // let result_m = func_ty.results.len();
-
// 1. Assert: m values are on the top of the stack (Ensured by validation)
- // assert!(stack.values.len() >= result_m);
+ debug_assert!(store.stack.values.len() >= func_ty.results.len());
// 2. Pop m values from the stack
- let res = stack.values.pop_results(&func_ty.results);
+ let res = store.stack.values.pop_results(&func_ty.results);
// The values are returned as the results of the invocation.
Ok(res)
@@ -115,42 +109,86 @@ impl<P: IntoWasmValueTuple, R: FromWasmValueTuple> FuncHandleTyped<P, R> {
}
}
-macro_rules! impl_into_wasm_value_tuple {
- ($($T:ident),*) => {
- impl<$($T),*> IntoWasmValueTuple for ($($T,)*)
+pub trait ValTypesFromTuple {
+ fn val_types() -> Box<[ValType]>;
+}
+
+pub trait ToValType {
+ fn to_val_type() -> ValType;
+}
+
+macro_rules! impl_scalar_wasm_traits {
+ ($($T:ty => $val_ty:ident),+ $(,)?) => {
+ $(
+ impl ToValType for $T {
+ #[inline]
+ fn to_val_type() -> ValType {
+ ValType::$val_ty
+ }
+ }
+
+ impl ValTypesFromTuple for $T {
+ #[inline]
+ fn val_types() -> Box<[ValType]> {
+ Box::new([ValType::$val_ty])
+ }
+ }
+
+ impl IntoWasmValueTuple for $T {
+ #[inline]
+ fn into_wasm_value_tuple(self) -> Vec<WasmValue> {
+ vec![self.into()]
+ }
+ }
+
+ impl FromWasmValueTuple for $T {
+ #[inline]
+ fn from_wasm_value_tuple(values: &[WasmValue]) -> Result<Self> {
+ let value = *values
+ .first()
+ .ok_or(Error::Other("Not enough values in WasmValue vector".to_string()))?;
+ <$T>::try_from(value).map_err(|e| {
+ Error::Other(format!(
+ "FromWasmValueTuple: Could not convert WasmValue to expected type: {:?}",
+ e
+ ))
+ })
+ }
+ }
+ )+
+ };
+}
+
+macro_rules! impl_tuple_traits {
+ ($($T:ident),+) => {
+ impl<$($T),+> ValTypesFromTuple for ($($T,)+)
where
- $($T: Into<WasmValue>),*
+ $($T: ToValType,)+
{
- #[allow(non_snake_case)]
#[inline]
- fn into_wasm_value_tuple(self) -> Vec<WasmValue> {
- let ($($T,)*) = self;
- vec![$($T.into(),)*]
+ fn val_types() -> Box<[ValType]> {
+ Box::new([$($T::to_val_type(),)+])
}
}
- }
-}
-macro_rules! impl_into_wasm_value_tuple_single {
- ($T:ident) => {
- impl IntoWasmValueTuple for $T {
+ impl<$($T),+> IntoWasmValueTuple for ($($T,)+)
+ where
+ $($T: Into<WasmValue>,)+
+ {
+ #[allow(non_snake_case)]
#[inline]
fn into_wasm_value_tuple(self) -> Vec<WasmValue> {
- vec![self.into()]
+ let ($($T,)+) = self;
+ vec![$($T.into(),)+]
}
}
- };
-}
-macro_rules! impl_from_wasm_value_tuple {
- ($($T:ident),*) => {
- impl<$($T),*> FromWasmValueTuple for ($($T,)*)
+ impl<$($T),+> FromWasmValueTuple for ($($T,)+)
where
- $($T: TryFrom<WasmValue, Error = ()>),*
+ $($T: TryFrom<WasmValue, Error = ()>,)+
{
#[inline]
fn from_wasm_value_tuple(values: &[WasmValue]) -> Result<Self> {
- #[allow(unused_variables, unused_mut)]
let mut iter = values.iter();
Ok((
@@ -159,91 +197,43 @@ macro_rules! impl_from_wasm_value_tuple {
*iter.next()
.ok_or(Error::Other("Not enough values in WasmValue vector".to_string()))?
)
- .map_err(|e| Error::Other(format!("FromWasmValueTuple: Could not convert WasmValue to expected type: {:?}", e,
- )))?,
- )*
+ .map_err(|e| Error::Other(format!(
+ "FromWasmValueTuple: Could not convert WasmValue to expected type: {:?}",
+ e,
+ )))?,
+ )+
))
}
}
}
}
-macro_rules! impl_from_wasm_value_tuple_single {
- ($T:ident) => {
- impl FromWasmValueTuple for $T {
- #[inline]
- fn from_wasm_value_tuple(values: &[WasmValue]) -> Result<Self> {
- #[allow(unused_variables, unused_mut)]
- let mut iter = values.iter();
- $T::try_from(*iter.next().ok_or(Error::Other("Not enough values in WasmValue vector".to_string()))?)
- .map_err(|e| {
- Error::Other(format!(
- "FromWasmValueTupleSingle: Could not convert WasmValue to expected type: {:?}",
- e
- ))
- })
- }
- }
+macro_rules! impl_tuple {
+ ($macro:ident) => {
+ $macro!(T1);
+ $macro!(T1, T2);
+ $macro!(T1, T2, T3);
+ $macro!(T1, T2, T3, T4);
+ $macro!(T1, T2, T3, T4, T5);
+ $macro!(T1, T2, T3, T4, T5, T6);
+ $macro!(T1, T2, T3, T4, T5, T6, T7);
+ $macro!(T1, T2, T3, T4, T5, T6, T7, T8);
+ $macro!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
+ $macro!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
+ $macro!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
+ $macro!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
};
}
-pub trait ValTypesFromTuple {
- fn val_types() -> Box<[ValType]>;
-}
-
-pub trait ToValType {
- fn to_val_type() -> ValType;
-}
-
-impl ToValType for i32 {
- fn to_val_type() -> ValType {
- ValType::I32
- }
-}
-
-impl ToValType for i64 {
- fn to_val_type() -> ValType {
- ValType::I64
- }
-}
-
-impl ToValType for f32 {
- fn to_val_type() -> ValType {
- ValType::F32
- }
-}
-
-impl ToValType for f64 {
- fn to_val_type() -> ValType {
- ValType::F64
- }
-}
-
-impl ToValType for FuncRef {
- fn to_val_type() -> ValType {
- ValType::RefFunc
- }
-}
-
-impl ToValType for ExternRef {
- fn to_val_type() -> ValType {
- ValType::RefExtern
- }
-}
-
-macro_rules! impl_val_types_from_tuple {
- ($($t:ident),+) => {
- impl<$($t),+> ValTypesFromTuple for ($($t,)+)
- where
- $($t: ToValType,)+
- {
- #[inline]
- fn val_types() -> Box<[ValType]> {
- Box::new([$($t::to_val_type(),)+])
- }
- }
- };
-}
+impl_scalar_wasm_traits!(
+ i32 => I32,
+ i64 => I64,
+ f32 => F32,
+ f64 => F64,
+ FuncRef => RefFunc,
+ ExternRef => RefExtern,
+);
+impl_tuple!(impl_tuple_traits);
impl ValTypesFromTuple for () {
#[inline]
@@ -252,46 +242,16 @@ impl ValTypesFromTuple for () {
}
}
-impl<T: ToValType> ValTypesFromTuple for T {
+impl IntoWasmValueTuple for () {
#[inline]
- fn val_types() -> Box<[ValType]> {
- Box::new([T::to_val_type()])
+ fn into_wasm_value_tuple(self) -> Vec<WasmValue> {
+ vec![]
}
}
-impl_from_wasm_value_tuple_single!(i32);
-impl_from_wasm_value_tuple_single!(i64);
-impl_from_wasm_value_tuple_single!(f32);
-impl_from_wasm_value_tuple_single!(f64);
-impl_from_wasm_value_tuple_single!(FuncRef);
-impl_from_wasm_value_tuple_single!(ExternRef);
-
-impl_into_wasm_value_tuple_single!(i32);
-impl_into_wasm_value_tuple_single!(i64);
-impl_into_wasm_value_tuple_single!(f32);
-impl_into_wasm_value_tuple_single!(f64);
-impl_into_wasm_value_tuple_single!(FuncRef);
-impl_into_wasm_value_tuple_single!(ExternRef);
-
-impl_val_types_from_tuple!(T1);
-impl_val_types_from_tuple!(T1, T2);
-impl_val_types_from_tuple!(T1, T2, T3);
-impl_val_types_from_tuple!(T1, T2, T3, T4);
-impl_val_types_from_tuple!(T1, T2, T3, T4, T5);
-impl_val_types_from_tuple!(T1, T2, T3, T4, T5, T6);
-
-impl_from_wasm_value_tuple!();
-impl_from_wasm_value_tuple!(T1);
-impl_from_wasm_value_tuple!(T1, T2);
-impl_from_wasm_value_tuple!(T1, T2, T3);
-impl_from_wasm_value_tuple!(T1, T2, T3, T4);
-impl_from_wasm_value_tuple!(T1, T2, T3, T4, T5);
-impl_from_wasm_value_tuple!(T1, T2, T3, T4, T5, T6);
-
-impl_into_wasm_value_tuple!();
-impl_into_wasm_value_tuple!(T1);
-impl_into_wasm_value_tuple!(T1, T2);
-impl_into_wasm_value_tuple!(T1, T2, T3);
-impl_into_wasm_value_tuple!(T1, T2, T3, T4);
-impl_into_wasm_value_tuple!(T1, T2, T3, T4, T5);
-impl_into_wasm_value_tuple!(T1, T2, T3, T4, T5, T6);
+impl FromWasmValueTuple for () {
+ #[inline]
+ fn from_wasm_value_tuple(_values: &[WasmValue]) -> Result<Self> {
+ Ok(())
+ }
+}
diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs
index 563e586..aa05ae9 100644
--- a/crates/tinywasm/src/imports.rs
+++ b/crates/tinywasm/src/imports.rs
@@ -403,25 +403,25 @@ impl Imports {
match (val, &import.kind) {
(ExternVal::Global(global_addr), ImportKind::Global(ty)) => {
- let global = store.get_global(global_addr);
+ let global = store.state.get_global(global_addr);
Self::compare_types(import, &global.ty, ty)?;
imports.globals.push(global_addr);
}
(ExternVal::Table(table_addr), ImportKind::Table(ty)) => {
- let table = store.get_table(table_addr);
+ let table = store.state.get_table(table_addr);
let mut kind = table.kind.clone();
kind.size_initial = table.size() as u32;
Self::compare_table_types(import, &kind, ty)?;
imports.tables.push(table_addr);
}
(ExternVal::Memory(memory_addr), ImportKind::Memory(ty)) => {
- let mem = store.get_mem(memory_addr);
+ let mem = store.state.get_mem(memory_addr);
let (size, kind) = { (mem.page_count, mem.kind) };
Self::compare_memory_types(import, &kind, ty, Some(size))?;
imports.memories.push(memory_addr);
}
(ExternVal::Func(func_addr), ImportKind::Function(ty)) => {
- let func = store.get_func(func_addr);
+ let func = store.state.get_func(func_addr);
let import_func_type = module
.0
.func_types
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index 0ca8f6f..02ef531 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -1,4 +1,4 @@
-use alloc::{boxed::Box, format, rc::Rc, string::ToString};
+use alloc::{boxed::Box, format, rc::Rc};
use tinywasm_types::*;
use crate::func::{FromWasmValueTuple, IntoWasmValueTuple};
@@ -174,8 +174,8 @@ impl ModuleInstance {
return Err(Error::Other(format!("Export is not a function: {name}")));
};
- let ty = store.get_func(func_addr).func.ty();
- Ok(FuncHandle { addr: func_addr, module_addr: self.id(), name: Some(name.to_string()), ty: ty.clone() })
+ let ty = store.state.get_func(func_addr).func.ty();
+ Ok(FuncHandle { addr: func_addr, module_addr: self.id(), ty: ty.clone() })
}
/// Get a typed exported function by name
@@ -210,13 +210,13 @@ impl ModuleInstance {
/// Get a memory by address
pub fn memory<'a>(&self, store: &'a Store, addr: MemAddr) -> Result<MemoryRef<'a>> {
- let mem = store.get_mem(self.resolve_mem_addr(addr));
+ let mem = store.state.get_mem(self.resolve_mem_addr(addr));
Ok(MemoryRef(mem))
}
/// Get a memory by address (mutable)
pub fn memory_mut<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result<MemoryRefMut<'a>> {
- let mem = store.get_mem_mut(self.resolve_mem_addr(addr));
+ let mem = store.state.get_mem_mut(self.resolve_mem_addr(addr));
Ok(MemoryRefMut(mem))
}
@@ -244,10 +244,10 @@ impl ModuleInstance {
};
let func_addr = self.resolve_func_addr(func_index);
- let func_inst = store.get_func(func_addr);
+ let func_inst = store.state.get_func(func_addr);
let ty = func_inst.func.ty();
- Ok(Some(FuncHandle { module_addr: self.id(), addr: func_addr, ty: ty.clone(), name: None }))
+ Ok(Some(FuncHandle { module_addr: self.id(), addr: func_addr, ty: ty.clone() }))
}
/// Invoke the start function of the module
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index 08089f4..fd24896 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -9,26 +9,24 @@ use interpreter::stack::CallFrame;
use tinywasm_types::*;
use super::num_helpers::*;
-use super::stack::{BlockFrame, BlockType, Stack};
+use super::stack::{BlockFrame, BlockType};
use super::values::*;
use crate::interpreter::Value128;
use crate::*;
-pub(crate) struct Executor<'store, 'stack> {
+pub(crate) struct Executor<'store> {
pub(crate) cf: CallFrame,
pub(crate) module: ModuleInstance,
pub(crate) store: &'store mut Store,
- pub(crate) stack: &'stack mut Stack,
}
-impl<'store, 'stack> Executor<'store, 'stack> {
- pub(crate) fn new(store: &'store mut Store, stack: &'stack mut Stack) -> Result<Self> {
- let current_frame = stack.call_stack.pop().expect("no call frame, this is a bug");
+impl<'store> Executor<'store> {
+ pub(crate) fn new(store: &'store mut Store) -> Result<Self> {
+ let current_frame = store.stack.call_stack.pop().expect("no call frame, this is a bug");
let current_module = store.get_module_instance_raw(current_frame.module_addr());
- Ok(Self { cf: current_frame, module: current_module, stack, store })
+ Ok(Self { cf: current_frame, module: current_module, store })
}
- #[inline(always)]
pub(crate) fn run_to_completion(&mut self) -> Result<()> {
loop {
if let ControlFlow::Break(res) = self.exec_next() {
@@ -46,31 +44,31 @@ impl<'store, 'stack> Executor<'store, 'stack> {
macro_rules! stack_op {
(simd_unary $method:ident) => {
- self.stack.values.unary_same::<Value128>(|v| Ok(v.$method())).to_cf()?
+ self.store.stack.values.unary_same::<Value128>(|v| Ok(v.$method())).to_cf()?
};
(simd_binary $method:ident) => {
- self.stack.values.binary_same::<Value128>(|a, b| Ok(a.$method(b))).to_cf()?
+ self.store.stack.values.binary_same::<Value128>(|a, b| Ok(a.$method(b))).to_cf()?
};
(unary $ty:ty, |$v:ident| $expr:expr) => {
- self.stack.values.unary_same::<$ty>(|$v| Ok($expr)).to_cf()?
+ self.store.stack.values.unary_same::<$ty>(|$v| Ok($expr)).to_cf()?
};
(binary $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
- self.stack.values.binary_same::<$ty>(|$a, $b| Ok($expr)).to_cf()?
+ self.store.stack.values.binary_same::<$ty>(|$a, $b| Ok($expr)).to_cf()?
};
(binary_try $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
- self.stack.values.binary_same::<$ty>(|$a, $b| $expr).to_cf()?
+ self.store.stack.values.binary_same::<$ty>(|$a, $b| $expr).to_cf()?
};
(unary $from:ty => $to:ty, |$v:ident| $expr:expr) => {
- self.stack.values.unary::<$from, $to>(|$v| Ok($expr)).to_cf()?
+ self.store.stack.values.unary::<$from, $to>(|$v| Ok($expr)).to_cf()?
};
(binary $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => {
- self.stack.values.binary::<$from, $to>(|$a, $b| Ok($expr)).to_cf()?
+ self.store.stack.values.binary::<$from, $to>(|$a, $b| Ok($expr)).to_cf()?
};
(binary $a:ty, $b:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
- self.stack.values.binary_diff::<$a, $b, $b>(|$lhs, $rhs| Ok($expr)).to_cf()?
+ self.store.stack.values.binary_diff::<$a, $b, $b>(|$lhs, $rhs| Ok($expr)).to_cf()?
};
(binary $a:ty, $b:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
- self.stack.values.binary_diff::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()?
+ self.store.stack.values.binary_diff::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()?
};
}
@@ -79,15 +77,15 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Nop | BrLabel(_) | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
Unreachable => self.exec_unreachable()?,
- Drop32 => self.stack.values.drop::<Value32>(),
- Drop64 => self.stack.values.drop::<Value64>(),
- Drop128 => self.stack.values.drop::<Value128>(),
- DropRef => self.stack.values.drop::<ValueRef>(),
+ Drop32 => self.store.stack.values.drop::<Value32>(),
+ Drop64 => self.store.stack.values.drop::<Value64>(),
+ Drop128 => self.store.stack.values.drop::<Value128>(),
+ DropRef => self.store.stack.values.drop::<ValueRef>(),
- Select32 => self.stack.values.select::<Value32>(),
- Select64 => self.stack.values.select::<Value64>(),
- Select128 => self.stack.values.select::<Value128>(),
- SelectRef => self.stack.values.select::<ValueRef>(),
+ Select32 => self.store.stack.values.select::<Value32>(),
+ Select64 => self.store.stack.values.select::<Value64>(),
+ Select128 => self.store.stack.values.select::<Value128>(),
+ SelectRef => self.store.stack.values.select::<ValueRef>(),
Call(v) => return self.exec_call_direct::<false>(*v),
CallIndirect(ty, table) => return self.exec_call_indirect::<false>(*ty, *table),
@@ -352,7 +350,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
V128AndNot => stack_op!(binary Value128, |a, b| a.v128_andnot(b)),
V128Or => stack_op!(binary Value128, |a, b| a.v128_or(b)),
V128Xor => stack_op!(binary Value128, |a, b| a.v128_xor(b)),
- V128Bitselect => self.stack.values.ternary_same::<Value128>(|v1, v2, c| Ok(Value128::v128_bitselect(v1, v2, c))).to_cf()?,
+ V128Bitselect => self.store.stack.values.ternary_same::<Value128>(|v1, v2, c| Ok(Value128::v128_bitselect(v1, v2, c))).to_cf()?,
V128AnyTrue => stack_op!(unary Value128 => i32, |v| v.v128_any_true() as i32),
I8x16Swizzle => stack_op!(binary Value128, |a, s| a.i8x16_swizzle(s)),
@@ -670,31 +668,31 @@ impl<'store, 'stack> Executor<'store, 'stack> {
wasm_func: Rc<WasmFunction>,
owner: ModuleInstanceAddr,
) -> ControlFlow<Option<Error>> {
- let locals = self.stack.values.pop_locals(wasm_func.params, wasm_func.locals);
+ let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals);
if IS_RETURN_CALL {
- self.cf.reuse_for(wasm_func, locals, self.stack.blocks.len() as u32, owner);
+ self.cf.reuse_for(wasm_func, locals, self.store.stack.blocks.len() as u32, owner);
} else {
- let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.stack.blocks.len() as u32);
+ let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.store.stack.blocks.len() as u32);
self.cf.incr_instr_ptr(); // skip the call instruction
- self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
+ self.store.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
}
self.module.swap_with(self.cf.module_addr(), self.store);
ControlFlow::Continue(())
}
fn exec_call_host(&mut self, host_func: Rc<imports::HostFunction>) -> ControlFlow<Option<Error>> {
- let params = self.stack.values.pop_params(&host_func.ty.params);
+ let params = self.store.stack.values.pop_params(&host_func.ty.params);
let res = host_func
.clone()
.call(FuncContext { store: self.store, module_addr: self.module.id() }, &params)
.to_cf()?;
- self.stack.values.extend_from_wasmvalues(&res);
+ self.store.stack.values.extend_from_wasmvalues(&res);
self.cf.incr_instr_ptr();
ControlFlow::Continue(())
}
fn exec_call_direct<const IS_RETURN_CALL: bool>(&mut self, v: u32) -> ControlFlow<Option<Error>> {
- let func_inst = self.store.get_func(self.module.resolve_func_addr(v));
+ let func_inst = self.store.state.get_func(self.module.resolve_func_addr(v));
match func_inst.func.clone() {
crate::Function::Wasm(wasm_func) => self.exec_call::<IS_RETURN_CALL>(wasm_func, func_inst.owner),
crate::Function::Host(host_func) => self.exec_call_host(host_func),
@@ -707,15 +705,15 @@ impl<'store, 'stack> Executor<'store, 'stack> {
) -> ControlFlow<Option<Error>> {
// verify that the table is of the right type, this should be validated by the parser already
let func_ref = {
- let table = self.store.get_table(self.module.resolve_table_addr(table_addr));
- let table_idx: u32 = self.stack.values.pop::<i32>() as u32;
+ let table_idx: u32 = self.store.stack.values.pop::<i32>() as u32;
+ let table = self.store.state.get_table(self.module.resolve_table_addr(table_addr));
assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref");
let table = table.get(table_idx).map_err(|_| Trap::UndefinedElement { index: table_idx as usize }.into());
let table = table.to_cf()?;
table.addr().ok_or(Trap::UninitializedElement { index: table_idx as usize }.into()).to_cf()?
};
- let func_inst = self.store.get_func(func_ref);
+ let func_inst = self.store.state.get_func(func_ref);
let call_ty = self.module.func_ty(type_addr);
match func_inst.func.clone() {
@@ -744,7 +742,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
fn exec_if(&mut self, else_offset: u32, end_offset: u32, (params, results): (StackHeight, StackHeight)) {
// truthy value is on the top of the stack, so enter the then block
- if self.stack.values.pop::<i32>() != 0 {
+ if self.store.stack.values.pop::<i32>() != 0 {
self.enter_block(end_offset, BlockType::If, (params, results));
return;
}
@@ -767,17 +765,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
((&*ty.params).into(), (&*ty.results).into())
}
fn enter_block(&mut self, end_instr_offset: u32, ty: BlockType, (params, results): (StackHeight, StackHeight)) {
- self.stack.blocks.push(BlockFrame {
+ self.store.stack.blocks.push(BlockFrame {
instr_ptr: self.cf.instr_ptr(),
end_instr_offset,
- stack_ptr: self.stack.values.height(),
+ stack_ptr: self.store.stack.values.height(),
results,
params,
ty,
});
}
fn exec_br(&mut self, to: u32) -> ControlFlow<Option<Error>> {
- if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() {
+ if self.cf.break_to(to, &mut self.store.stack.values, &mut self.store.stack.blocks).is_none() {
return self.exec_return();
}
@@ -785,8 +783,8 @@ impl<'store, 'stack> Executor<'store, 'stack> {
ControlFlow::Continue(())
}
fn exec_br_if(&mut self, to: u32) -> ControlFlow<Option<Error>> {
- if self.stack.values.pop::<i32>() != 0
- && self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none()
+ if self.store.stack.values.pop::<i32>() != 0
+ && self.cf.break_to(to, &mut self.store.stack.values, &mut self.store.stack.blocks).is_none()
{
return self.exec_return();
}
@@ -804,14 +802,14 @@ impl<'store, 'stack> Executor<'store, 'stack> {
))));
}
- let idx = self.stack.values.pop::<i32>();
+ let idx = self.store.stack.values.pop::<i32>();
let to = match self.cf.instructions()[start..end].get(idx as usize) {
None => default,
Some(Instruction::BrLabel(to)) => *to,
_ => return ControlFlow::Break(Some(Error::Other("br_table out of bounds".to_string()))),
};
- if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() {
+ if self.cf.break_to(to, &mut self.store.stack.values, &mut self.store.stack.blocks).is_none() {
return self.exec_return();
}
@@ -820,64 +818,68 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
fn exec_return(&mut self) -> ControlFlow<Option<Error>> {
let old = self.cf.block_ptr();
- match self.stack.call_stack.pop() {
+ match self.store.stack.call_stack.pop() {
None => return ControlFlow::Break(None),
Some(cf) => self.cf = cf,
}
if old > self.cf.block_ptr() {
- self.stack.blocks.truncate(old);
+ self.store.stack.blocks.truncate(old);
}
self.module.swap_with(self.cf.module_addr(), self.store);
ControlFlow::Continue(())
}
fn exec_end_block(&mut self) {
- let block = self.stack.blocks.pop();
- self.stack.values.truncate_keep(block.stack_ptr, block.results);
+ let block = self.store.stack.blocks.pop();
+ self.store.stack.values.truncate_keep(block.stack_ptr, block.results);
}
fn exec_local_get<T: InternalValue>(&mut self, local_index: u16) {
let v = self.cf.locals.get::<T>(local_index);
- self.stack.values.push(v);
+ self.store.stack.values.push(v);
}
fn exec_local_set<T: InternalValue>(&mut self, local_index: u16) {
- let v = self.stack.values.pop::<T>();
+ let v = self.store.stack.values.pop::<T>();
self.cf.locals.set(local_index, v);
}
fn exec_local_tee<T: InternalValue>(&mut self, local_index: u16) {
- let v = self.stack.values.peek::<T>();
+ let v = self.store.stack.values.peek::<T>();
self.cf.locals.set(local_index, v);
}
fn exec_global_get(&mut self, global_index: u32) {
- self.stack.values.push_dyn(self.store.get_global_val(self.module.resolve_global_addr(global_index)));
+ self.store
+ .stack
+ .values
+ .push_dyn(self.store.state.get_global_val(self.module.resolve_global_addr(global_index)));
}
fn exec_global_set<T: InternalValue>(&mut self, global_index: u32) {
- self.store.set_global_val(self.module.resolve_global_addr(global_index), self.stack.values.pop::<T>().into());
+ let val = self.store.stack.values.pop::<T>().into();
+ self.store.state.set_global_val(self.module.resolve_global_addr(global_index), val);
}
fn exec_const<T: InternalValue>(&mut self, val: T) {
- self.stack.values.push(val);
+ self.store.stack.values.push(val);
}
fn exec_ref_is_null(&mut self) {
- let is_null = i32::from(self.stack.values.pop::<ValueRef>().is_none());
- self.stack.values.push::<i32>(is_null);
+ let is_null = i32::from(self.store.stack.values.pop::<ValueRef>().is_none());
+ self.store.stack.values.push::<i32>(is_null);
}
fn exec_memory_size(&mut self, addr: u32) {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(addr));
+ let mem = self.store.state.get_mem(self.module.resolve_mem_addr(addr));
match mem.is_64bit() {
- true => self.stack.values.push::<i64>(mem.page_count as i64),
- false => self.stack.values.push::<i32>(mem.page_count as i32),
+ true => self.store.stack.values.push::<i64>(mem.page_count as i64),
+ false => self.store.stack.values.push::<i32>(mem.page_count as i32),
}
}
fn exec_memory_grow(&mut self, addr: u32) {
- let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(addr));
+ let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(addr));
let prev_size = mem.page_count;
let pages_delta = match mem.is_64bit() {
- true => self.stack.values.pop::<i64>(),
- false => i64::from(self.stack.values.pop::<i32>()),
+ true => self.store.stack.values.pop::<i64>(),
+ false => i64::from(self.store.stack.values.pop::<i32>()),
};
match (
@@ -887,52 +889,52 @@ impl<'store, 'stack> Executor<'store, 'stack> {
None => -1_i64,
},
) {
- (true, size) => self.stack.values.push::<i64>(size),
- (false, size) => self.stack.values.push::<i32>(size as i32),
+ (true, size) => self.store.stack.values.push::<i64>(size),
+ (false, size) => self.store.stack.values.push::<i32>(size as i32),
};
}
fn exec_memory_copy(&mut self, from: u32, to: u32) -> Result<()> {
- let size: i32 = self.stack.values.pop();
- let src: i32 = self.stack.values.pop();
- let dst: i32 = self.stack.values.pop();
+ let size: i32 = self.store.stack.values.pop();
+ let src: i32 = self.store.stack.values.pop();
+ let dst: i32 = self.store.stack.values.pop();
if from == to {
- let mem_from = self.store.get_mem_mut(self.module.resolve_mem_addr(from));
+ let mem_from = self.store.state.get_mem_mut(self.module.resolve_mem_addr(from));
// copy within the same memory
mem_from.copy_within(dst as usize, src as usize, size as usize)?;
} else {
// copy between two memories
let (mem_from, mem_to) =
- self.store.get_mems_mut(self.module.resolve_mem_addr(from), self.module.resolve_mem_addr(to))?;
+ self.store.state.get_mems_mut(self.module.resolve_mem_addr(from), self.module.resolve_mem_addr(to))?;
mem_from.copy_from_slice(dst as usize, mem_to.load(src as usize, size as usize)?)?;
}
Ok(())
}
fn exec_memory_fill(&mut self, addr: u32) -> Result<()> {
- let size: i32 = self.stack.values.pop();
- let val: i32 = self.stack.values.pop();
- let dst: i32 = self.stack.values.pop();
+ let size: i32 = self.store.stack.values.pop();
+ let val: i32 = self.store.stack.values.pop();
+ let dst: i32 = self.store.stack.values.pop();
- let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(addr));
+ let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(addr));
mem.fill(dst as usize, size as usize, val as u8)
}
fn exec_memory_init(&mut self, data_index: u32, mem_index: u32) -> Result<()> {
- let size: i32 = self.stack.values.pop();
- let offset: i32 = self.stack.values.pop();
- let dst: i32 = self.stack.values.pop();
+ let size: i32 = self.store.stack.values.pop();
+ let offset: i32 = self.store.stack.values.pop();
+ let dst: i32 = self.store.stack.values.pop();
let data = self
.store
- .data
+ .state
.data
.get(self.module.resolve_data_addr(data_index) as usize)
.ok_or_else(|| Error::Other("data not found".to_string()))?;
let mem = self
.store
- .data
+ .state
.memories
.get_mut(self.module.resolve_mem_addr(mem_index) as usize)
.ok_or_else(|| Error::Other("memory not found".to_string()))?;
@@ -951,27 +953,29 @@ impl<'store, 'stack> Executor<'store, 'stack> {
mem.store(dst as usize, size as usize, &data[offset as usize..((offset + size) as usize)])
}
fn exec_data_drop(&mut self, data_index: u32) {
- self.store.get_data_mut(self.module.resolve_data_addr(data_index)).drop();
+ self.store.state.get_data_mut(self.module.resolve_data_addr(data_index)).drop();
}
fn exec_elem_drop(&mut self, elem_index: u32) {
- self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)).drop();
+ self.store.state.get_elem_mut(self.module.resolve_elem_addr(elem_index)).drop();
}
fn exec_table_copy(&mut self, from: u32, to: u32) -> Result<()> {
- let size: i32 = self.stack.values.pop();
- let src: i32 = self.stack.values.pop();
- let dst: i32 = self.stack.values.pop();
+ let size: i32 = self.store.stack.values.pop();
+ let src: i32 = self.store.stack.values.pop();
+ let dst: i32 = self.store.stack.values.pop();
if from == to {
// copy within the same memory
- self.store.get_table_mut(self.module.resolve_table_addr(from)).copy_within(
+ self.store.state.get_table_mut(self.module.resolve_table_addr(from)).copy_within(
dst as usize,
src as usize,
size as usize,
)
} else {
// copy between two memories
- let (table_from, table_to) =
- self.store.get_tables_mut(self.module.resolve_table_addr(from), self.module.resolve_table_addr(to))?;
+ let (table_from, table_to) = self
+ .store
+ .state
+ .get_tables_mut(self.module.resolve_table_addr(from), self.module.resolve_table_addr(to))?;
table_to.copy_from_slice(dst as usize, table_from.load(src as usize, size as usize)?)
}
}
@@ -982,9 +986,9 @@ impl<'store, 'stack> Executor<'store, 'stack> {
offset: u64,
lane: u8,
) -> ControlFlow<Option<Error>> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr));
- let mut imm = self.stack.values.pop::<Value128>().to_mem_bytes();
- let val = self.stack.values.pop::<i32>() as u64;
+ let mut imm = self.store.stack.values.pop::<Value128>().to_mem_bytes();
+ let val = self.store.stack.values.pop::<i32>() as u64;
+ let mem = self.store.state.get_mem(self.module.resolve_mem_addr(mem_addr));
let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else {
cold();
return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
@@ -998,7 +1002,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let offset = lane as usize * LOAD_SIZE;
imm[offset..offset + LOAD_SIZE].copy_from_slice(&val);
- self.stack.values.push(Value128::from_mem_bytes(imm));
+ self.store.stack.values.push(Value128::from_mem_bytes(imm));
ControlFlow::Continue(())
}
@@ -1008,11 +1012,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
offset: u64,
cast: fn(LOAD) -> TARGET,
) -> ControlFlow<Option<Error>> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr));
+ let mem = self.store.state.get_mem(self.module.resolve_mem_addr(mem_addr));
let addr = match mem.is_64bit() {
- true => self.stack.values.pop::<i64>() as u64,
- false => u64::from(self.stack.values.pop::<i32>() as u32),
+ true => self.store.stack.values.pop::<i64>() as u64,
+ false => u64::from(self.store.stack.values.pop::<i32>() as u32),
};
let Some(Ok(addr)) = offset.checked_add(addr).map(|a| a.try_into()) else {
@@ -1024,7 +1028,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
})));
};
let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?;
- self.stack.values.push(cast(val));
+ self.store.stack.values.push(cast(val));
ControlFlow::Continue(())
}
@@ -1034,15 +1038,15 @@ impl<'store, 'stack> Executor<'store, 'stack> {
offset: u64,
lane: u8,
) -> ControlFlow<Option<Error>> {
- let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(mem_addr));
- let bytes = self.stack.values.pop::<Value128>().to_mem_bytes();
+ let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(mem_addr));
+ let bytes = self.store.stack.values.pop::<Value128>().to_mem_bytes();
let lane_offset = lane as usize * N;
let mut val = [0u8; N];
val.copy_from_slice(&bytes[lane_offset..lane_offset + N]);
let addr = match mem.is_64bit() {
- true => self.stack.values.pop::<i64>() as u64,
- false => self.stack.values.pop::<i32>() as u32 as u64,
+ true => self.store.stack.values.pop::<i64>() as u64,
+ false => self.store.stack.values.pop::<i32>() as u32 as u64,
};
if let Err(e) = mem.store((offset + addr) as usize, val.len(), &val) {
@@ -1058,13 +1062,13 @@ impl<'store, 'stack> Executor<'store, 'stack> {
offset: u64,
cast: fn(T) -> U,
) -> ControlFlow<Option<Error>> {
- let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(mem_addr));
- let val = self.stack.values.pop::<T>();
+ let val = self.store.stack.values.pop::<T>();
+ let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(mem_addr));
let val = (cast(val)).to_mem_bytes();
let addr = match mem.is_64bit() {
- true => self.stack.values.pop::<i64>() as u64,
- false => u64::from(self.stack.values.pop::<i32>() as u32),
+ true => self.store.stack.values.pop::<i64>() as u64,
+ false => u64::from(self.store.stack.values.pop::<i32>() as u32),
};
if let Err(e) = mem.store((offset + addr) as usize, val.len(), &val) {
@@ -1075,38 +1079,38 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
fn exec_table_get(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index));
- let idx: i32 = self.stack.values.pop::<i32>();
+ let idx: i32 = self.store.stack.values.pop::<i32>();
+ let table = self.store.state.get_table(self.module.resolve_table_addr(table_index));
let v = table.get_wasm_val(idx as u32)?;
- self.stack.values.push_dyn(v.into());
+ self.store.stack.values.push_dyn(v.into());
Ok(())
}
fn exec_table_set(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index));
- let val = self.stack.values.pop::<ValueRef>();
- let idx = self.stack.values.pop::<i32>() as u32;
+ let val = self.store.stack.values.pop::<ValueRef>();
+ let idx = self.store.stack.values.pop::<i32>() as u32;
+ let table = self.store.state.get_table_mut(self.module.resolve_table_addr(table_index));
table.set(idx, val.into())
}
fn exec_table_size(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index));
- self.stack.values.push_dyn(table.size().into());
+ let table = self.store.state.get_table(self.module.resolve_table_addr(table_index));
+ self.store.stack.values.push_dyn(table.size().into());
Ok(())
}
fn exec_table_init(&mut self, elem_index: u32, table_index: u32) -> Result<()> {
- let size: i32 = self.stack.values.pop(); // n
- let offset: i32 = self.stack.values.pop(); // s
- let dst: i32 = self.stack.values.pop(); // d
+ let size: i32 = self.store.stack.values.pop(); // n
+ let offset: i32 = self.store.stack.values.pop(); // s
+ let dst: i32 = self.store.stack.values.pop(); // d
let elem = self
.store
- .data
+ .state
.elements
.get(self.module.resolve_elem_addr(elem_index) as usize)
.ok_or_else(|| Error::Other("element not found".to_string()))?;
let table = self
.store
- .data
+ .state
.tables
.get_mut(self.module.resolve_table_addr(table_index) as usize)
.ok_or_else(|| Error::Other("table not found".to_string()))?;
@@ -1133,25 +1137,25 @@ impl<'store, 'stack> Executor<'store, 'stack> {
table.init(i64::from(dst), &items[offset as usize..(offset + size) as usize])
}
fn exec_table_grow(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index));
+ let table = self.store.state.get_table_mut(self.module.resolve_table_addr(table_index));
let sz = table.size();
- let n = self.stack.values.pop::<i32>();
- let val = self.stack.values.pop::<ValueRef>();
+ let n = self.store.stack.values.pop::<i32>();
+ let val = self.store.stack.values.pop::<ValueRef>();
match table.grow(n, val.into()) {
- Ok(()) => self.stack.values.push(sz),
- Err(_) => self.stack.values.push(-1_i32),
+ Ok(()) => self.store.stack.values.push(sz),
+ Err(_) => self.store.stack.values.push(-1_i32),
}
Ok(())
}
fn exec_table_fill(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index));
+ let table = self.store.state.get_table_mut(self.module.resolve_table_addr(table_index));
- let n = self.stack.values.pop::<i32>();
- let val = self.stack.values.pop::<ValueRef>();
- let i = self.stack.values.pop::<i32>();
+ let n = self.store.stack.values.pop::<i32>();
+ let val = self.store.stack.values.pop::<ValueRef>();
+ let i = self.store.stack.values.pop::<i32>();
if unlikely(i + n > table.size()) {
return Err(Error::Trap(Trap::TableOutOfBounds {
diff --git a/crates/tinywasm/src/interpreter/mod.rs b/crates/tinywasm/src/interpreter/mod.rs
index 6d94ce1..6f296ce 100644
--- a/crates/tinywasm/src/interpreter/mod.rs
+++ b/crates/tinywasm/src/interpreter/mod.rs
@@ -9,16 +9,16 @@ mod no_std_floats;
use crate::{Result, Store};
pub(crate) use value128::*;
-pub use values::*;
+pub(crate) use values::*;
/// The main `TinyWasm` runtime.
///
/// This is the default runtime used by `TinyWasm`.
#[derive(Debug, Default)]
-pub struct InterpreterRuntime {}
+pub(crate) struct InterpreterRuntime;
impl InterpreterRuntime {
- pub(crate) fn exec(&self, store: &mut Store, stack: &mut stack::Stack) -> Result<()> {
- executor::Executor::new(store, stack)?.run_to_completion()
+ pub(crate) fn exec(store: &mut Store) -> Result<()> {
+ executor::Executor::new(store)?.run_to_completion()
}
}
diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs
index 12d3022..35afca4 100644
--- a/crates/tinywasm/src/interpreter/num_helpers.rs
+++ b/crates/tinywasm/src/interpreter/num_helpers.rs
@@ -32,6 +32,7 @@ macro_rules! checked_conv_float {
// Conversion with an intermediate unsigned type and error checking (three types)
($from:tt, $intermediate:tt, $to:tt, $self:expr) => {
$self
+ .store
.stack
.values
.unary::<$from, $to>(|v| {
diff --git a/crates/tinywasm/src/interpreter/stack/block_stack.rs b/crates/tinywasm/src/interpreter/stack/block_stack.rs
index e5d87a8..b35ad94 100644
--- a/crates/tinywasm/src/interpreter/stack/block_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/block_stack.rs
@@ -1,4 +1,4 @@
-use crate::{StackConfig, unlikely};
+use crate::{engine::Config, unlikely};
use alloc::vec::Vec;
use crate::interpreter::values::{StackHeight, StackLocation};
@@ -7,8 +7,12 @@ use crate::interpreter::values::{StackHeight, StackLocation};
pub(crate) struct BlockStack(Vec<BlockFrame>);
impl BlockStack {
- pub(crate) fn new(config: &StackConfig) -> Self {
- Self(Vec::with_capacity(config.block_stack_init_size()))
+ pub(crate) fn new(config: &Config) -> Self {
+ Self(Vec::with_capacity(config.block_stack_init_size))
+ }
+
+ pub(crate) fn clear(&mut self) {
+ self.0.clear();
}
#[inline(always)]
diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs
index e0a4d6a..9954beb 100644
--- a/crates/tinywasm/src/interpreter/stack/call_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs
@@ -6,7 +6,7 @@ use crate::interpreter::{Value128, values::*};
use crate::{Error, unlikely};
use alloc::boxed::Box;
-use alloc::{rc::Rc, vec, vec::Vec};
+use alloc::{rc::Rc, vec::Vec};
use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmFunctionData, WasmValue};
pub(crate) const MAX_CALL_STACK_SIZE: usize = 1024;
@@ -18,8 +18,13 @@ pub(crate) struct CallStack {
impl CallStack {
#[inline]
- pub(crate) fn new(initial_frame: CallFrame) -> Self {
- Self { stack: vec![initial_frame] }
+ pub(crate) fn new(config: &crate::engine::Config) -> Self {
+ Self { stack: Vec::with_capacity(config.call_stack_init_size) }
+ }
+
+ pub(crate) fn reset(&mut self, call_frame: CallFrame) {
+ self.stack.clear();
+ self.stack.push(call_frame);
}
#[inline]
diff --git a/crates/tinywasm/src/interpreter/stack/mod.rs b/crates/tinywasm/src/interpreter/stack/mod.rs
index a4706f1..3da262c 100644
--- a/crates/tinywasm/src/interpreter/stack/mod.rs
+++ b/crates/tinywasm/src/interpreter/stack/mod.rs
@@ -6,7 +6,7 @@ pub(crate) use block_stack::{BlockFrame, BlockStack, BlockType};
pub(crate) use call_stack::{CallFrame, CallStack, Locals};
pub(crate) use value_stack::ValueStack;
-use crate::StackConfig;
+use crate::engine::Config;
/// A WebAssembly Stack
#[derive(Debug)]
@@ -17,11 +17,14 @@ pub(crate) struct Stack {
}
impl Stack {
- pub(crate) fn new(call_frame: CallFrame, config: &StackConfig) -> Self {
- Self {
- values: ValueStack::new(config),
- blocks: BlockStack::new(config),
- call_stack: CallStack::new(call_frame),
- }
+ pub(crate) fn new(config: &Config) -> Self {
+ Self { values: ValueStack::new(config), blocks: BlockStack::new(config), call_stack: CallStack::new(config) }
+ }
+
+ /// Initialize the stack with the given call frame (used for starting execution)
+ pub(crate) fn initialize(&mut self, callframe: CallFrame) {
+ self.blocks.clear();
+ self.values.clear();
+ self.call_stack.reset(callframe);
}
}
diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index 016b823..32dd3a8 100644
--- a/crates/tinywasm/src/interpreter/stack/value_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs
@@ -1,7 +1,7 @@
use alloc::vec::Vec;
use tinywasm_types::{ExternRef, FuncRef, ValType, ValueCounts, ValueCountsSmall, WasmValue};
-use crate::{Result, StackConfig, interpreter::*};
+use crate::{Result, engine::Config, interpreter::*};
use super::Locals;
@@ -14,15 +14,22 @@ pub(crate) struct ValueStack {
}
impl ValueStack {
- pub(crate) fn new(config: &StackConfig) -> Self {
+ pub(crate) fn new(config: &Config) -> Self {
Self {
- stack_32: Vec::with_capacity(config.value_stack_32_init_size()),
- stack_64: Vec::with_capacity(config.value_stack_64_init_size()),
- stack_128: Vec::with_capacity(config.value_stack_128_init_size()),
- stack_ref: Vec::with_capacity(config.value_stack_ref_init_size()),
+ stack_32: Vec::with_capacity(config.stack_32_init_size),
+ stack_64: Vec::with_capacity(config.stack_64_init_size),
+ stack_128: Vec::with_capacity(config.stack_128_init_size),
+ stack_ref: Vec::with_capacity(config.stack_ref_init_size),
}
}
+ pub(crate) fn clear(&mut self) {
+ self.stack_32.clear();
+ self.stack_64.clear();
+ self.stack_128.clear();
+ self.stack_ref.clear();
+ }
+
pub(crate) fn height(&self) -> StackLocation {
StackLocation {
s32: self.stack_32.len() as u32,
@@ -32,6 +39,10 @@ impl ValueStack {
}
}
+ pub(crate) fn len(&self) -> usize {
+ self.stack_32.len() + self.stack_64.len() + self.stack_128.len() + self.stack_ref.len()
+ }
+
#[inline]
pub(crate) fn peek<T: InternalValue>(&self) -> T {
T::stack_peek(self)
diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs
index a176670..07748b9 100644
--- a/crates/tinywasm/src/lib.rs
+++ b/crates/tinywasm/src/lib.rs
@@ -68,29 +68,6 @@
//! and other modules to be linked into the module when it is instantiated.
//!
//! See the [`Imports`] documentation for more information.
-//!
-//! ## Runtime Configuration
-//!
-//! For resource-constrained targets, you can configure the initial memory allocation:
-//!
-//! ```rust
-//! use tinywasm::{Store, StackConfig};
-//!
-//! // Create a store with minimal initial allocation (90% reduction in pre-allocated memory)
-//! let config = StackConfig::new()
-//! .with_value_stack_32_init_size(1024) // 1KB instead of 32KB
-//! .with_value_stack_64_init_size(512) // 512B instead of 16KB
-//! .with_value_stack_128_init_size(256) // 256B instead of 8KB
-//! .with_value_stack_ref_init_size(128) // 128B instead of 1KB
-
-//! .with_block_stack_init_size(32); // 32 instead of 128
-//! let store = Store::with_config(config);
-//!
-//! // Or create a partial configuration (only override what you need)
-//! let config = StackConfig::new()
-//! .with_value_stack_32_init_size(2048); // Only override 32-bit stack size
-//! let store = Store::with_config(config);
-//! ```
mod std;
extern crate alloc;
@@ -128,13 +105,12 @@ mod module;
mod reference;
mod store;
-/// Runtime for executing WebAssembly modules.
-pub mod interpreter;
-pub use interpreter::InterpreterRuntime;
+mod interpreter;
+use interpreter::InterpreterRuntime;
-/// Configuration for the WebAssembly interpreter's stack preallocation.
-pub mod config;
-pub use config::StackConfig;
+/// Global configuration for the WebAssembly interpreter
+pub mod engine;
+pub use engine::Engine;
#[cfg(feature = "parser")]
/// Re-export of [`tinywasm_parser`]. Requires `parser` feature.
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 9cafa7e..70a2b01 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -3,8 +3,9 @@ use core::fmt::Debug;
use core::sync::atomic::{AtomicUsize, Ordering};
use tinywasm_types::*;
-use crate::interpreter::{self, InterpreterRuntime, TinyWasmValue};
-use crate::{Error, Function, ModuleInstance, Result, StackConfig, Trap, cold};
+use crate::interpreter::TinyWasmValue;
+use crate::interpreter::stack::Stack;
+use crate::{Engine, Error, Function, ModuleInstance, Result, Trap, cold};
mod data;
mod element;
@@ -31,9 +32,9 @@ pub struct Store {
id: usize,
module_instances: Vec<ModuleInstance>,
- pub(crate) data: StoreData,
- pub(crate) runtime: Runtime,
- pub(crate) config: StackConfig,
+ pub(crate) engine: Engine,
+ pub(crate) state: State,
+ pub(crate) stack: Stack,
}
impl Debug for Store {
@@ -42,28 +43,17 @@ impl Debug for Store {
.field("id", &self.id)
.field("module_instances", &self.module_instances)
.field("data", &"...")
- .field("runtime", &self.runtime)
+ .field("engine", &self.engine)
.finish()
}
}
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum Runtime {
- Default,
-}
-
impl Store {
/// Create a new store
pub fn new() -> Self {
Self::default()
}
- /// Create a new store with the given stack configuration
- pub fn with_config(config: StackConfig) -> Self {
- let id = STORE_ID.fetch_add(1, Ordering::Relaxed);
- Self { id, module_instances: Vec::new(), data: StoreData::default(), runtime: Runtime::Default, config }
- }
-
/// Get a module instance by the internal id
pub fn get_module_instance(&self, addr: ModuleInstanceAddr) -> Option<&ModuleInstance> {
self.module_instances.get(addr as usize)
@@ -72,13 +62,6 @@ impl Store {
pub(crate) fn get_module_instance_raw(&self, addr: ModuleInstanceAddr) -> ModuleInstance {
self.module_instances[addr as usize].clone()
}
-
- /// Create a new store with the given runtime
- pub(crate) fn runtime(&self) -> interpreter::InterpreterRuntime {
- match self.runtime {
- Runtime::Default => InterpreterRuntime::default(),
- }
- }
}
impl PartialEq for Store {
@@ -90,13 +73,8 @@ impl PartialEq for Store {
impl Default for Store {
fn default() -> Self {
let id = STORE_ID.fetch_add(1, Ordering::Relaxed);
- Self {
- id,
- module_instances: Vec::new(),
- data: StoreData::default(),
- runtime: Runtime::Default,
- config: StackConfig::default(),
- }
+ let engine = Engine::default();
+ Self { id, module_instances: Vec::new(), state: State::default(), stack: Stack::new(engine.config()), engine }
}
}
@@ -105,7 +83,7 @@ impl Default for Store {
///
/// Data should only be addressable by the module that owns it
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#store>
-pub(crate) struct StoreData {
+pub(crate) struct State {
pub(crate) funcs: Vec<FunctionInstance>,
pub(crate) tables: Vec<TableInstance>,
pub(crate) memories: Vec<MemoryInstance>,
@@ -114,42 +92,23 @@ pub(crate) struct StoreData {
pub(crate) data: Vec<DataInstance>,
}
-impl Store {
- /// Get the store's ID (unique per process)
- pub fn id(&self) -> usize {
- self.id
- }
-
- pub(crate) fn next_module_instance_idx(&self) -> ModuleInstanceAddr {
- self.module_instances.len() as ModuleInstanceAddr
- }
-
- pub(crate) fn add_instance(&mut self, instance: ModuleInstance) {
- assert!(instance.id() == self.module_instances.len() as ModuleInstanceAddr);
- self.module_instances.push(instance);
- }
-
- #[cold]
- fn not_found_error(name: &str) -> Error {
- Error::Other(format!("{name} not found"))
- }
-
+impl State {
/// Get the function at the actual index in the store
#[inline]
pub(crate) fn get_func(&self, addr: FuncAddr) -> &FunctionInstance {
- &self.data.funcs[addr as usize]
+ &self.funcs[addr as usize]
}
/// Get the memory at the actual index in the store
#[inline]
pub(crate) fn get_mem(&self, addr: MemAddr) -> &MemoryInstance {
- &self.data.memories[addr as usize]
+ &self.memories[addr as usize]
}
/// Get the memory at the actual index in the store
#[inline(always)]
pub(crate) fn get_mem_mut(&mut self, addr: MemAddr) -> &mut MemoryInstance {
- &mut self.data.memories[addr as usize]
+ &mut self.memories[addr as usize]
}
/// Get the memory at the actual index in the store
@@ -159,7 +118,7 @@ impl Store {
addr: MemAddr,
addr2: MemAddr,
) -> Result<(&mut MemoryInstance, &mut MemoryInstance)> {
- match get_pair_mut(&mut self.data.memories, addr as usize, addr2 as usize) {
+ match get_pair_mut(&mut self.memories, addr as usize, addr2 as usize) {
Some(mems) => Ok(mems),
None => {
cold();
@@ -171,13 +130,13 @@ impl Store {
/// Get the table at the actual index in the store
#[inline]
pub(crate) fn get_table(&self, addr: TableAddr) -> &TableInstance {
- &self.data.tables[addr as usize]
+ &self.tables[addr as usize]
}
/// Get the table at the actual index in the store
#[inline]
pub(crate) fn get_table_mut(&mut self, addr: TableAddr) -> &mut TableInstance {
- &mut self.data.tables[addr as usize]
+ &mut self.tables[addr as usize]
}
/// Get two mutable tables at the actual index in the store
@@ -187,7 +146,7 @@ impl Store {
addr: TableAddr,
addr2: TableAddr,
) -> Result<(&mut TableInstance, &mut TableInstance)> {
- match get_pair_mut(&mut self.data.tables, addr as usize, addr2 as usize) {
+ match get_pair_mut(&mut self.tables, addr as usize, addr2 as usize) {
Some(tables) => Ok(tables),
None => {
cold();
@@ -199,31 +158,62 @@ impl Store {
/// Get the data at the actual index in the store
#[inline]
pub(crate) fn get_data_mut(&mut self, addr: DataAddr) -> &mut DataInstance {
- &mut self.data.data[addr as usize]
+ &mut self.data[addr as usize]
}
/// Get the element at the actual index in the store
#[inline]
pub(crate) fn get_elem_mut(&mut self, addr: ElemAddr) -> &mut ElementInstance {
- &mut self.data.elements[addr as usize]
+ &mut self.elements[addr as usize]
}
/// Get the global at the actual index in the store
#[inline]
pub(crate) fn get_global(&self, addr: GlobalAddr) -> &GlobalInstance {
- &self.data.globals[addr as usize]
+ &self.globals[addr as usize]
+ }
+
+ /// Get the global at the actual index in the store
+ pub(crate) fn get_global_val(&self, addr: MemAddr) -> TinyWasmValue {
+ self.globals[addr as usize].value.get()
+ }
+
+ /// Set the global at the actual index in the store
+ pub(crate) fn set_global_val(&mut self, addr: MemAddr, value: TinyWasmValue) {
+ self.globals[addr as usize].value.set(value);
+ }
+
+ #[cold]
+ fn not_found_error(name: &str) -> Error {
+ Error::Other(format!("{name} not found"))
+ }
+}
+
+impl Store {
+ /// Get the store's ID (unique per process)
+ pub fn id(&self) -> usize {
+ self.id
+ }
+
+ pub(crate) fn next_module_instance_idx(&self) -> ModuleInstanceAddr {
+ self.module_instances.len() as ModuleInstanceAddr
+ }
+
+ pub(crate) fn add_instance(&mut self, instance: ModuleInstance) {
+ assert!(instance.id() == self.module_instances.len() as ModuleInstanceAddr);
+ self.module_instances.push(instance);
}
/// Get the global at the actual index in the store
#[doc(hidden)]
pub fn get_global_val(&self, addr: MemAddr) -> TinyWasmValue {
- self.data.globals[addr as usize].value.get()
+ self.state.get_global_val(addr)
}
/// Set the global at the actual index in the store
#[doc(hidden)]
pub fn set_global_val(&mut self, addr: MemAddr, value: TinyWasmValue) {
- self.data.globals[addr as usize].value.set(value);
+ self.state.set_global_val(addr, value);
}
}
@@ -231,10 +221,10 @@ impl Store {
impl Store {
/// Add functions to the store, returning their addresses in the store
pub(crate) fn init_funcs(&mut self, funcs: Vec<WasmFunction>, idx: ModuleInstanceAddr) -> Result<Vec<FuncAddr>> {
- let func_count = self.data.funcs.len();
+ let func_count = self.state.funcs.len();
let mut func_addrs = Vec::with_capacity(func_count);
for (i, func) in funcs.into_iter().enumerate() {
- self.data.funcs.push(FunctionInstance::new_wasm(func, idx));
+ self.state.funcs.push(FunctionInstance::new_wasm(func, idx));
func_addrs.push((i + func_count) as FuncAddr);
}
Ok(func_addrs)
@@ -242,10 +232,10 @@ impl Store {
/// Add tables to the store, returning their addresses in the store
pub(crate) fn init_tables(&mut self, tables: Vec<TableType>, idx: ModuleInstanceAddr) -> Result<Vec<TableAddr>> {
- let table_count = self.data.tables.len();
+ let table_count = self.state.tables.len();
let mut table_addrs = Vec::with_capacity(table_count);
for (i, table) in tables.into_iter().enumerate() {
- self.data.tables.push(TableInstance::new(table, idx));
+ self.state.tables.push(TableInstance::new(table, idx));
table_addrs.push((i + table_count) as TableAddr);
}
Ok(table_addrs)
@@ -253,10 +243,10 @@ impl Store {
/// Add memories to the store, returning their addresses in the store
pub(crate) fn init_memories(&mut self, memories: Vec<MemoryType>, idx: ModuleInstanceAddr) -> Result<Vec<MemAddr>> {
- let mem_count = self.data.memories.len();
+ let mem_count = self.state.memories.len();
let mut mem_addrs = Vec::with_capacity(mem_count);
for (i, mem) in memories.into_iter().enumerate() {
- self.data.memories.push(MemoryInstance::new(mem, idx));
+ self.state.memories.push(MemoryInstance::new(mem, idx));
mem_addrs.push((i + mem_count) as MemAddr);
}
Ok(mem_addrs)
@@ -270,12 +260,12 @@ impl Store {
func_addrs: &[FuncAddr],
idx: ModuleInstanceAddr,
) -> Result<Vec<Addr>> {
- let global_count = self.data.globals.len();
+ let global_count = self.state.globals.len();
imported_globals.reserve_exact(new_globals.len());
let mut global_addrs = imported_globals;
for (i, global) in new_globals.iter().enumerate() {
- self.data.globals.push(GlobalInstance::new(
+ self.state.globals.push(GlobalInstance::new(
global.ty,
self.eval_const(&global.init, &global_addrs, func_addrs)?,
idx,
@@ -299,7 +289,7 @@ impl Store {
let addr = globals.get(*addr as usize).copied().ok_or_else(|| {
Error::Other(format!("global {addr} not found. This should have been caught by the validator"))
})?;
- self.data.globals[addr as usize].value.get().unwrap_ref()
+ self.state.globals[addr as usize].value.get().unwrap_ref()
}
ElementItem::Expr(item) => {
return Err(Error::UnsupportedFeature(format!("const expression other than ref: {item:?}")));
@@ -319,7 +309,7 @@ impl Store {
elements: &[Element],
idx: ModuleInstanceAddr,
) -> Result<(Box<[Addr]>, Option<Trap>)> {
- let elem_count = self.data.elements.len();
+ let elem_count = self.state.elements.len();
let mut elem_addrs = Vec::with_capacity(elem_count);
for (i, element) in elements.iter().enumerate() {
let init = element
@@ -343,7 +333,7 @@ impl Store {
.copied()
.ok_or_else(|| Error::Other(format!("table {table} not found for element {i}")))?;
- let Some(table) = self.data.tables.get_mut(table_addr as usize) else {
+ let Some(table) = self.state.tables.get_mut(table_addr as usize) else {
return Err(Error::Other(format!("table {table} not found for element {i}")));
};
@@ -361,7 +351,7 @@ impl Store {
}
};
- self.data.elements.push(ElementInstance::new(element.kind, idx, items));
+ self.state.elements.push(ElementInstance::new(element.kind, idx, items));
elem_addrs.push((i + elem_count) as Addr);
}
@@ -376,7 +366,7 @@ impl Store {
data: Vec<Data>,
idx: ModuleInstanceAddr,
) -> Result<(Box<[Addr]>, Option<Trap>)> {
- let data_count = self.data.data.len();
+ let data_count = self.state.data.len();
let mut data_addrs = Vec::with_capacity(data_count);
for (i, data) in data.into_iter().enumerate() {
let data_val = match data.kind {
@@ -386,7 +376,7 @@ impl Store {
};
let offset = self.eval_size_const(offset)?;
- let Some(mem) = self.data.memories.get_mut(*mem_addr as usize) else {
+ let Some(mem) = self.state.memories.get_mut(*mem_addr as usize) else {
return Err(Error::Other(format!("memory {mem_addr} not found for data segment {i}")));
};
@@ -399,7 +389,7 @@ impl Store {
tinywasm_types::DataKind::Passive => Some(data.data.to_vec()),
};
- self.data.data.push(DataInstance::new(data_val, idx));
+ self.state.data.push(DataInstance::new(data_val, idx));
data_addrs.push((i + data_count) as Addr);
}
@@ -408,26 +398,26 @@ impl Store {
}
pub(crate) fn add_global(&mut self, ty: GlobalType, value: TinyWasmValue, idx: ModuleInstanceAddr) -> Result<Addr> {
- self.data.globals.push(GlobalInstance::new(ty, value, idx));
- Ok(self.data.globals.len() as Addr - 1)
+ self.state.globals.push(GlobalInstance::new(ty, value, idx));
+ Ok(self.state.globals.len() as Addr - 1)
}
pub(crate) fn add_table(&mut self, table: TableType, idx: ModuleInstanceAddr) -> Result<TableAddr> {
- self.data.tables.push(TableInstance::new(table, idx));
- Ok(self.data.tables.len() as TableAddr - 1)
+ self.state.tables.push(TableInstance::new(table, idx));
+ Ok(self.state.tables.len() as TableAddr - 1)
}
pub(crate) fn add_mem(&mut self, mem: MemoryType, idx: ModuleInstanceAddr) -> Result<MemAddr> {
if let MemoryArch::I64 = mem.arch() {
return Err(Error::UnsupportedFeature("64-bit memories".to_string()));
}
- self.data.memories.push(MemoryInstance::new(mem, idx));
- Ok(self.data.memories.len() as MemAddr - 1)
+ self.state.memories.push(MemoryInstance::new(mem, idx));
+ Ok(self.state.memories.len() as MemAddr - 1)
}
pub(crate) fn add_func(&mut self, func: Function, idx: ModuleInstanceAddr) -> Result<FuncAddr> {
- self.data.funcs.push(FunctionInstance { func, owner: idx });
- Ok(self.data.funcs.len() as FuncAddr - 1)
+ self.state.funcs.push(FunctionInstance { func, owner: idx });
+ Ok(self.state.funcs.len() as FuncAddr - 1)
}
/// Evaluate a constant expression that's either a i32 or a i64 as a global or a const instruction
@@ -435,7 +425,7 @@ impl Store {
Ok(match const_instr {
ConstInstruction::I32Const(i) => i64::from(i),
ConstInstruction::I64Const(i) => i,
- ConstInstruction::GlobalGet(addr) => match self.data.globals[addr as usize].value.get() {
+ ConstInstruction::GlobalGet(addr) => match self.state.globals[addr as usize].value.get() {
TinyWasmValue::Value32(i) => i64::from(i),
TinyWasmValue::Value64(i) => i as i64,
o => return Err(Error::Other(format!("expected i32 or i64, got {o:?}"))),
@@ -464,7 +454,7 @@ impl Store {
})?;
let global =
- self.data.globals.get(*addr as usize).expect("global not found. This should be unreachable");
+ self.state.globals.get(*addr as usize).expect("global not found. This should be unreachable");
global.value.get()
}
RefFunc(None) => TinyWasmValue::ValueRef(None),