From 1ff5945c3373bd86191123690c81aa80deca57c6 Mon Sep 17 00:00:00 2001 From: Henry Date: Sat, 28 Mar 2026 18:17:12 +0100 Subject: chore: cleanup Signed-off-by: Henry --- crates/tinywasm/src/func.rs | 5 +- crates/tinywasm/src/imports.rs | 4 +- crates/tinywasm/src/instance.rs | 127 ++++++++++----------- crates/tinywasm/src/interpreter/executor.rs | 99 ++++++++++------ crates/tinywasm/src/interpreter/no_std_floats.rs | 20 ++-- crates/tinywasm/src/interpreter/num_helpers.rs | 9 -- .../tinywasm/src/interpreter/stack/call_stack.rs | 125 ++++++++------------ crates/tinywasm/src/interpreter/value128.rs | 15 --- crates/tinywasm/src/interpreter/values.rs | 3 - crates/tinywasm/src/store/memory.rs | 9 +- crates/tinywasm/src/store/mod.rs | 39 ++++--- crates/tinywasm/tests/testsuite/run.rs | 8 +- crates/tinywasm/tests/testsuite/util.rs | 2 +- crates/types/src/lib.rs | 3 - 14 files changed, 215 insertions(+), 253 deletions(-) (limited to 'crates') diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 3a3985b..6cf0c8c 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -56,12 +56,11 @@ impl FuncHandle { }; // 6. Let f be the dummy frame - let callframe = CallFrame::new(wasm_func, func_inst.owner, params, 0); + let callframe = CallFrame::new_with_params(wasm_func.locals, self.addr, 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) + // & 8. Push the values to the stack store.stack.clear(); - // 9. Invoke the function instance InterpreterRuntime::exec(store, callframe)?; diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs index dcd5e12..099396b 100644 --- a/crates/tinywasm/src/imports.rs +++ b/crates/tinywasm/src/imports.rs @@ -68,7 +68,9 @@ impl FuncContext<'_> { /// Get a reference to the module instance pub fn module(&self) -> crate::ModuleInstance { - self.store.get_module_instance_raw(self.module_addr) + self.store.get_module_instance(self.module_addr).unwrap_or_else(|| { + unreachable!("invalid module instance address in host function context: {}", self.module_addr) + }) } /// Get a reference to an exported memory diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs index 7eddb10..45542f9 100644 --- a/crates/tinywasm/src/instance.rs +++ b/crates/tinywasm/src/instance.rs @@ -35,20 +35,68 @@ pub(crate) struct ModuleInstanceInner { pub(crate) exports: ArcSlice, } -impl ModuleInstance { - // drop the module instance reference and swap it with another one - #[inline] - pub(crate) fn swap(&mut self, other: Self) { - self.0 = other.0; +impl ModuleInstanceInner { + pub(crate) fn func_ty(&self, addr: FuncAddr) -> &FuncType { + match self.types.get(addr as usize) { + Some(ty) => ty, + None => unreachable!("invalid function address: {addr}"), + } } - #[inline] - pub(crate) fn swap_with(&mut self, other_addr: ModuleInstanceAddr, store: &mut Store) { - if other_addr != self.id() { - self.swap(store.get_module_instance_raw(other_addr)) + pub(crate) fn func_addrs(&self) -> &[FuncAddr] { + &self.func_addrs + } + + // resolve a function address to the global store address + pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> FuncAddr { + match self.func_addrs.get(addr as usize) { + Some(addr) => *addr, + None => unreachable!("invalid function address: {addr}"), + } + } + + // resolve a table address to the global store address + pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> TableAddr { + match self.table_addrs.get(addr as usize) { + Some(addr) => *addr, + None => unreachable!("invalid table address: {addr}"), + } + } + + // resolve a memory address to the global store address + pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> MemAddr { + match self.mem_addrs.get(addr as usize) { + Some(addr) => *addr, + None => unreachable!("invalid memory address: {addr}"), } } + // resolve a data address to the global store address + pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> DataAddr { + match self.data_addrs.get(addr as usize) { + Some(addr) => *addr, + None => unreachable!("invalid data address: {addr}"), + } + } + + // resolve a memory address to the global store address + pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> ElemAddr { + match self.elem_addrs.get(addr as usize) { + Some(addr) => *addr, + None => unreachable!("invalid element address: {addr}"), + } + } + + // resolve a global address to the global store address + pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> GlobalAddr { + match self.global_addrs.get(addr as usize) { + Some(addr) => *addr, + None => unreachable!("invalid global address: {addr}"), + } + } +} + +impl ModuleInstance { /// Get the module instance's address #[inline] pub fn id(&self) -> ModuleInstanceAddr { @@ -91,12 +139,12 @@ impl ModuleInstance { exports: module.0.exports.clone(), }; - let instance = Self::new(instance); + let instance = Rc::new(instance); store.add_instance(instance.clone()); match (elem_trapped, data_trapped) { (Some(trap), _) | (_, Some(trap)) => Err(trap.into()), - _ => Ok(instance), + _ => Ok(ModuleInstance(instance)), } } @@ -113,57 +161,6 @@ impl ModuleInstance { Some(ExternVal::new(exports.kind, *addr)) } - #[inline] - pub(crate) fn new(inner: ModuleInstanceInner) -> Self { - Self(Rc::new(inner)) - } - - #[inline] - pub(crate) fn func_ty(&self, addr: FuncAddr) -> &FuncType { - &self.0.types[addr as usize] - } - - #[inline] - pub(crate) fn func_addrs(&self) -> &[FuncAddr] { - &self.0.func_addrs - } - - // resolve a function address to the global store address - #[inline] - pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> FuncAddr { - self.0.func_addrs[addr as usize] - } - - // resolve a table address to the global store address - #[inline] - pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> TableAddr { - self.0.table_addrs[addr as usize] - } - - // resolve a memory address to the global store address - #[inline] - pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> MemAddr { - self.0.mem_addrs[addr as usize] - } - - // resolve a data address to the global store address - #[inline] - pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> DataAddr { - self.0.data_addrs[addr as usize] - } - - // resolve a memory address to the global store address - #[inline] - pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> ElemAddr { - self.0.elem_addrs[addr as usize] - } - - // resolve a global address to the global store address - #[inline] - pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> GlobalAddr { - self.0.global_addrs[addr as usize] - } - /// Get an exported function by name pub fn exported_func_untyped(&self, store: &Store, name: &str) -> Result { if self.0.store_id != store.id() { @@ -211,13 +208,13 @@ impl ModuleInstance { /// Get a memory by address pub fn memory<'a>(&self, store: &'a Store, addr: MemAddr) -> Result> { - let mem = store.state.get_mem(self.resolve_mem_addr(addr)); + let mem = store.state.get_mem(self.0.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> { - let mem = store.state.get_mem_mut(self.resolve_mem_addr(addr)); + let mem = store.state.get_mem_mut(self.0.resolve_mem_addr(addr)); Ok(MemoryRefMut(mem)) } @@ -244,7 +241,7 @@ impl ModuleInstance { } }; - let func_addr = self.resolve_func_addr(func_index); + let func_addr = self.0.resolve_func_addr(func_index); let func_inst = store.state.get_func(func_addr); let ty = func_inst.func.ty(); diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 08a24cf..5dfad85 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -12,19 +12,24 @@ use tinywasm_types::*; use super::num_helpers::*; use super::stack::{BlockFrame, BlockType}; use super::values::*; +use crate::instance::ModuleInstanceInner; use crate::interpreter::Value128; use crate::*; pub(crate) struct Executor<'store> { - pub(crate) cf: CallFrame, - pub(crate) module: ModuleInstance, - pub(crate) store: &'store mut Store, + cf: CallFrame, + instructions: ArcSlice, + func: Rc, + module: Rc, + store: &'store mut Store, } impl<'store> Executor<'store> { pub(crate) fn new(store: &'store mut Store, cf: CallFrame) -> Result { - let module = store.get_module_instance_raw(cf.module_addr()); - Ok(Self { module, store, cf }) + let module = store.get_module_instance_raw(cf.module_addr).clone(); + let func = store.state.get_wasm_func(cf.func_addr).clone(); + let instructions = func.instructions.clone(); + Ok(Self { module, store, cf, func, instructions }) } pub(crate) fn run_to_completion(&mut self) -> Result<()> { @@ -72,8 +77,17 @@ impl<'store> Executor<'store> { }; } + let next = match self.instructions.0.get(self.cf.instr_ptr) { + Some(instr) => instr, + None => unreachable!( + "Instruction pointer out of bounds: {} ({} instructions)", + self.cf.instr_ptr, + self.instructions.0.len() + ), + }; + #[rustfmt::skip] - match self.cf.fetch_instr() { + match next { Nop | BrLabel(_) | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} Unreachable => return ControlFlow::Break(Some(Trap::Unreachable.into())), Drop32 => self.store.stack.values.drop::(), @@ -342,7 +356,7 @@ impl<'store> Executor<'store> { V128Store64Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, V128Load32Zero(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| Value128::from_i32x4([v, 0, 0, 0]))?, V128Load64Zero(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| Value128::from_i64x2([v, 0]))?, - V128Const(arg) => self.exec_const::(self.cf.data().v128_constants[*arg as usize].into()).to_cf()?, + V128Const(arg) => self.exec_const::(self.func.data.v128_constants[*arg as usize].into()).to_cf()?, I8x16ExtractLaneS(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i8(*lane) as i32), I8x16ExtractLaneU(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_u8(*lane) as i32), I16x8ExtractLaneS(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i16(*lane) as i32), @@ -509,7 +523,7 @@ impl<'store> Executor<'store> { I64x2ExtendHighI32x4S => stack_op!(unary Value128, |a| a.i64x2_extend_high_i32x4_s()), I64x2ExtendHighI32x4U => stack_op!(unary Value128, |a| a.i64x2_extend_high_i32x4_u()), I8x16Popcnt => stack_op!(unary Value128, |v| v.i8x16_popcnt()), - I8x16Shuffle(idx) => { let idx = self.cf.data().v128_constants[*idx as usize].to_le_bytes(); stack_op!(binary Value128, |a, b| Value128::i8x16_shuffle(a, b, idx)) } + I8x16Shuffle(idx) => { let idx = self.func.data.v128_constants[*idx as usize].to_le_bytes(); stack_op!(binary Value128, |a, b| Value128::i8x16_shuffle(a, b, idx)) } I16x8Q15MulrSatS => stack_op!(binary Value128, |a, b| a.i16x8_q15mulr_sat_s(b)), I32x4DotI16x8S => stack_op!(binary Value128, |a, b| a.i32x4_dot_i16x8_s(b)), F32x4Ceil => stack_op!(simd_unary f32x4_ceil), @@ -564,32 +578,44 @@ impl<'store> Executor<'store> { fn exec_call( &mut self, wasm_func: Rc, + func_addr: FuncAddr, owner: ModuleInstanceAddr, ) -> ControlFlow> { + if self.func != wasm_func { + self.func = wasm_func.clone(); + self.instructions = wasm_func.instructions.clone(); + } + if IS_RETURN_CALL { let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals); - self.cf.reuse_for(wasm_func, locals, self.store.stack.blocks.len() as u32, owner); + self.cf.reuse_for(func_addr, locals, self.store.stack.blocks.len() as u32, owner); } else { let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals); - let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.store.stack.blocks.len() as u32); + let new_call_frame = CallFrame::new(func_addr, owner, locals, self.store.stack.blocks.len() as u32); self.cf.incr_instr_ptr(); // skip the call instruction self.store.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame)).to_cf()?; } - self.module.swap_with(self.cf.module_addr(), self.store); + if self.cf.module_addr != self.module.idx { + self.module = self.store.get_module_instance_raw(self.cf.module_addr).clone(); + } + ControlFlow::Continue(()) } fn exec_call_host(&mut self, host_func: Rc) -> ControlFlow> { let params = self.store.stack.values.pop_types(&host_func.ty.params).collect::>(); - let res = host_func.call(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms).to_cf()?; + let res = host_func.call(FuncContext { store: self.store, module_addr: self.module.idx }, ¶ms).to_cf()?; self.store.stack.values.extend_from_wasmvalues(&res).to_cf()?; self.cf.incr_instr_ptr(); ControlFlow::Continue(()) } fn exec_call_direct(&mut self, v: u32) -> ControlFlow> { - let func_inst = self.store.state.get_func(self.module.resolve_func_addr(v)); + let addr = self.module.resolve_func_addr(v); + let func_inst = self.store.state.get_func(addr); match &func_inst.func { - crate::Function::Wasm(wasm_func) => self.exec_call::(wasm_func.clone(), func_inst.owner), + crate::Function::Wasm(wasm_func) => { + self.exec_call::(wasm_func.clone(), addr, func_inst.owner) + } crate::Function::Host(host_func) => self.exec_call_host(host_func.clone()), } } @@ -620,7 +646,7 @@ impl<'store> Executor<'store> { )); } - self.exec_call::(wasm_func.clone(), func_inst.owner) + self.exec_call::(wasm_func.clone(), func_ref, func_inst.owner) } crate::Function::Host(host_func) => { if host_func.ty != *call_ty { @@ -661,7 +687,7 @@ impl<'store> Executor<'store> { } fn enter_block(&mut self, end_instr_offset: u32, ty: BlockType, (params, results): (StackHeight, StackHeight)) { self.store.stack.blocks.push(BlockFrame { - instr_ptr: self.cf.instr_ptr() as u32, + instr_ptr: self.cf.instr_ptr as u32, end_instr_offset, stack_ptr: self.store.stack.values.height(), results, @@ -687,18 +713,18 @@ impl<'store> Executor<'store> { ControlFlow::Continue(()) } fn exec_brtable(&mut self, default: u32, len: u32) -> ControlFlow> { - let start = self.cf.instr_ptr() + 1; + let start = self.cf.instr_ptr + 1; let end = start + len as usize; - if end > self.cf.instructions().len() { + if end > self.func.instructions.len() { return ControlFlow::Break(Some(Error::Other(format!( "br_table out of bounds: {} >= {}", end, - self.cf.instructions().len() + self.func.instructions.len() )))); } let idx = self.store.stack.values.pop::(); - let to = match self.cf.instructions()[start..end].get(idx as usize) { + let to = match self.func.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()))), @@ -712,17 +738,23 @@ impl<'store> Executor<'store> { ControlFlow::Continue(()) } fn exec_return(&mut self) -> ControlFlow> { - let old = self.cf.block_ptr(); - match self.store.stack.call_stack.pop() { - None => return ControlFlow::Break(None), - Some(cf) => self.cf = cf, + let old = self.cf.block_ptr; + let Some(cf) = self.store.stack.call_stack.pop() else { return ControlFlow::Break(None) }; + + if cf.func_addr != self.cf.func_addr { + self.func = self.store.state.get_wasm_func(cf.func_addr).clone(); + self.instructions = self.func.instructions.clone(); + + if cf.module_addr != self.module.idx { + self.module = self.store.get_module_instance_raw(cf.module_addr).clone(); + } } - if old > self.cf.block_ptr() { + if old > cf.block_ptr { self.store.stack.blocks.truncate(old); } - self.module.swap_with(self.cf.module_addr(), self.store); + self.cf = cf; ControlFlow::Continue(()) } fn exec_end_block(&mut self) { @@ -748,7 +780,6 @@ impl<'store> Executor<'store> { fn exec_memory_size(&mut self, addr: u32) -> Result<()> { let mem = self.store.state.get_mem(self.module.resolve_mem_addr(addr)); - match mem.is_64bit() { true => self.store.stack.values.push::(mem.page_count as i64), false => self.store.stack.values.push::(mem.page_count as i32), @@ -757,21 +788,15 @@ impl<'store> Executor<'store> { fn exec_memory_grow(&mut self, addr: u32) -> Result<()> { 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.store.stack.values.pop::(), false => i64::from(self.store.stack.values.pop::()), }; - match ( - mem.is_64bit(), - match mem.grow(pages_delta) { - Some(_) => prev_size as i64, - None => -1_i64, - }, - ) { - (true, size) => self.store.stack.values.push::(size)?, - (false, size) => self.store.stack.values.push::(size as i32)?, + let size = mem.grow(pages_delta).map(|_| prev_size as i64).unwrap_or(-1); + match mem.is_64bit() { + true => self.store.stack.values.push::(size)?, + false => self.store.stack.values.push::(size as i32)?, }; Ok(()) diff --git a/crates/tinywasm/src/interpreter/no_std_floats.rs b/crates/tinywasm/src/interpreter/no_std_floats.rs index b6ce998..0698f5d 100644 --- a/crates/tinywasm/src/interpreter/no_std_floats.rs +++ b/crates/tinywasm/src/interpreter/no_std_floats.rs @@ -9,18 +9,18 @@ pub(super) trait NoStdFloatExt { #[rustfmt::skip] impl NoStdFloatExt for f64 { - #[inline] fn round(self) -> Self { libm::round(self) } - #[inline] fn ceil(self) -> Self { libm::ceil(self) } - #[inline] fn floor(self) -> Self { libm::floor(self) } - #[inline] fn trunc(self) -> Self { libm::trunc(self) } - #[inline] fn sqrt(self) -> Self { libm::sqrt(self) } + fn round(self) -> Self { libm::round(self) } + fn ceil(self) -> Self { libm::ceil(self) } + fn floor(self) -> Self { libm::floor(self) } + fn trunc(self) -> Self { libm::trunc(self) } + fn sqrt(self) -> Self { libm::sqrt(self) } } #[rustfmt::skip] impl NoStdFloatExt for f32 { - #[inline] fn round(self) -> Self { libm::roundf(self) } - #[inline] fn ceil(self) -> Self { libm::ceilf(self) } - #[inline] fn floor(self) -> Self { libm::floorf(self) } - #[inline] fn trunc(self) -> Self { libm::truncf(self) } - #[inline] fn sqrt(self) -> Self { libm::sqrtf(self) } + fn round(self) -> Self { libm::roundf(self) } + fn ceil(self) -> Self { libm::ceilf(self) } + fn floor(self) -> Self { libm::floorf(self) } + fn trunc(self) -> Self { libm::truncf(self) } + fn sqrt(self) -> Self { libm::sqrtf(self) } } diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs index 35afca4..f2b617d 100644 --- a/crates/tinywasm/src/interpreter/num_helpers.rs +++ b/crates/tinywasm/src/interpreter/num_helpers.rs @@ -70,7 +70,6 @@ macro_rules! impl_wasm_float_ops { ($($t:ty)*) => ($( impl TinywasmFloatExt for $t { // https://webassembly.github.io/spec/core/exec/numerics.html#op-fnearest - #[inline] fn tw_nearest(self) -> Self { match self { #[cfg(not(feature = "canonicalize_nans"))] @@ -95,7 +94,6 @@ macro_rules! impl_wasm_float_ops { // https://webassembly.github.io/spec/core/exec/numerics.html#op-fmin // Based on f32::minimum (which is not yet stable) - #[inline] fn tw_minimum(self, other: Self) -> Self { match self.partial_cmp(&other) { Some(core::cmp::Ordering::Less) => self, @@ -110,7 +108,6 @@ macro_rules! impl_wasm_float_ops { // https://webassembly.github.io/spec/core/exec/numerics.html#op-fmax // Based on f32::maximum (which is not yet stable) - #[inline] fn tw_maximum(self, other: Self) -> Self { match self.partial_cmp(&other) { Some(core::cmp::Ordering::Greater) => self, @@ -138,22 +135,18 @@ pub(crate) trait WasmIntOps { macro_rules! impl_wrapping_self_sh { ($($t:ty)*) => ($( impl WasmIntOps for $t { - #[inline] fn wasm_shl(self, rhs: Self) -> Self { self.wrapping_shl(rhs as u32) } - #[inline] fn wasm_shr(self, rhs: Self) -> Self { self.wrapping_shr(rhs as u32) } - #[inline] fn wasm_rotl(self, rhs: Self) -> Self { self.rotate_left(rhs as u32) } - #[inline] fn wasm_rotr(self, rhs: Self) -> Self { self.rotate_right(rhs as u32) } @@ -166,7 +159,6 @@ impl_wrapping_self_sh! { i32 i64 u32 u64 } macro_rules! impl_checked_wrapping_rem { ($($t:ty)*) => ($( impl TinywasmIntExt for $t { - #[inline] fn checked_wrapping_rem(self, rhs: Self) -> Result { if rhs == 0 { Err(Error::Trap(crate::Trap::DivisionByZero)) @@ -175,7 +167,6 @@ macro_rules! impl_checked_wrapping_rem { } } - #[inline] fn wasm_checked_div(self, rhs: Self) -> Result { if rhs == 0 { Err(Error::Trap(crate::Trap::DivisionByZero)) diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index 688dde8..9c588b3 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -3,8 +3,8 @@ use crate::interpreter::{Value128, values::*}; use crate::{Result, Trap, unlikely}; use alloc::boxed::Box; -use alloc::{rc::Rc, vec::Vec}; -use tinywasm_types::{ArcSlice, Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmFunctionData, WasmValue}; +use alloc::vec::Vec; +use tinywasm_types::{FuncAddr, LocalAddr, ModuleInstanceAddr, ValueCounts, WasmValue}; #[derive(Debug)] pub(crate) struct CallStack { @@ -36,11 +36,11 @@ impl CallStack { #[derive(Debug)] pub(crate) struct CallFrame { - instr_ptr: usize, - func_instance: Rc, - block_ptr: u32, - module_addr: ModuleInstanceAddr, + pub(crate) instr_ptr: usize, + pub(crate) block_ptr: u32, pub(crate) locals: Locals, + pub(crate) module_addr: ModuleInstanceAddr, + pub(crate) func_addr: FuncAddr, } #[derive(Debug)] @@ -62,12 +62,46 @@ impl Locals { } impl CallFrame { - pub(crate) fn instr_ptr(&self) -> usize { - self.instr_ptr + pub(crate) fn new(func_addr: FuncAddr, module_addr: ModuleInstanceAddr, locals: Locals, block_ptr: u32) -> Self { + Self { instr_ptr: 0, func_addr, module_addr, block_ptr, locals } } - pub(crate) fn data(&self) -> &WasmFunctionData { - &self.func_instance.data + pub(crate) fn new_with_params( + local_count: ValueCounts, + func_addr: FuncAddr, + module_addr: ModuleInstanceAddr, + params: &[WasmValue], + block_ptr: u32, + ) -> Self { + let locals = { + let mut locals_32 = Vec::with_capacity(local_count.c32 as usize); + let mut locals_64 = Vec::with_capacity(local_count.c64 as usize); + let mut locals_128 = Vec::with_capacity(local_count.c128 as usize); + let mut locals_ref = Vec::with_capacity(local_count.cref as usize); + + for p in params { + match p.into() { + TinyWasmValue::Value32(v) => locals_32.push(v), + TinyWasmValue::Value64(v) => locals_64.push(v), + TinyWasmValue::Value128(v) => locals_128.push(v), + TinyWasmValue::ValueRef(v) => locals_ref.push(v), + } + } + + locals_32.resize_with(local_count.c32 as usize, Default::default); + locals_64.resize_with(local_count.c64 as usize, Default::default); + locals_128.resize_with(local_count.c128 as usize, Default::default); + locals_ref.resize_with(local_count.cref as usize, Default::default); + + Locals { + locals_32: locals_32.into_boxed_slice(), + locals_64: locals_64.into_boxed_slice(), + locals_128: locals_128.into_boxed_slice(), + locals_ref: locals_ref.into_boxed_slice(), + } + }; + + Self::new(func_addr, module_addr, locals, block_ptr) } pub(crate) fn incr_instr_ptr(&mut self) { @@ -78,30 +112,14 @@ impl CallFrame { self.instr_ptr += offset as usize; } - pub(crate) fn module_addr(&self) -> ModuleInstanceAddr { - self.module_addr - } - - #[inline(always)] - pub(crate) fn fetch_instr(&self) -> &Instruction { - match self.func_instance.instructions.get(self.instr_ptr) { - Some(instr) => instr, - None => unreachable!("Instruction pointer out of bounds, this is a bug"), - } - } - - pub(crate) fn block_ptr(&self) -> u32 { - self.block_ptr - } - pub(crate) fn reuse_for( &mut self, - func: Rc, + func_addr: FuncAddr, locals: Locals, block_depth: u32, module_addr: ModuleInstanceAddr, ) { - self.func_instance = func; + self.func_addr = func_addr; self.module_addr = module_addr; self.locals = locals; self.block_ptr = block_depth; @@ -151,55 +169,4 @@ impl CallFrame { Some(()) } - - pub(crate) fn new( - func_instance: Rc, - module_addr: ModuleInstanceAddr, - params: &[WasmValue], - block_ptr: u32, - ) -> Self { - let locals = { - let mut locals_32 = Vec::with_capacity(func_instance.locals.c32 as usize); - let mut locals_64 = Vec::with_capacity(func_instance.locals.c64 as usize); - let mut locals_128 = Vec::with_capacity(func_instance.locals.c128 as usize); - let mut locals_ref = Vec::with_capacity(func_instance.locals.cref as usize); - - for p in params { - match p.into() { - TinyWasmValue::Value32(v) => locals_32.push(v), - TinyWasmValue::Value64(v) => locals_64.push(v), - TinyWasmValue::Value128(v) => locals_128.push(v), - TinyWasmValue::ValueRef(v) => locals_ref.push(v), - } - } - - locals_32.resize_with(func_instance.locals.c32 as usize, Default::default); - locals_64.resize_with(func_instance.locals.c64 as usize, Default::default); - locals_128.resize_with(func_instance.locals.c128 as usize, Default::default); - locals_ref.resize_with(func_instance.locals.cref as usize, Default::default); - - Locals { - locals_32: locals_32.into_boxed_slice(), - locals_64: locals_64.into_boxed_slice(), - locals_128: locals_128.into_boxed_slice(), - locals_ref: locals_ref.into_boxed_slice(), - } - }; - - Self { instr_ptr: 0, func_instance, module_addr, block_ptr, locals } - } - - pub(crate) fn new_raw( - func_instance: Rc, - module_addr: ModuleInstanceAddr, - locals: Locals, - block_ptr: u32, - ) -> Self { - Self { instr_ptr: 0, func_instance, module_addr, block_ptr, locals } - } - - #[inline] - pub(crate) fn instructions(&self) -> &ArcSlice { - &self.func_instance.instructions - } } diff --git a/crates/tinywasm/src/interpreter/value128.rs b/crates/tinywasm/src/interpreter/value128.rs index e2fa448..a16327f 100644 --- a/crates/tinywasm/src/interpreter/value128.rs +++ b/crates/tinywasm/src/interpreter/value128.rs @@ -124,33 +124,28 @@ impl Value128 { Self::from_le_bytes([x[0].to_bits().to_le_bytes()[0], x[0].to_bits().to_le_bytes()[1], x[0].to_bits().to_le_bytes()[2], x[0].to_bits().to_le_bytes()[3], x[0].to_bits().to_le_bytes()[4], x[0].to_bits().to_le_bytes()[5], x[0].to_bits().to_le_bytes()[6], x[0].to_bits().to_le_bytes()[7], x[1].to_bits().to_le_bytes()[0], x[1].to_bits().to_le_bytes()[1], x[1].to_bits().to_le_bytes()[2], x[1].to_bits().to_le_bytes()[3], x[1].to_bits().to_le_bytes()[4], x[1].to_bits().to_le_bytes()[5], x[1].to_bits().to_le_bytes()[6], x[1].to_bits().to_le_bytes()[7]]) } - #[inline] fn map_f32x4(self, mut op: impl FnMut(f32) -> f32) -> Self { let lanes = self.as_f32x4(); Self::from_f32x4([op(lanes[0]), op(lanes[1]), op(lanes[2]), op(lanes[3])]) } - #[inline] fn zip_f32x4(self, rhs: Self, mut op: impl FnMut(f32, f32) -> f32) -> Self { let a = self.as_f32x4(); let b = rhs.as_f32x4(); Self::from_f32x4([op(a[0], b[0]), op(a[1], b[1]), op(a[2], b[2]), op(a[3], b[3])]) } - #[inline] fn map_f64x2(self, mut op: impl FnMut(f64) -> f64) -> Self { let lanes = self.as_f64x2(); Self::from_f64x2([op(lanes[0]), op(lanes[1])]) } - #[inline] fn zip_f64x2(self, rhs: Self, mut op: impl FnMut(f64, f64) -> f64) -> Self { let a = self.as_f64x2(); let b = rhs.as_f64x2(); Self::from_f64x2([op(a[0], b[0]), op(a[1], b[1])]) } - #[inline] pub const fn reduce_or(self) -> u8 { let mut result = 0u8; let bytes = self.to_le_bytes(); @@ -2506,7 +2501,6 @@ impl core::ops::BitXor for Value128 { } } -#[inline] const fn canonicalize_simd_f32_nan(x: f32) -> f32 { #[cfg(feature = "canonicalize_nans")] if x.is_nan() { @@ -2518,7 +2512,6 @@ const fn canonicalize_simd_f32_nan(x: f32) -> f32 { x } -#[inline] const fn canonicalize_simd_f64_nan(x: f64) -> f64 { #[cfg(feature = "canonicalize_nans")] if x.is_nan() { @@ -2530,7 +2523,6 @@ const fn canonicalize_simd_f64_nan(x: f64) -> f64 { x } -#[inline] const fn saturate_i16_to_i8(x: i16) -> i8 { if x > i8::MAX as i16 { i8::MAX @@ -2541,7 +2533,6 @@ const fn saturate_i16_to_i8(x: i16) -> i8 { } } -#[inline] const fn saturate_i16_to_u8(x: i16) -> u8 { if x <= 0 { 0 @@ -2552,7 +2543,6 @@ const fn saturate_i16_to_u8(x: i16) -> u8 { } } -#[inline] const fn saturate_i32_to_i16(x: i32) -> i16 { if x > i16::MAX as i32 { i16::MAX @@ -2563,7 +2553,6 @@ const fn saturate_i32_to_i16(x: i32) -> i16 { } } -#[inline] const fn saturate_i32_to_u16(x: i32) -> u16 { if x <= 0 { 0 @@ -2574,7 +2563,6 @@ const fn saturate_i32_to_u16(x: i32) -> u16 { } } -#[inline] fn trunc_sat_f32_to_i32(v: f32) -> i32 { if v.is_nan() { 0 @@ -2587,7 +2575,6 @@ fn trunc_sat_f32_to_i32(v: f32) -> i32 { } } -#[inline] fn trunc_sat_f32_to_u32(v: f32) -> u32 { if v.is_nan() || v <= -1.0_f32 { 0 @@ -2598,7 +2585,6 @@ fn trunc_sat_f32_to_u32(v: f32) -> u32 { } } -#[inline] fn trunc_sat_f64_to_i32(v: f64) -> i32 { if v.is_nan() { 0 @@ -2611,7 +2597,6 @@ fn trunc_sat_f64_to_i32(v: f64) -> i32 { } } -#[inline] fn trunc_sat_f64_to_u32(v: f64) -> u32 { if v.is_nan() || v <= -1.0_f64 { 0 diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 447b163..3535725 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -197,7 +197,6 @@ macro_rules! impl_internalvalue { fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result) -> Result<()> { let v2 = stack.$stack.pop(); let v1 = stack.$stack.last_mut(); - *v1 = $to_internal(func($to_outer(*v1), $to_outer(v2))?); Ok(()) } @@ -206,14 +205,12 @@ macro_rules! impl_internalvalue { let v3 = stack.$stack.pop(); let v2 = stack.$stack.pop(); let v1 = stack.$stack.last_mut(); - *v1 = $to_internal(func($to_outer(*v1), $to_outer(v2), $to_outer(v3))?); Ok(()) } fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result) -> Result<()> { let v = stack.$stack.last_mut(); - *v = $to_internal(func($to_outer(*v))?); Ok(()) } diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs index 022db0d..c1df263 100644 --- a/crates/tinywasm/src/store/memory.rs +++ b/crates/tinywasm/src/store/memory.rs @@ -28,18 +28,14 @@ impl MemoryInstance { } } - #[inline] pub(crate) fn is_64bit(&self) -> bool { matches!(self.kind.arch(), MemoryArch::I64) } - #[inline] pub(crate) fn len(&self) -> usize { self.data.len() } - #[inline(never)] - #[cold] fn trap_oob(&self, addr: usize, len: usize) -> Error { Error::Trap(crate::Trap::MemoryOutOfBounds { offset: addr, len, max: self.data.len() }) } @@ -96,7 +92,7 @@ impl MemoryInstance { if end > self.data.len() { return Err(self.trap_oob(addr, len)); } - self.data[addr..end].fill_with(|| val); + self.data[addr..end].fill(val); Ok(()) } @@ -128,7 +124,6 @@ impl MemoryInstance { Ok(()) } - #[inline] pub(crate) fn grow(&mut self, pages_delta: i64) -> Option { let current_pages = self.page_count; let new_pages = current_pages as i64 + pages_delta; @@ -165,12 +160,10 @@ macro_rules! impl_mem_traits { ($($ty:ty, $size:expr),*) => { $( impl MemValue<$size> for $ty { - #[inline(always)] fn from_mem_bytes(bytes: [u8; $size]) -> Self { <$ty>::from_le_bytes(bytes.into()) } - #[inline(always)] fn to_mem_bytes(self) -> [u8; $size] { self.to_le_bytes().into() } diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index a0a025c..c1d20e6 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -1,8 +1,10 @@ +use alloc::rc::Rc; use alloc::{boxed::Box, format, string::ToString, vec::Vec}; use core::fmt::Debug; use core::sync::atomic::{AtomicUsize, Ordering}; use tinywasm_types::*; +use crate::instance::ModuleInstanceInner; use crate::interpreter::TinyWasmValue; use crate::interpreter::stack::Stack; use crate::{Engine, Error, Function, ModuleInstance, Result, Trap}; @@ -30,7 +32,7 @@ static STORE_ID: AtomicUsize = AtomicUsize::new(0); /// See pub struct Store { id: usize, - module_instances: Vec, + module_instances: Vec>, pub(crate) engine: Engine, pub(crate) state: State, @@ -50,17 +52,18 @@ impl Debug for Store { impl Store { /// Create a new store - pub fn new() -> Self { - Self::default() + pub fn new(engine: Engine) -> Self { + let id = STORE_ID.fetch_add(1, Ordering::Relaxed); + Self { id, module_instances: Vec::new(), state: State::default(), stack: Stack::new(engine.config()), engine } } /// 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) + pub fn get_module_instance(&self, addr: ModuleInstanceAddr) -> Option { + Some(ModuleInstance(self.module_instances.get(addr as usize)?.clone())) } - pub(crate) fn get_module_instance_raw(&self, addr: ModuleInstanceAddr) -> ModuleInstance { - self.module_instances[addr as usize].clone() + pub(crate) fn get_module_instance_raw(&self, addr: ModuleInstanceAddr) -> &Rc { + &self.module_instances[addr as usize] } } @@ -72,9 +75,7 @@ impl PartialEq for Store { impl Default for Store { fn default() -> Self { - let id = STORE_ID.fetch_add(1, Ordering::Relaxed); - let engine = Engine::default(); - Self { id, module_instances: Vec::new(), state: State::default(), stack: Stack::new(engine.config()), engine } + Self::new(Engine::default()) } } @@ -101,6 +102,19 @@ impl State { } } + /// Get a wasm function at the actual index in the store, panicking if it's a host function (which should be guaranteed by the validator) + pub(crate) fn get_wasm_func(&self, addr: FuncAddr) -> &Rc { + match self.funcs.get(addr as usize) { + Some(func) => match &func.func { + Function::Wasm(wasm_func) => wasm_func, + Function::Host(_) => unreachable!( + "expected a wasm function at address {addr}, but found a host function. This should be unreachable" + ), + }, + None => unreachable!("function {addr} not found. This should be unreachable"), + } + } + /// Get the memory at the actual index in the store pub(crate) fn get_mem(&self, addr: MemAddr) -> &MemoryInstance { match self.memories.get(addr as usize) { @@ -110,7 +124,6 @@ impl State { } /// Get the memory at the actual index in the store - #[inline(always)] pub(crate) fn get_mem_mut(&mut self, addr: MemAddr) -> &mut MemoryInstance { match self.memories.get_mut(addr as usize) { Some(mem) => mem, @@ -209,8 +222,8 @@ impl Store { self.module_instances.len() as ModuleInstanceAddr } - pub(crate) fn add_instance(&mut self, instance: ModuleInstance) { - assert!(instance.id() == self.module_instances.len() as ModuleInstanceAddr); + pub(crate) fn add_instance(&mut self, instance: Rc) { + assert!(instance.idx == self.module_instances.len() as ModuleInstanceAddr); self.module_instances.push(instance); } diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs index c46a276..6352730 100644 --- a/crates/tinywasm/tests/testsuite/run.rs +++ b/crates/tinywasm/tests/testsuite/run.rs @@ -57,16 +57,12 @@ impl ModuleRegistry { } } - fn get<'a>( - &self, - module_id: Option>, - store: &'a tinywasm::Store, - ) -> Option<&'a ModuleInstance> { + fn get(&self, module_id: Option>, store: &tinywasm::Store) -> Option { let addr = self.get_idx(module_id)?; store.get_module_instance(*addr) } - fn last<'a>(&self, store: &'a tinywasm::Store) -> Option<&'a ModuleInstance> { + fn last(&self, store: &tinywasm::Store) -> Option { store.get_module_instance(*self.last_module.as_ref()?) } } diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs index 59013ad..4699d69 100644 --- a/crates/tinywasm/tests/testsuite/util.rs +++ b/crates/tinywasm/tests/testsuite/util.rs @@ -40,7 +40,7 @@ pub fn exec_fn( return Err(tinywasm::Error::Other("no module found".to_string())); }; - let mut store = tinywasm::Store::new(); + let mut store = tinywasm::Store::default(); let module = tinywasm::Module::from(module); let instance = module.instantiate(&mut store, imports)?; instance.exported_func_untyped(&store, name)?.call(&mut store, args) diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 395c056..969620d 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -170,7 +170,6 @@ pub enum ExternVal { } impl ExternVal { - #[inline] pub fn kind(&self) -> ExternalKind { match self { Self::Func(_) => ExternalKind::Func, @@ -180,7 +179,6 @@ impl ExternVal { } } - #[inline] pub fn new(kind: ExternalKind, addr: Addr) -> Self { match kind { ExternalKind::Func => Self::Func(addr), @@ -418,7 +416,6 @@ pub enum ImportKind { } impl From<&ImportKind> for ExternalKind { - #[inline] fn from(kind: &ImportKind) -> Self { match kind { ImportKind::Function(_) => Self::Func, -- cgit v1.3.1