diff options
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/tinywasm/Cargo.toml | 4 | ||||
| -rw-r--r-- | crates/tinywasm/src/config.rs | 115 | ||||
| -rw-r--r-- | crates/tinywasm/src/engine.rs | 140 | ||||
| -rw-r--r-- | crates/tinywasm/src/func.rs | 264 | ||||
| -rw-r--r-- | crates/tinywasm/src/imports.rs | 8 | ||||
| -rw-r--r-- | crates/tinywasm/src/instance.rs | 14 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/executor.rs | 252 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/mod.rs | 8 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/num_helpers.rs | 1 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/block_stack.rs | 10 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/call_stack.rs | 11 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/mod.rs | 17 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/value_stack.rs | 23 | ||||
| -rw-r--r-- | crates/tinywasm/src/lib.rs | 34 | ||||
| -rw-r--r-- | crates/tinywasm/src/store/mod.rs | 168 |
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() }, ¶ms) .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), |
