diff options
| author | Henry <mail@henrygressmann.de> | 2026-04-18 00:37:24 +0200 |
|---|---|---|
| committer | Henry <mail@henrygressmann.de> | 2026-04-18 00:37:24 +0200 |
| commit | 77cf2a6812f5563f902479175cc8b59502ce233c (patch) | |
| tree | 54d44a5a5bb81de134c158bc766e6d45a14b6751 | |
| parent | 468a600d029d6aa45447c4346b11c9b9371050ca (diff) | |
chore: cleanup
Signed-off-by: Henry <mail@henrygressmann.de>
| -rw-r--r-- | crates/parser/src/visit.rs | 6 | ||||
| -rw-r--r-- | crates/tinywasm/src/func.rs | 29 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/executor.rs | 397 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/num_helpers.rs | 4 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/simd/instructions.rs | 98 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/simd/macros.rs | 4 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/simd/mod.rs | 60 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/simd/tests.rs | 10 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/simd/utils.rs | 6 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/mod.rs | 20 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/value_stack.rs | 89 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/values.rs | 12 | ||||
| -rw-r--r-- | crates/tinywasm/src/reference.rs | 4 | ||||
| -rw-r--r-- | crates/tinywasm/src/store/memory.rs | 22 | ||||
| -rw-r--r-- | crates/tinywasm/src/store/mod.rs | 11 | ||||
| -rw-r--r-- | crates/tinywasm/tests/internal_refs.rs | 2 | ||||
| -rw-r--r-- | crates/tinywasm/tests/memory_ref_api.rs | 2 | ||||
| -rw-r--r-- | crates/types/src/lib.rs | 2 | ||||
| -rw-r--r-- | examples/wasm-rust.rs | 2 |
19 files changed, 342 insertions, 438 deletions
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 3000b9b..5c99df2 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -30,7 +30,7 @@ struct LoweringCtx { #[derive(Default)] struct FunctionDataBuilder { - v128_constants: Vec<i128>, + v128_constants: Vec<[u8; 16]>, branch_table_targets: Vec<u32>, } @@ -481,12 +481,12 @@ impl<R: WasmModuleResources> wasmparser::VisitSimdOperator<'_> for FunctionBuild fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output { self.instructions.push(Instruction::I8x16Shuffle(self.data.v128_constants.len() as u32)); - self.data.v128_constants.push(i128::from_le_bytes(lanes)); + self.data.v128_constants.push(lanes); } fn visit_v128_const(&mut self, value: wasmparser::V128) -> Self::Output { self.instructions.push(Instruction::V128Const(self.data.v128_constants.len() as u32)); - self.data.v128_constants.push(value.i128()); + self.data.v128_constants.push(*value.bytes()); } } diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index e2a187f..536b518 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -1,4 +1,4 @@ -use crate::interpreter::stack::CallFrame; +use crate::interpreter::stack::{CallFrame, ValueStack}; use crate::reference::StoreItem; use crate::{Error, FunctionInstance, InterpreterRuntime, Result, Store, unlikely}; use alloc::rc::Rc; @@ -22,16 +22,16 @@ impl Function { }; // Reset stack, push args, allocate locals, create entry frame. - store.stack.clear(); - store.stack.values.extend_from_wasmvalues(params)?; - let locals_base = store.stack.values.enter_locals(&wasm_func.func.params, &wasm_func.func.locals)?; + store.call_stack.clear(); + store.value_stack.clear(); + store.value_stack.extend_from_wasmvalues(params)?; + let locals_base = store.value_stack.enter_locals(&wasm_func.func.params, &wasm_func.func.locals)?; let stack_offset = wasm_func.func.locals; let callframe = CallFrame::new(self.addr, wasm_func.owner, locals_base, stack_offset); // Execute until completion and then collect result values from the stack. InterpreterRuntime::exec(store, callframe)?; - - collect_call_results(store, &self.ty) + collect_call_results(&mut store.value_stack, &self.ty) } /// Call a function and return a resumable execution handle. @@ -53,9 +53,10 @@ impl Function { Ok(FuncExecution { store, state: FuncExecutionState::Completed { result: Some(result) } }) } FunctionInstance::Wasm(wasm_func) => { - store.stack.clear(); - store.stack.values.extend_from_wasmvalues(params)?; - let locals_base = store.stack.values.enter_locals(&wasm_func.func.params, &wasm_func.func.locals)?; + store.call_stack.clear(); + store.value_stack.clear(); + store.value_stack.extend_from_wasmvalues(params)?; + let locals_base = store.value_stack.enter_locals(&wasm_func.func.params, &wasm_func.func.locals)?; let stack_offset = wasm_func.func.locals; let callframe = CallFrame::new(self.addr, wasm_func.owner, locals_base, stack_offset); @@ -312,7 +313,7 @@ impl<'store> FuncExecution<'store> { match InterpreterRuntime::exec_with_fuel(self.store, exec_state.callframe, fuel)? { crate::interpreter::ExecState::Completed => { let result_ty = self.store.state.get_func(*root_func_addr).ty().clone(); - let result = collect_call_results(self.store, &result_ty)?; + let result = collect_call_results(&mut self.store.value_stack, &result_ty)?; self.state = FuncExecutionState::Completed { result: None }; Ok(ExecProgress::Completed(result)) } @@ -349,7 +350,7 @@ impl<'store> FuncExecution<'store> { match InterpreterRuntime::exec_with_time_budget(self.store, exec_state.callframe, time_budget)? { crate::interpreter::ExecState::Completed => { let result_ty = self.store.state.get_func(*root_func_addr).ty().clone(); - let result = collect_call_results(self.store, &result_ty)?; + let result = collect_call_results(&mut self.store.value_stack, &result_ty)?; self.state = FuncExecutionState::Completed { result: None }; Ok(ExecProgress::Completed(result)) } @@ -377,9 +378,9 @@ fn validate_call_params(func_ty: &FuncType, params: &[WasmValue]) -> Result<()> Ok(()) } -fn collect_call_results(store: &mut Store, func_ty: &FuncType) -> Result<Vec<WasmValue>> { - debug_assert!(store.stack.values.len() >= func_ty.results().len()); // m values are on the top of the stack (Ensured by validation) - let mut res: Vec<_> = store.stack.values.pop_types(func_ty.results().iter().rev()).collect(); // pop in reverse order since the stack is LIFO +fn collect_call_results(value_stack: &mut ValueStack, func_ty: &FuncType) -> Result<Vec<WasmValue>> { + debug_assert!(value_stack.len() >= func_ty.results().len()); // m values are on the top of the stack (Ensured by validation) + let mut res: Vec<_> = value_stack.pop_types(func_ty.results().iter().rev()).collect(); // pop in reverse order since the stack is LIFO res.reverse(); // reverse to get the original order Ok(res) } diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 03b3d3e..ca100b9 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -51,65 +51,65 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { fn exec(&mut self) -> Result<Option<()>> { macro_rules! stack_op { (unary $ty:ty, |$v:ident| $expr:expr) => {{ - let $v = self.store.stack.values.pop::<$ty>(); - self.store.stack.values.push::<$ty>($expr)?; + let $v = self.store.value_stack.pop::<$ty>(); + self.store.value_stack.push::<$ty>($expr)?; }}; (binary $ty:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{ - let $rhs = self.store.stack.values.pop::<$ty>(); - let $lhs = self.store.stack.values.pop::<$ty>(); - self.store.stack.values.push::<$ty>($expr)?; + let $rhs = self.store.value_stack.pop::<$ty>(); + let $lhs = self.store.value_stack.pop::<$ty>(); + self.store.value_stack.push::<$ty>($expr)?; }}; (binary try $ty:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{ - let $rhs = self.store.stack.values.pop::<$ty>(); - let $lhs = self.store.stack.values.pop::<$ty>(); - self.store.stack.values.push::<$ty>($expr?)?; + let $rhs = self.store.value_stack.pop::<$ty>(); + let $lhs = self.store.value_stack.pop::<$ty>(); + self.store.value_stack.push::<$ty>($expr?)?; }}; (unary $from:ty => $to:ty, |$v:ident| $expr:expr) => {{ - let $v = self.store.stack.values.pop::<$from>(); - self.store.stack.values.push::<$to>($expr)?; + let $v = self.store.value_stack.pop::<$from>(); + self.store.value_stack.push::<$to>($expr)?; }}; (binary $from:ty => $to:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{ - let $rhs = self.store.stack.values.pop::<$from>(); - let $lhs = self.store.stack.values.pop::<$from>(); - self.store.stack.values.push::<$to>($expr)?; + let $rhs = self.store.value_stack.pop::<$from>(); + let $lhs = self.store.value_stack.pop::<$from>(); + self.store.value_stack.push::<$to>($expr)?; }}; (binary_into2 $from:ty => $to:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{ - let $rhs = self.store.stack.values.pop::<$from>(); - let $lhs = self.store.stack.values.pop::<$from>(); + let $rhs = self.store.value_stack.pop::<$from>(); + let $lhs = self.store.value_stack.pop::<$from>(); let out = $expr; - self.store.stack.values.push::<$to>(out.0)?; - self.store.stack.values.push::<$to>(out.1)?; + self.store.value_stack.push::<$to>(out.0)?; + self.store.value_stack.push::<$to>(out.1)?; }}; (binary $lhs_ty:ty, $rhs_ty:ty, |$lhs:ident, $rhs:ident| $expr:expr) => { stack_op!(binary $lhs_ty, $rhs_ty => $rhs_ty, |$lhs, $rhs| $expr) }; (binary $lhs_ty:ty, $rhs_ty:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{ - let $rhs = self.store.stack.values.pop::<$rhs_ty>(); - let $lhs = self.store.stack.values.pop::<$lhs_ty>(); - self.store.stack.values.push::<$res>($expr)?; + let $rhs = self.store.value_stack.pop::<$rhs_ty>(); + let $lhs = self.store.value_stack.pop::<$lhs_ty>(); + self.store.value_stack.push::<$res>($expr)?; }}; (ternary $ty:ty, |$a:ident, $b:ident, $c:ident| $expr:expr) => {{ - let $c = self.store.stack.values.pop::<$ty>(); - let $b = self.store.stack.values.pop::<$ty>(); - let $a = self.store.stack.values.pop::<$ty>(); - self.store.stack.values.push::<$ty>($expr)?; + let $c = self.store.value_stack.pop::<$ty>(); + let $b = self.store.value_stack.pop::<$ty>(); + let $a = self.store.value_stack.pop::<$ty>(); + self.store.value_stack.push::<$ty>($expr)?; }}; (quaternary_into2 $from:ty => $to:ty, |$a:ident, $b:ident, $c:ident, $d:ident| $expr:expr) => {{ - let $d = self.store.stack.values.pop::<$from>(); - let $c = self.store.stack.values.pop::<$from>(); - let $b = self.store.stack.values.pop::<$from>(); - let $a = self.store.stack.values.pop::<$from>(); + let $d = self.store.value_stack.pop::<$from>(); + let $c = self.store.value_stack.pop::<$from>(); + let $b = self.store.value_stack.pop::<$from>(); + let $a = self.store.value_stack.pop::<$from>(); let out = $expr; - self.store.stack.values.push::<$to>(out.0)?; - self.store.stack.values.push::<$to>(out.1)?; + self.store.value_stack.push::<$to>(out.0)?; + self.store.value_stack.push::<$to>(out.1)?; }}; (local_set_pop $ty:ty, $local_index:expr) => {{ - let val = self.store.stack.values.pop::<$ty>(); - self.store.stack.values.local_set(&self.cf, *$local_index, val); + let val = self.store.value_stack.pop::<$ty>(); + self.store.value_stack.local_set(&self.cf, *$local_index, val); }}; (local_tee $ty:ty, $local_index:expr) => {{ - let val = self.store.stack.values.peek::<$ty>(); - self.store.stack.values.local_set(&self.cf, *$local_index, val); + let val = self.store.value_stack.peek::<$ty>(); + self.store.value_stack.local_set(&self.cf, *$local_index, val); }}; } @@ -130,13 +130,13 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { match next { Nop => {} Unreachable => return Err(Trap::Unreachable.into()), - Drop32 => self.store.stack.values.drop::<Value32>(), - Drop64 => self.store.stack.values.drop::<Value64>(), - Drop128 => self.store.stack.values.drop::<Value128>(), - Select32 => self.store.stack.values.select::<Value32>()?, - Select64 => self.store.stack.values.select::<Value64>()?, - Select128 => self.store.stack.values.select::<Value128>()?, - SelectMulti(counts) => self.store.stack.values.select_multi(*counts), + Drop32 => self.store.value_stack.drop::<Value32>(), + Drop64 => self.store.value_stack.drop::<Value64>(), + Drop128 => self.store.value_stack.drop::<Value128>(), + Select32 => self.store.value_stack.select::<Value32>()?, + Select64 => self.store.value_stack.select::<Value64>()?, + Select128 => self.store.value_stack.select::<Value128>()?, + SelectMulti(counts) => self.store.value_stack.select_multi(*counts), Call(v) => { self.exec_call_direct::<false>(*v)?; return Ok(None); } CallSelf => { self.exec_call_self::<false>()?; return Ok(None); } CallIndirect(ty, table) => { self.exec_call_indirect::<false>(*ty, *table)?; return Ok(None); } @@ -154,34 +154,34 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { JumpCmpLocalLocal64 { target_ip, left, right, op } => if self.exec_jump_cmp_local_local_64(*target_ip, *left, *right, *op) { return Ok(None) }, DropKeep { base32, keep32, base64, keep64, base128, keep128 } => { let mut base = self.cf.stack_base(); base.s32 += *base32 as u32; base.s64 += *base64 as u32; base.s128 += *base128 as u32; - self.store.stack.values.truncate_keep_counts(base, ValueCounts { c32: *keep32 as u16, c64: *keep64 as u16, c128: *keep128 as u16 }); + self.store.value_stack.truncate_keep_counts(base, ValueCounts { c32: *keep32 as u16, c64: *keep64 as u16, c128: *keep128 as u16 }); } - DropKeep32(base, keep) => self.store.stack.values.stack_32.truncate_keep((self.cf.stack_base().s32 + *base as u32) as usize, *keep as usize), - DropKeep64(base, keep) => self.store.stack.values.stack_64.truncate_keep((self.cf.stack_base().s64 + *base as u32) as usize, *keep as usize), - DropKeep128(base, keep) => self.store.stack.values.stack_128.truncate_keep((self.cf.stack_base().s128 + *base as u32) as usize, *keep as usize), + DropKeep32(base, keep) => self.store.value_stack.stack_32.truncate_keep((self.cf.stack_base().s32 + *base as u32) as usize, *keep as usize), + DropKeep64(base, keep) => self.store.value_stack.stack_64.truncate_keep((self.cf.stack_base().s64 + *base as u32) as usize, *keep as usize), + DropKeep128(base, keep) => self.store.value_stack.stack_128.truncate_keep((self.cf.stack_base().s128 + *base as u32) as usize, *keep as usize), BranchTable(default_ip, start, len) => { self.exec_branch_table(*default_ip, *start, *len); return Ok(None); } Return => { if self.exec_return() { return Ok(Some(())); } return Ok(None); } - LocalGet32(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value32>(&self.cf, *local_index))?, - LocalGet64(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value64>(&self.cf, *local_index))?, - LocalGet128(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value128>(&self.cf, *local_index))?, + LocalGet32(local_index) => self.store.value_stack.push(self.store.value_stack.local_get::<Value32>(&self.cf, *local_index))?, + LocalGet64(local_index) => self.store.value_stack.push(self.store.value_stack.local_get::<Value64>(&self.cf, *local_index))?, + LocalGet128(local_index) => self.store.value_stack.push(self.store.value_stack.local_get::<Value128>(&self.cf, *local_index))?, LocalSet32(local_index) => stack_op!(local_set_pop Value32, local_index), LocalSet64(local_index) => stack_op!(local_set_pop Value64, local_index), LocalSet128(local_index) => stack_op!(local_set_pop Value128, local_index), - LocalCopy32(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value32>(&self.cf, *from)), - LocalCopy64(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value64>(&self.cf, *from)), - LocalCopy128(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value128>(&self.cf, *from)), - AddLocalLocal32(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::<i32>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i32>(&self.cf, *b)))?, - AddLocalLocal64(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::<i64>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i64>(&self.cf, *b)))?, + LocalCopy32(from, to) => self.store.value_stack.local_set(&self.cf, *to, self.store.value_stack.local_get::<Value32>(&self.cf, *from)), + LocalCopy64(from, to) => self.store.value_stack.local_set(&self.cf, *to, self.store.value_stack.local_get::<Value64>(&self.cf, *from)), + LocalCopy128(from, to) => self.store.value_stack.local_set(&self.cf, *to, self.store.value_stack.local_get::<Value128>(&self.cf, *from)), + AddLocalLocal32(a, b) => self.store.value_stack.push(self.store.value_stack.local_get::<i32>(&self.cf, *a).wrapping_add(self.store.value_stack.local_get::<i32>(&self.cf, *b)))?, + AddLocalLocal64(a, b) => self.store.value_stack.push(self.store.value_stack.local_get::<i64>(&self.cf, *a).wrapping_add(self.store.value_stack.local_get::<i64>(&self.cf, *b)))?, AddConst32(c) => stack_op!(unary i32, |v| v.wrapping_add(*c)), AddConst64(c) => stack_op!(unary i64, |v| v.wrapping_add(*c)), - AddLocalConst32(local_index, c) => self.store.stack.values.local_update::<Value32>(&self.cf, *local_index, |local| *local = local.wrapping_add(*c as u32)), - AddLocalConst64(local_index, c) => self.store.stack.values.local_update::<Value64>(&self.cf, *local_index, |local| *local = local.wrapping_add(*c as u64)), - SetLocalConst32(local_index, c) => self.store.stack.values.local_set::<i32>(&self.cf, *local_index, *c), - SetLocalConst64(local_index, c) => self.store.stack.values.local_set::<i64>(&self.cf, *local_index, *c), + AddLocalConst32(local_index, c) => self.store.value_stack.local_update::<Value32>(&self.cf, *local_index, |local| local.wrapping_add(*c as u32)), + AddLocalConst64(local_index, c) => self.store.value_stack.local_update::<Value64>(&self.cf, *local_index, |local| local.wrapping_add(*c as u64)), + SetLocalConst32(local_index, c) => self.store.value_stack.local_set::<i32>(&self.cf, *local_index, *c), + SetLocalConst64(local_index, c) => self.store.value_stack.local_set::<i64>(&self.cf, *local_index, *c), StoreLocalLocal32(m, addr_local, value_local) => self.exec_store_local_local::<u32, 4>(*m, *addr_local, *value_local)?, StoreLocalLocal64(m, addr_local, value_local) => self.exec_store_local_local::<i64, 8>(*m, *addr_local, *value_local)?, StoreLocalLocal128(m, addr_local, value_local) => self.exec_store_local_local::<Value128, 16>(*m, *addr_local, *value_local)?, - LoadLocal32(m, addr_local) => self.exec_load_local::<i32, 4>(*m, *addr_local)?, + LoadLocal32(m, addr_local) => self.store.value_stack.push(self.exec_load_local_value::<i32, 4>(*m, *addr_local)?)?, LoadLocalTee32(m, addr_local, dst_local) => self.exec_load_local_tee::<i32, 4>(*m, *addr_local, *dst_local)?, LoadLocalSet32(m, addr_local, dst_local) => self.exec_load_local_set::<i32, 4>(*m, *addr_local, *dst_local)?, LoadLocalTee128(m, addr_local, dst_local) => self.exec_load_local_tee::<Value128, 16>(*m, *addr_local, *dst_local)?, @@ -454,7 +454,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { V128Store64Lane(arg, lane) => self.exec_mem_store_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?, V128Load32Zero(arg) => self.exec_mem_load::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i32x4([v, 0, 0, 0]))?, V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i64x2([v, 0]))?, - V128Const(arg) => self.exec_const(Value128(*self.func.data.v128_constants.get(*arg as usize).unwrap_or_else(|| {cold_path(); unreachable!("invalid v128 constant index") })))?, + V128Const(arg) => self.exec_const(Value128::from(self.func.data.v128_constants.get(*arg as usize).copied().unwrap_or_else(|| {cold_path(); unreachable!("invalid v128 constant index") })))?, 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), @@ -623,7 +623,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { I8x16Popcnt => stack_op!(unary Value128, |v| v.i8x16_popcnt()), I8x16Shuffle(idx) => { let mask = self.func.data.v128_constants.get(*idx as usize).unwrap_or_else(|| {cold_path(); unreachable!("invalid i128 constant index")}); - stack_op!(binary Value128, |a, b| Value128::i8x16_shuffle(a, b, *mask)) + stack_op!(binary Value128, |a, b| Value128::i8x16_shuffle(a, b, Value128::from(*mask))) }, 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)), @@ -708,55 +708,55 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { #[inline(always)] fn exec_jump_if_zero(&mut self, ip: u32) -> bool { - let condition = self.store.stack.values.pop::<i32>() == 0; + let condition = self.store.value_stack.pop::<i32>() == 0; self.jump_if(condition, ip) } #[inline(always)] fn exec_jump_if_non_zero(&mut self, ip: u32) -> bool { - let condition = self.store.stack.values.pop::<i32>() != 0; + let condition = self.store.value_stack.pop::<i32>() != 0; self.jump_if(condition, ip) } #[inline(always)] fn exec_jump_cmp_stack_const_32(&mut self, target_ip: u32, imm: i32, op: CmpOp) -> bool { - let condition = cmp_i32(self.store.stack.values.pop::<i32>(), imm, op); + let condition = cmp_i32(self.store.value_stack.pop::<i32>(), imm, op); self.jump_if(condition, target_ip) } #[inline(always)] fn exec_jump_cmp_stack_const_64(&mut self, target_ip: u32, imm: i64, op: CmpOp) -> bool { - let condition = cmp_i64(self.store.stack.values.pop::<i64>(), imm, op); + let condition = cmp_i64(self.store.value_stack.pop::<i64>(), imm, op); self.jump_if(condition, target_ip) } #[inline(always)] fn exec_jump_cmp_local_const_32(&mut self, target_ip: u32, local: LocalAddr, imm: i32, op: CmpOp) -> bool { - self.jump_if(cmp_i32(self.store.stack.values.local_get::<i32>(&self.cf, local), imm, op), target_ip) + self.jump_if(cmp_i32(self.store.value_stack.local_get::<i32>(&self.cf, local), imm, op), target_ip) } #[inline(always)] fn exec_jump_cmp_local_const_64(&mut self, target_ip: u32, local: LocalAddr, imm: i32, op: CmpOp) -> bool { - self.jump_if(cmp_i64(self.store.stack.values.local_get::<i64>(&self.cf, local), i64::from(imm), op), target_ip) + self.jump_if(cmp_i64(self.store.value_stack.local_get::<i64>(&self.cf, local), i64::from(imm), op), target_ip) } #[inline(always)] fn exec_jump_cmp_local_local_32(&mut self, target_ip: u32, left: LocalAddr, right: LocalAddr, op: CmpOp) -> bool { - let lhs = self.store.stack.values.local_get::<i32>(&self.cf, left); - let rhs = self.store.stack.values.local_get::<i32>(&self.cf, right); + let lhs = self.store.value_stack.local_get::<i32>(&self.cf, left); + let rhs = self.store.value_stack.local_get::<i32>(&self.cf, right); self.jump_if(cmp_i32(lhs, rhs, op), target_ip) } #[inline(always)] fn exec_jump_cmp_local_local_64(&mut self, target_ip: u32, left: LocalAddr, right: LocalAddr, op: CmpOp) -> bool { - let lhs = self.store.stack.values.local_get::<i64>(&self.cf, left); - let rhs = self.store.stack.values.local_get::<i64>(&self.cf, right); + let lhs = self.store.value_stack.local_get::<i64>(&self.cf, left); + let rhs = self.store.value_stack.local_get::<i64>(&self.cf, right); self.jump_if(cmp_i64(lhs, rhs, op), target_ip) } #[inline(always)] fn exec_branch_table(&mut self, default_ip: u32, start: u32, len: u32) { - let idx = self.store.stack.values.pop::<i32>(); + let idx = self.store.value_stack.pop::<i32>(); let target_ip = if idx >= 0 && (idx as u32) < len { self.func.data.branch_table_targets.get((start + idx as u32) as usize).copied().unwrap_or(default_ip) } else { @@ -776,10 +776,10 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { } if IS_RETURN_CALL { - self.store.stack.values.truncate_keep_counts(self.cf.locals_base, wasm_func.func.params); + self.store.value_stack.truncate_keep_counts(self.cf.locals_base, wasm_func.func.params); } - let res = self.store.stack.values.enter_locals(&wasm_func.func.params, &wasm_func.func.locals); + let res = self.store.value_stack.enter_locals(&wasm_func.func.params, &wasm_func.func.locals); let locals_base = res.map_err(|err| { cold_path(); if IS_RETURN_CALL { err } else { Error::Trap(Trap::CallStackOverflow) } @@ -789,7 +789,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { if !IS_RETURN_CALL { self.cf.incr_instr_ptr(); // skip the call instruction - self.store.stack.call_stack.push(self.cf)?; + self.store.call_stack.push(self.cf)?; } self.cf = new_call_frame; @@ -800,9 +800,9 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { Ok(()) } fn exec_call_host(&mut self, host_func: Rc<HostFunction>) -> Result<()> { - let params = self.store.stack.values.pop_types(host_func.ty.params()).collect::<Box<_>>(); + let params = self.store.value_stack.pop_types(host_func.ty.params()).collect::<Box<_>>(); let res = host_func.call(FuncContext { store: self.store, module_addr: self.module.idx }, ¶ms)?; - self.store.stack.values.extend_from_wasmvalues(&res)?; + self.store.value_stack.extend_from_wasmvalues(&res)?; self.cf.incr_instr_ptr(); Ok(()) } @@ -821,10 +821,10 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { let locals = self.func.locals; if IS_RETURN_CALL { - self.store.stack.values.truncate_keep_counts(self.cf.locals_base, params); + self.store.value_stack.truncate_keep_counts(self.cf.locals_base, params); } - let res = self.store.stack.values.enter_locals(¶ms, &locals); + let res = self.store.value_stack.enter_locals(¶ms, &locals); let locals_base = res.map_err(|err| { cold_path(); if IS_RETURN_CALL { err } else { Error::Trap(Trap::CallStackOverflow) } @@ -833,7 +833,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { if !IS_RETURN_CALL { self.cf.incr_instr_ptr(); - self.store.stack.call_stack.push(self.cf)?; + self.store.call_stack.push(self.cf)?; } self.cf = new_call_frame; Ok(()) @@ -843,7 +843,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { self.charge_call_fuel(FUEL_COST_CALL_TOTAL); // verify that the table is of the right type, this should be validated by the parser already let func_ref = { - let table_idx: u32 = self.store.stack.values.pop::<i32>() as u32; + let table_idx: u32 = self.store.value_stack.pop::<i32>() as u32; let table = self.store.state.get_table(self.module.resolve_table_addr(table_addr)); assert!(table.kind.element_type == WasmType::RefFunc, "table is not of type funcref"); @@ -889,8 +889,8 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { fn exec_return(&mut self) -> bool { let results = ValueCounts::from_iter(self.func.ty.results()); - self.store.stack.values.truncate_keep_counts(self.cf.locals_base, results); - let Some(cf) = self.store.stack.call_stack.pop() else { return true }; + self.store.value_stack.truncate_keep_counts(self.cf.locals_base, results); + let Some(cf) = self.store.call_stack.pop() else { return true }; if cf.func_addr != self.cf.func_addr { self.func = self.store.state.get_wasm_func(cf.func_addr).clone(); @@ -903,11 +903,6 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { false } - fn local_mem_addr<const N: usize>(&self, memarg: MemoryArg, addr_local: u8) -> Result<usize> { - let addr = u64::from(self.store.stack.values.local_get::<u32>(&self.cf, u16::from(addr_local))); - Self::effective_addr::<N>(addr, memarg.offset()) - } - #[cfg(target_pointer_width = "64")] fn effective_addr<const N: usize>(addr: u64, offset: u64) -> Result<usize> { let Some(addr) = offset.checked_add(addr) else { @@ -926,39 +921,31 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { Ok(addr) } - fn pop_mem_addr(&mut self, is_64bit: bool) -> u64 { - if is_64bit { - self.store.stack.values.pop::<i64>() as u64 - } else { - self.store.stack.values.pop::<i32>() as u32 as u64 - } - } - fn exec_store_local_local<T: InternalValue + MemValue<N>, const N: usize>( &mut self, memarg: MemoryArg, addr_local: u8, value_local: u8, ) -> Result<()> { - let effective_addr = self.local_mem_addr::<N>(memarg, addr_local)?; - let value = self.store.stack.values.local_get::<T>(&self.cf, u16::from(value_local)).to_mem_bytes(); + let addr = u64::from(self.store.value_stack.local_get::<u32>(&self.cf, u16::from(addr_local))); + let value = self.store.value_stack.local_get::<T>(&self.cf, u16::from(value_local)).to_mem_bytes(); let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(memarg.mem_addr())); - mem.store(effective_addr, value.len(), &value)?; + mem.store(Self::effective_addr::<N>(addr, memarg.offset())?, &value)?; Ok(()) } fn exec_load_local_value<T: MemValue<N>, const N: usize>(&self, memarg: MemoryArg, addr_local: u8) -> Result<T> { let mem = self.store.state.get_mem(self.module.resolve_mem_addr(memarg.mem_addr())); - mem.load_as::<N, T>(self.local_mem_addr::<N>(memarg, addr_local)?) + let addr = u64::from(self.store.value_stack.local_get::<u32>(&self.cf, u16::from(addr_local))); + mem.load_as::<N, T>(Self::effective_addr::<N>(addr, memarg.offset())?) } fn exec_load_local<T: InternalValue + MemValue<N>, const N: usize>( &mut self, - memarg: MemoryArg, - addr_local: u8, + mem: MemoryArg, + addr: u8, ) -> Result<()> { - let value = self.exec_load_local_value::<T, N>(memarg, addr_local)?; - self.store.stack.values.push(value) + self.store.value_stack.push(self.exec_load_local_value::<T, N>(mem, addr)?) } fn exec_load_local_tee<T: InternalValue + MemValue<N>, const N: usize>( @@ -968,8 +955,8 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { dst_local: u8, ) -> Result<()> { let value = self.exec_load_local_value::<T, N>(memarg, addr_local)?; - self.store.stack.values.local_set(&self.cf, u16::from(dst_local), value); - self.store.stack.values.push(value)?; + self.store.value_stack.local_set(&self.cf, u16::from(dst_local), value); + self.store.value_stack.push(value)?; Ok(()) } @@ -980,23 +967,23 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { dst_local: u8, ) -> Result<()> { let value = self.exec_load_local_value::<T, N>(memarg, addr_local)?; - self.store.stack.values.local_set(&self.cf, u16::from(dst_local), value); + self.store.value_stack.local_set(&self.cf, u16::from(dst_local), value); Ok(()) } fn exec_global_get(&mut self, global_index: u32) -> Result<()> { - self.store.stack.values.push_dyn(self.store.state.get_global_val(self.module.resolve_global_addr(global_index))) + self.store.value_stack.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) { let global_addr = self.module.resolve_global_addr(global_index); - let value = self.store.stack.values.pop::<T>().into(); + let value = self.store.value_stack.pop::<T>().into(); self.store.state.set_global_val(global_addr, value); } fn exec_global_set_32(&mut self, global_index: u32) { let global_addr = self.module.resolve_global_addr(global_index); - let raw = self.store.stack.values.pop::<Value32>(); + let raw = self.store.value_stack.pop::<Value32>(); let value = match self.store.state.get_global(global_addr).ty.ty { WasmType::I32 | WasmType::F32 => TinyWasmValue::Value32(raw), WasmType::RefExtern | WasmType::RefFunc => TinyWasmValue::ValueRef(ValueRef::from_raw(raw)), @@ -1006,88 +993,89 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { } fn exec_const<T: InternalValue>(&mut self, val: T) -> Result<()> { - self.store.stack.values.push(val) + self.store.value_stack.push(val) } fn exec_ref_is_null(&mut self) -> Result<()> { - let is_null = i32::from(self.store.stack.values.pop::<ValueRef>().is_null()); - self.store.stack.values.push::<i32>(is_null) + let is_null = i32::from(self.store.value_stack.pop::<ValueRef>().is_null()); + self.store.value_stack.push::<i32>(is_null) } 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::<i64>(mem.page_count as i64), - false => self.store.stack.values.push::<i32>(mem.page_count as i32), + true => self.store.value_stack.push::<i64>(mem.page_count as i64), + false => self.store.value_stack.push::<i32>(mem.page_count as i32), } } fn exec_memory_grow(&mut self, addr: u32) -> Result<()> { let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(addr)); let is_64bit = mem.is_64bit(); let pages_delta = match is_64bit { - true => self.store.stack.values.pop::<i64>(), - false => i64::from(self.store.stack.values.pop::<i32>()), + true => self.store.value_stack.pop::<i64>(), + false => i64::from(self.store.value_stack.pop::<i32>()), }; let size = mem.grow(pages_delta).unwrap_or(-1); match is_64bit { - true => self.store.stack.values.push::<i64>(size)?, - false => self.store.stack.values.push::<i32>(size as i32)?, + true => self.store.value_stack.push::<i64>(size)?, + false => self.store.value_stack.push::<i32>(size as i32)?, }; Ok(()) } fn exec_memory_copy(&mut self, dst_mem: u32, src_mem: u32) -> Result<()> { - let size: i32 = self.store.stack.values.pop(); - let src: i32 = self.store.stack.values.pop(); - let dst: i32 = self.store.stack.values.pop(); + let size: i32 = self.store.value_stack.pop(); + let src: i32 = self.store.value_stack.pop(); + let dst: i32 = self.store.value_stack.pop(); + let dst_mem_addr = self.module.resolve_mem_addr(dst_mem); if dst_mem == src_mem { - let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(dst_mem)); // copy within the same memory + let mem = self.store.state.get_mem_mut(dst_mem_addr); mem.copy_within(dst as usize, src as usize, size as usize)?; } else { // copy between two memories - let (dst_memory, src_memory) = self - .store - .state - .get_mems_mut(self.module.resolve_mem_addr(dst_mem), self.module.resolve_mem_addr(src_mem)); - + let src_mem_addr = self.module.resolve_mem_addr(src_mem); + let (dst_memory, src_memory) = self.store.state.get_mems_mut(dst_mem_addr, src_mem_addr); dst_memory.copy_from_slice(dst as usize, src_memory.load(src as usize, size as usize)?)?; } Ok(()) } fn exec_memory_fill(&mut self, addr: u32) -> Result<()> { - 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 size: i32 = self.store.value_stack.pop(); + let val: i32 = self.store.value_stack.pop(); + let dst: i32 = self.store.value_stack.pop(); self.exec_memory_fill_impl(addr, dst, val as u8, size) } fn exec_memory_fill_imm(&mut self, addr: u32, val: u8, size: i32) -> Result<()> { - let dst: i32 = self.store.stack.values.pop(); + let dst: i32 = self.store.value_stack.pop(); self.exec_memory_fill_impl(addr, dst, val, size) } fn exec_memory_fill_impl(&mut self, addr: u32, dst: i32, val: u8, size: i32) -> Result<()> { - let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(addr)); - mem.fill(dst as usize, size as usize, val) + self.store.state.get_mem_mut(self.module.resolve_mem_addr(addr)).fill(dst as usize, size as usize, val) } fn exec_memory_init(&mut self, data_index: u32, mem_index: u32) -> Result<()> { - 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 size: i32 = self.store.value_stack.pop(); + let offset: i32 = self.store.value_stack.pop(); + let dst: i32 = self.store.value_stack.pop(); let data_addr = self.module.resolve_data_addr(data_index) as usize; - let data = self.store.state.data.get(data_addr).ok_or_else(|| Error::Other("data not found".to_string()))?; + let Some(data) = self.store.state.data.get(data_addr) else { + cold_path(); + unreachable!("data segment not found, should have been validated by the parser") + }; let mem_addr = self.module.resolve_mem_addr(mem_index) as usize; - let mem = - self.store.state.memories.get_mut(mem_addr).ok_or_else(|| Error::Other("memory not found".to_string()))?; + let Some(mem) = self.store.state.memories.get_mut(mem_addr) else { + cold_path(); + unreachable!("memory not found, should have been validated by the parser") + }; let data_len = data.data.as_ref().map_or(0, |d| d.len()); - if ((size + offset) as usize > data_len) || ((dst + size) as usize > mem.len()) { cold_path(); return Err(Trap::MemoryOutOfBounds { offset: offset as usize, len: size as usize, max: data_len }.into()); @@ -1102,26 +1090,21 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { return Err(Trap::MemoryOutOfBounds { offset: 0, len: 0, max: 0 }.into()); }; - mem.store(dst as usize, size as usize, &data[offset as usize..((offset + size) as usize)]) + mem.store(dst as usize, &data[offset as usize..((offset + size) as usize)]) } fn exec_table_copy(&mut self, dst_table: u32, src_table: u32) -> Result<()> { - let size: i32 = self.store.stack.values.pop(); - let src: i32 = self.store.stack.values.pop(); - let dst: i32 = self.store.stack.values.pop(); + let size: i32 = self.store.value_stack.pop(); + let src: i32 = self.store.value_stack.pop(); + let dst: i32 = self.store.value_stack.pop(); + let dst_table_addr = self.module.resolve_table_addr(dst_table); if dst_table == src_table { // copy within the same table - self.store.state.get_table_mut(self.module.resolve_table_addr(dst_table)).copy_within( - dst as usize, - src as usize, - size as usize, - ) + self.store.state.get_table_mut(dst_table_addr).copy_within(dst as usize, src as usize, size as usize) } else { // copy between two tables - let (dst_table_ref, src_table_ref) = self - .store - .state - .get_tables_mut(self.module.resolve_table_addr(dst_table), self.module.resolve_table_addr(src_table)); + let src_table_addr = self.module.resolve_table_addr(src_table); + let (dst_table_ref, src_table_ref) = self.store.state.get_tables_mut(dst_table_addr, src_table_addr); dst_table_ref.copy_from_slice(dst as usize, src_table_ref.load(src as usize, size as usize)?) } } @@ -1132,16 +1115,14 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { offset: u64, lane: u8, ) -> Result<()> { - let mut imm = self.store.stack.values.pop::<Value128>().to_mem_bytes(); - let val = self.store.stack.values.pop::<i32>() as u64; + let mut imm = self.store.value_stack.pop::<Value128>().to_mem_bytes(); + let val = self.store.value_stack.pop::<i32>() as u64; let mem = self.store.state.get_mem(self.module.resolve_mem_addr(mem_addr)); let addr = Self::effective_addr::<LOAD_SIZE>(val, offset)?; let val = mem.load_as::<LOAD_SIZE, LOAD>(addr)?.to_mem_bytes(); - let offset = lane as usize * LOAD_SIZE; imm[offset..offset + LOAD_SIZE].copy_from_slice(&val); - - self.store.stack.values.push(Value128::from_mem_bytes(imm))?; + self.store.value_stack.push(Value128::from_mem_bytes(imm))?; Ok(()) } @@ -1150,19 +1131,16 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { &mut self, mem_addr: tinywasm_types::MemAddr, offset: u64, - cast: fn(LOAD) -> TARGET, + cast: impl Fn(LOAD) -> TARGET, ) -> Result<()> { let mem = self.store.state.get_mem(self.module.resolve_mem_addr(mem_addr)); - let base = if mem.is_64bit() { - self.store.stack.values.pop::<i64>() as u64 - } else { - self.store.stack.values.pop::<i32>() as u32 as u64 + let base = match mem.is_64bit() { + true => self.store.value_stack.pop::<i64>() as u64, + false => self.store.value_stack.pop::<i32>() as u32 as u64, }; let addr = Self::effective_addr::<LOAD_SIZE>(base, offset)?; - let val = mem.load_as::<LOAD_SIZE, LOAD>(addr)?; - self.store.stack.values.push(cast(val))?; - Ok(()) + self.store.value_stack.push(cast(val)) } fn exec_mem_store_lane<U: MemValue<N> + Copy, const N: usize>( @@ -1171,75 +1149,66 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { offset: u64, lane: u8, ) -> Result<()> { - let bytes = self.store.stack.values.pop::<Value128>().to_mem_bytes(); + let bytes = self.store.value_stack.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 mem_addr = self.module.resolve_mem_addr(mem_addr); - let is_64bit = self.store.state.get_mem(mem_addr).is_64bit(); - let effective_addr = Self::effective_addr::<N>(self.pop_mem_addr(is_64bit), offset)?; let mem = self.store.state.get_mem_mut(mem_addr); - - mem.store(effective_addr, val.len(), &val)?; - - Ok(()) + let addr = match mem.is_64bit() { + true => self.store.value_stack.pop::<i64>() as u64, + false => self.store.value_stack.pop::<i32>() as u32 as u64, + }; + let effective_addr = Self::effective_addr::<N>(addr, offset)?; + mem.store(effective_addr, &val) } fn exec_mem_store<T: InternalValue, U: MemValue<N>, const N: usize>( &mut self, mem_addr: tinywasm_types::MemAddr, offset: u64, - cast: fn(T) -> U, + cast: impl Fn(T) -> U, ) -> Result<()> { - let val = self.store.stack.values.pop::<T>(); - let val = (cast(val)).to_mem_bytes(); + let val = self.store.value_stack.pop::<T>(); + let val = cast(val).to_mem_bytes(); let mem_addr = self.module.resolve_mem_addr(mem_addr); - let is_64bit = self.store.state.get_mem(mem_addr).is_64bit(); - let effective_addr = Self::effective_addr::<N>(self.pop_mem_addr(is_64bit), offset)?; let mem = self.store.state.get_mem_mut(mem_addr); - - mem.store(effective_addr, val.len(), &val)?; - Ok(()) + let addr = match mem.is_64bit() { + true => self.store.value_stack.pop::<i64>() as u64, + false => self.store.value_stack.pop::<i32>() as u32 as u64, + }; + let effective_addr = Self::effective_addr::<N>(addr, offset)?; + mem.store(effective_addr, &val) } fn exec_table_get(&mut self, table_index: u32) -> Result<()> { - let idx: i32 = self.store.stack.values.pop::<i32>(); + let idx: i32 = self.store.value_stack.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.store.stack.values.push_dyn(v.into())?; - Ok(()) + self.store.value_stack.push_dyn(v.into()) } fn exec_table_set(&mut self, table_index: u32) -> Result<()> { - let val = self.store.stack.values.pop::<ValueRef>(); - let idx = self.store.stack.values.pop::<i32>() as u32; + let val = self.store.value_stack.pop::<ValueRef>(); + let idx = self.store.value_stack.pop::<i32>() as u32; let table = self.store.state.get_table_mut(self.module.resolve_table_addr(table_index)); table.set(idx, val.addr().into()) } fn exec_table_size(&mut self, table_index: u32) -> Result<()> { let table = self.store.state.get_table(self.module.resolve_table_addr(table_index)); - self.store.stack.values.push(table.size())?; - Ok(()) + self.store.value_stack.push(table.size()) } fn exec_table_init(&mut self, elem_index: u32, table_index: u32) -> Result<()> { - 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 - .state - .elements - .get(self.module.resolve_elem_addr(elem_index) as usize) - .ok_or_else(|| Error::Other("element not found".to_string()))?; + let size: i32 = self.store.value_stack.pop(); // n + let offset: i32 = self.store.value_stack.pop(); // s + let dst: i32 = self.store.value_stack.pop(); // d + let elem_addr = self.module.resolve_elem_addr(elem_index) as usize; + let elem = + self.store.state.elements.get(elem_addr).ok_or_else(|| Error::Other("element not found".to_string()))?; - let table = self - .store - .state - .tables - .get_mut(self.module.resolve_table_addr(table_index) as usize) - .ok_or_else(|| Error::Other("table not found".to_string()))?; + let table_addr = self.module.resolve_table_addr(table_index) as usize; + let table = + self.store.state.tables.get_mut(table_addr).ok_or_else(|| Error::Other("table not found".to_string()))?; let elem_len = elem.items.as_ref().map_or(0, alloc::vec::Vec::len); let table_len = table.size(); @@ -1268,23 +1237,19 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { fn exec_table_grow(&mut self, table_index: u32) -> Result<()> { let table = self.store.state.get_table_mut(self.module.resolve_table_addr(table_index)); let sz = table.size(); - - let n = self.store.stack.values.pop::<i32>(); - let val = self.store.stack.values.pop::<ValueRef>(); - + let n = self.store.value_stack.pop::<i32>(); + let val = self.store.value_stack.pop::<ValueRef>(); match table.grow(n, val.addr().into()) { - Ok(()) => self.store.stack.values.push(sz)?, - Err(_) => self.store.stack.values.push(-1_i32)?, + Ok(()) => self.store.value_stack.push(sz), + Err(_) => self.store.value_stack.push(-1_i32), } - - Ok(()) } fn exec_table_fill(&mut self, table_index: u32) -> Result<()> { let table = self.store.state.get_table_mut(self.module.resolve_table_addr(table_index)); - let n = self.store.stack.values.pop::<i32>(); - let val = self.store.stack.values.pop::<ValueRef>(); - let i = self.store.stack.values.pop::<i32>(); + let n = self.store.value_stack.pop::<i32>(); + let val = self.store.value_stack.pop::<ValueRef>(); + let i = self.store.value_stack.pop::<i32>(); if i + n > table.size() { cold_path(); diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs index 20882b3..6fa4df0 100644 --- a/crates/tinywasm/src/interpreter/num_helpers.rs +++ b/crates/tinywasm/src/interpreter/num_helpers.rs @@ -31,7 +31,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) => {{ - let v = $self.store.stack.values.pop::<$from>(); + let v = $self.store.value_stack.pop::<$from>(); let (min, max) = float_min_max!($from, $intermediate); if unlikely(v.is_nan()) { return Err(Error::Trap(crate::Trap::InvalidConversionToInt)); @@ -39,7 +39,7 @@ macro_rules! checked_conv_float { if unlikely(v <= min || v >= max) { return Err(Error::Trap(crate::Trap::IntegerOverflow)); } - $self.store.stack.values.push::<$to>((v as $intermediate as $to).into())?; + $self.store.value_stack.push::<$to>((v as $intermediate as $to).into())?; }}; } diff --git a/crates/tinywasm/src/interpreter/simd/instructions.rs b/crates/tinywasm/src/interpreter/simd/instructions.rs index ba519b5..dec4b4d 100644 --- a/crates/tinywasm/src/interpreter/simd/instructions.rs +++ b/crates/tinywasm/src/interpreter/simd/instructions.rs @@ -28,7 +28,7 @@ impl Value128 { pub fn v128_any_true(self) -> bool { simd_impl! { wasm => { wasm::v128_any_true(self.to_wasm_v128()) } - generic => { self.0 != 0 } + generic => { self.0.iter().any(|&b| b != 0) } } } @@ -36,7 +36,7 @@ impl Value128 { pub fn v128_not(self) -> Self { simd_impl! { wasm => { Self::from_wasm_v128(wasm::v128_not(self.to_wasm_v128())) } - generic => { Self(!self.0) } + generic => { Self(self.0.map(|b| !b)) } } } @@ -44,7 +44,7 @@ impl Value128 { pub fn v128_and(self, rhs: Self) -> Self { simd_impl! { wasm => { Self::from_wasm_v128(wasm::v128_and(self.to_wasm_v128(), rhs.to_wasm_v128())) } - generic => { Self(self.0 & rhs.0) } + generic => { (i128::from_le_bytes(self.0) & i128::from_le_bytes(rhs.0)).into() } } } @@ -52,7 +52,7 @@ impl Value128 { pub fn v128_andnot(self, rhs: Self) -> Self { simd_impl! { wasm => { Self::from_wasm_v128(wasm::v128_andnot(self.to_wasm_v128(), rhs.to_wasm_v128())) } - generic => { Self(self.0 & !rhs.0) } + generic => { (i128::from_le_bytes(self.0) & !i128::from_le_bytes(rhs.0)).into() } } } @@ -60,7 +60,7 @@ impl Value128 { pub fn v128_or(self, rhs: Self) -> Self { simd_impl! { wasm => { Self::from_wasm_v128(wasm::v128_or(self.to_wasm_v128(), rhs.to_wasm_v128())) } - generic => { Self(self.0 | rhs.0) } + generic => { (i128::from_le_bytes(self.0) | i128::from_le_bytes(rhs.0)).into() } } } @@ -68,7 +68,7 @@ impl Value128 { pub fn v128_xor(self, rhs: Self) -> Self { simd_impl! { wasm => { Self::from_wasm_v128(wasm::v128_xor(self.to_wasm_v128(), rhs.to_wasm_v128())) } - generic => { Self(self.0 ^ rhs.0) } + generic => { (i128::from_le_bytes(self.0) ^ i128::from_le_bytes(rhs.0)).into() } } } @@ -76,7 +76,7 @@ impl Value128 { pub fn v128_bitselect(v1: Self, v2: Self, c: Self) -> Self { simd_impl! { wasm => { Self::from_wasm_v128(wasm::v128_bitselect(v1.to_wasm_v128(), v2.to_wasm_v128(), c.to_wasm_v128())) } - generic => { Self((v1.0 & c.0) | (v2.0 & !c.0)) } + generic => { ((i128::from_le_bytes(v1.0) & i128::from_le_bytes(c.0)) | (i128::from_le_bytes(v2.0) & !i128::from_le_bytes(c.0))).into() } } } @@ -149,8 +149,8 @@ impl Value128 { simd_impl! { wasm => { Self::from_wasm_v128(wasm::i8x16_swizzle(self.to_wasm_v128(), s.to_wasm_v128())) } x86 => { - let a = self.to_le_bytes(); - let idx = s.to_le_bytes(); + let a = self.0; + let idx = s.0; let mut mask = [0u8; 16]; for i in 0..16 { let j = idx[i]; @@ -167,18 +167,18 @@ impl Value128 { x86::_mm_storeu_si128(out.as_mut_ptr().cast::<x86::__m128i>(), result); out }; - Self::from_le_bytes(out) + Self(out) } generic => { - let a = self.to_le_bytes(); - let idx = s.to_le_bytes(); + let a = self.0; + let idx = s.0; let mut out = [0u8; 16]; for i in 0..16 { let j = idx[i]; let lane = a[(j & 0x0f) as usize]; out[i] = if j < 16 { lane } else { 0 }; } - Self::from_le_bytes(out) + Self(out) } } } @@ -189,12 +189,12 @@ impl Value128 { } #[doc(alias = "i8x16.shuffle")] - pub fn i8x16_shuffle(a: Self, b: Self, idx: i128) -> Self { + pub fn i8x16_shuffle(a: Self, b: Self, idx: Self) -> Self { simd_impl! { x86 => { - let a_bytes = a.to_le_bytes(); - let b_bytes = b.to_le_bytes(); - let idx = idx.to_le_bytes(); + let a_bytes = a.0; + let b_bytes = b.0; + let idx = idx.0; let mut mask_a = [0u8; 16]; let mut mask_b = [0u8; 16]; for i in 0..16 { @@ -217,25 +217,25 @@ impl Value128 { x86::_mm_storeu_si128(out.as_mut_ptr().cast::<x86::__m128i>(), result); out }; - Self::from_le_bytes(out) + Self(out) } generic => { - let a_bytes = a.to_le_bytes(); - let b_bytes = b.to_le_bytes(); - let idx = idx.to_le_bytes(); + let a_bytes = a.0; + let b_bytes = b.0; + let idx = idx.0; let mut out = [0u8; 16]; for i in 0..16 { let j = idx[i] & 31; out[i] = if j < 16 { a_bytes[j as usize] } else { b_bytes[(j & 0x0f) as usize] }; } - Self::from_le_bytes(out) + Self(out) } } } #[doc(alias = "i8x16.splat")] pub fn splat_i8(src: i8) -> Self { - Self::from_le_bytes([src as u8; 16]) + Self([src as u8; 16]) } #[doc(alias = "i8x16.replace_lane")] @@ -270,50 +270,32 @@ impl Value128 { #[doc(alias = "i8x16.all_true")] pub fn i8x16_all_true(self) -> bool { - for byte in self.to_le_bytes() { - if byte == 0 { - return false; - } - } - true + self.0.iter().all(|&b| b != 0) } #[doc(alias = "i16x8.all_true")] pub fn i16x8_all_true(self) -> bool { - let bytes = self.to_le_bytes(); - for lane in bytes.chunks_exact(2) { - if u16::from_le_bytes([lane[0], lane[1]]) == 0 { - return false; - } - } - true + self.0.chunks_exact(2).map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]])).all(|x| x != 0) } #[doc(alias = "i32x4.all_true")] pub fn i32x4_all_true(self) -> bool { - let bytes = self.to_le_bytes(); - for lane in bytes.chunks_exact(4) { - if u32::from_le_bytes([lane[0], lane[1], lane[2], lane[3]]) == 0 { - return false; - } - } - true + self.0.chunks_exact(4).map(|chunk| u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])).all(|x| x != 0) } #[doc(alias = "i64x2.all_true")] pub fn i64x2_all_true(self) -> bool { - let bytes = self.to_le_bytes(); - for lane in bytes.chunks_exact(8) { - if u64::from_le_bytes([lane[0], lane[1], lane[2], lane[3], lane[4], lane[5], lane[6], lane[7]]) == 0 { - return false; - } - } - true + self.0 + .chunks_exact(8) + .map(|chunk| { + u64::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], chunk[5], chunk[6], chunk[7]]) + }) + .all(|x| x != 0) } #[doc(alias = "i8x16.bitmask")] pub fn i8x16_bitmask(self) -> u32 { - let bytes = self.to_le_bytes(); + let bytes = self.0; let mut mask = 0u32; for (i, byte) in bytes.into_iter().enumerate() { if (byte & 0x80) != 0 { @@ -325,7 +307,7 @@ impl Value128 { #[doc(alias = "i16x8.bitmask")] pub fn i16x8_bitmask(self) -> u32 { - let bytes = self.to_le_bytes(); + let bytes = self.0; let mut mask = 0u32; for (i, lane) in bytes.chunks_exact(2).enumerate() { if (lane[1] & 0x80) != 0 { @@ -337,7 +319,7 @@ impl Value128 { #[doc(alias = "i32x4.bitmask")] pub fn i32x4_bitmask(self) -> u32 { - let bytes = self.to_le_bytes(); + let bytes = self.0; let mut mask = 0u32; for (i, lane) in bytes.chunks_exact(4).enumerate() { if (lane[3] & 0x80) != 0 { @@ -349,18 +331,18 @@ impl Value128 { #[doc(alias = "i64x2.bitmask")] pub fn i64x2_bitmask(self) -> u32 { - let x = u128::from_le_bytes(self.to_le_bytes()); + let x = u128::from_le_bytes(self.0); (((x >> 63) & 1) as u32) | ((((x >> 127) & 1) as u32) << 1) } #[doc(alias = "i8x16.popcnt")] pub fn i8x16_popcnt(self) -> Self { - let lanes = self.to_le_bytes(); + let lanes = self.0; let mut out = [0u8; 16]; for (dst, lane) in out.iter_mut().zip(lanes) { *dst = lane.count_ones() as u8; } - Self::from_le_bytes(out) + Self(out) } #[doc(alias = "i8x16.shl")] @@ -1348,7 +1330,7 @@ impl Value128 { pub fn extract_lane_i8(self, lane: u8) -> i8 { debug_assert!(lane < 16); let lane = lane as usize; - let bytes = self.to_le_bytes(); + let bytes = self.0; bytes[lane] as i8 } @@ -1356,7 +1338,7 @@ impl Value128 { pub fn extract_lane_u8(self, lane: u8) -> u8 { debug_assert!(lane < 16); let lane = lane as usize; - let bytes = self.to_le_bytes(); + let bytes = self.0; bytes[lane] } diff --git a/crates/tinywasm/src/interpreter/simd/macros.rs b/crates/tinywasm/src/interpreter/simd/macros.rs index 9509594..91fdbb6 100644 --- a/crates/tinywasm/src/interpreter/simd/macros.rs +++ b/crates/tinywasm/src/interpreter/simd/macros.rs @@ -302,7 +302,7 @@ macro_rules! impl_lane_accessors { $( #[inline] $as_vis const fn $as_name(self) -> [$lane_ty; $lane_count] { - let bytes = self.to_le_bytes(); + let bytes = self.0; let mut out = [0 as $lane_ty; $lane_count]; let mut i = 0; while i < $lane_count { @@ -325,7 +325,7 @@ macro_rules! impl_lane_accessors { } i += 1; } - Self::from_le_bytes(bytes) + Self(bytes) } )* }; diff --git a/crates/tinywasm/src/interpreter/simd/mod.rs b/crates/tinywasm/src/interpreter/simd/mod.rs index 7320304..9d926f7 100644 --- a/crates/tinywasm/src/interpreter/simd/mod.rs +++ b/crates/tinywasm/src/interpreter/simd/mod.rs @@ -12,19 +12,39 @@ use core::arch::wasm32 as wasm; #[cfg(target_arch = "wasm64")] use core::arch::wasm64 as wasm; +use crate::MemValue; + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] /// A 128-bit SIMD value -pub struct Value128(pub(crate) i128); +pub struct Value128([u8; 16]); + +impl From<[u8; 16]> for Value128 { + fn from(bytes: [u8; 16]) -> Self { + Self(bytes) + } +} + +impl MemValue<16> for Value128 { + #[inline(always)] + fn from_mem_bytes(bytes: [u8; 16]) -> Self { + Self(bytes) + } + + #[inline(always)] + fn to_mem_bytes(self) -> [u8; 16] { + self.0 + } +} impl From<Value128> for i128 { fn from(val: Value128) -> Self { - val.0 + i128::from_le_bytes(val.0) } } impl From<i128> for Value128 { fn from(value: i128) -> Self { - Self(value) + Self(value.to_le_bytes()) } } @@ -33,7 +53,7 @@ impl Value128 { #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] #[inline(always)] fn to_wasm_v128(self) -> wasm::v128 { - let b = self.to_le_bytes(); + let b = self.0; wasm::u8x16( b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], ) @@ -43,17 +63,7 @@ impl Value128 { #[inline(always)] #[rustfmt::skip] fn from_wasm_v128(value: wasm::v128) -> Self { - Self::from_le_bytes([ wasm::u8x16_extract_lane::<0>(value), wasm::u8x16_extract_lane::<1>(value), wasm::u8x16_extract_lane::<2>(value), wasm::u8x16_extract_lane::<3>(value), wasm::u8x16_extract_lane::<4>(value), wasm::u8x16_extract_lane::<5>(value), wasm::u8x16_extract_lane::<6>(value), wasm::u8x16_extract_lane::<7>(value), wasm::u8x16_extract_lane::<8>(value), wasm::u8x16_extract_lane::<9>(value), wasm::u8x16_extract_lane::<10>(value), wasm::u8x16_extract_lane::<11>(value), wasm::u8x16_extract_lane::<12>(value), wasm::u8x16_extract_lane::<13>(value), wasm::u8x16_extract_lane::<14>(value), wasm::u8x16_extract_lane::<15>(value)]) - } - - #[inline(always)] - pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { - Self(i128::from_le_bytes(bytes)) - } - - #[inline(always)] - pub const fn to_le_bytes(self) -> [u8; 16] { - self.0.to_le_bytes() + Self([ wasm::u8x16_extract_lane::<0>(value), wasm::u8x16_extract_lane::<1>(value), wasm::u8x16_extract_lane::<2>(value), wasm::u8x16_extract_lane::<3>(value), wasm::u8x16_extract_lane::<4>(value), wasm::u8x16_extract_lane::<5>(value), wasm::u8x16_extract_lane::<6>(value), wasm::u8x16_extract_lane::<7>(value), wasm::u8x16_extract_lane::<8>(value), wasm::u8x16_extract_lane::<9>(value), wasm::u8x16_extract_lane::<10>(value), wasm::u8x16_extract_lane::<11>(value), wasm::u8x16_extract_lane::<12>(value), wasm::u8x16_extract_lane::<13>(value), wasm::u8x16_extract_lane::<14>(value), wasm::u8x16_extract_lane::<15>(value)]) } impl_lane_accessors! { @@ -71,19 +81,19 @@ impl Value128 { #[inline] fn map_f32x4(self, mut op: impl FnMut(f32) -> f32) -> Self { - let bytes = self.to_le_bytes(); + let bytes = self.0; let mut out_bytes = [0u8; 16]; for (src, dst) in bytes.chunks_exact(4).zip(out_bytes.chunks_exact_mut(4)) { let lane = f32::from_bits(u32::from_le_bytes([src[0], src[1], src[2], src[3]])); dst.copy_from_slice(&op(lane).to_bits().to_le_bytes()); } - Self::from_le_bytes(out_bytes) + Self(out_bytes) } #[inline] fn zip_f32x4(self, rhs: Self, mut op: impl FnMut(f32, f32) -> f32) -> Self { - let a_bytes = self.to_le_bytes(); - let b_bytes = rhs.to_le_bytes(); + let a_bytes = self.0; + let b_bytes = rhs.0; let mut out_bytes = [0u8; 16]; for ((a, b), dst) in a_bytes.chunks_exact(4).zip(b_bytes.chunks_exact(4)).zip(out_bytes.chunks_exact_mut(4)) { @@ -92,25 +102,25 @@ impl Value128 { dst.copy_from_slice(&op(a_lane, b_lane).to_bits().to_le_bytes()); } - Self::from_le_bytes(out_bytes) + Self(out_bytes) } #[inline] fn map_f64x2(self, mut op: impl FnMut(f64) -> f64) -> Self { - let bytes = self.to_le_bytes(); + let bytes = self.0; let mut out_bytes = [0u8; 16]; for (src, dst) in bytes.chunks_exact(8).zip(out_bytes.chunks_exact_mut(8)) { let lane = f64::from_bits(u64::from_le_bytes([src[0], src[1], src[2], src[3], src[4], src[5], src[6], src[7]])); dst.copy_from_slice(&op(lane).to_bits().to_le_bytes()); } - Self::from_le_bytes(out_bytes) + Self(out_bytes) } #[inline] fn zip_f64x2(self, rhs: Self, mut op: impl FnMut(f64, f64) -> f64) -> Self { - let a_bytes = self.to_le_bytes(); - let b_bytes = rhs.to_le_bytes(); + let a_bytes = self.0; + let b_bytes = rhs.0; let mut out_bytes = [0u8; 16]; for ((a, b), dst) in a_bytes.chunks_exact(8).zip(b_bytes.chunks_exact(8)).zip(out_bytes.chunks_exact_mut(8)) { @@ -119,6 +129,6 @@ impl Value128 { dst.copy_from_slice(&op(a_lane, b_lane).to_bits().to_le_bytes()); } - Self::from_le_bytes(out_bytes) + Self(out_bytes) } } diff --git a/crates/tinywasm/src/interpreter/simd/tests.rs b/crates/tinywasm/src/interpreter/simd/tests.rs index 70ceac6..ca69942 100644 --- a/crates/tinywasm/src/interpreter/simd/tests.rs +++ b/crates/tinywasm/src/interpreter/simd/tests.rs @@ -32,8 +32,8 @@ fn swizzle_matches_reference() { *byte = (x & 0xff) as u8; } - let got = Value128::from_le_bytes(a).i8x16_swizzle(Value128::from_le_bytes(s)).to_le_bytes(); - let expected = ref_swizzle(a, s); + let got = Value128::from(a).i8x16_swizzle(Value128::from(s)); + let expected = ref_swizzle(a, s).into(); assert_eq!(got, expected, "seed={seed}"); } } @@ -53,10 +53,8 @@ fn shuffle_matches_reference() { *byte = (x & 0xff) as u8; } - let got = - Value128::i8x16_shuffle(Value128::from_le_bytes(a), Value128::from_le_bytes(b), i128::from_le_bytes(idx)) - .to_le_bytes(); - let expected = ref_shuffle(a, b, idx); + let got = Value128::i8x16_shuffle(Value128::from(a), Value128::from(b), Value128::from(idx)); + let expected = ref_shuffle(a, b, idx).into(); assert_eq!(got, expected, "seed={seed}"); } } diff --git a/crates/tinywasm/src/interpreter/simd/utils.rs b/crates/tinywasm/src/interpreter/simd/utils.rs index 7f79871..6feabe1 100644 --- a/crates/tinywasm/src/interpreter/simd/utils.rs +++ b/crates/tinywasm/src/interpreter/simd/utils.rs @@ -6,7 +6,7 @@ use crate::interpreter::no_std_floats::NoStdFloatExt; impl Value128 { pub(super) fn extract_lane_bytes<const LANE_BYTES: usize>(self, lane: u8, lane_count: u8) -> [u8; LANE_BYTES] { debug_assert!(lane < lane_count); - let bytes = self.to_le_bytes(); + let bytes = self.0; let start = lane as usize * LANE_BYTES; let mut out = [0u8; LANE_BYTES]; out.copy_from_slice(&bytes[start..start + LANE_BYTES]); @@ -20,10 +20,10 @@ impl Value128 { lane_count: u8, ) -> Self { debug_assert!(lane < lane_count); - let mut bytes = self.to_le_bytes(); + let mut bytes = self.0; let start = lane as usize * LANE_BYTES; bytes[start..start + LANE_BYTES].copy_from_slice(&value); - Self::from_le_bytes(bytes) + Self(bytes) } } diff --git a/crates/tinywasm/src/interpreter/stack/mod.rs b/crates/tinywasm/src/interpreter/stack/mod.rs index bb18fd3..cc77c52 100644 --- a/crates/tinywasm/src/interpreter/stack/mod.rs +++ b/crates/tinywasm/src/interpreter/stack/mod.rs @@ -3,23 +3,3 @@ mod value_stack; pub(crate) use call_stack::{CallFrame, CallStack, StackBase}; pub(crate) use value_stack::ValueStack; - -use crate::engine::Config; - -/// A WebAssembly Stack -#[cfg_attr(feature = "debug", derive(Debug))] -pub(crate) struct Stack { - pub(crate) values: ValueStack, - pub(crate) call_stack: CallStack, -} - -impl Stack { - pub(crate) fn new(config: &Config) -> Self { - Self { values: ValueStack::new(config), call_stack: CallStack::new(config) } - } - - pub(crate) fn clear(&mut self) { - self.values.clear(); - self.call_stack.clear(); - } -} diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index f59f3b6..335bef6 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -1,7 +1,5 @@ -use core::hint::cold_path; - -use alloc::boxed::Box; use alloc::vec::Vec; +use core::hint::cold_path; use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValueCounts, WasmType, WasmValue}; use super::{CallFrame, StackBase}; @@ -16,37 +14,37 @@ pub(crate) struct ValueStack { #[cfg_attr(feature = "debug", derive(Debug))] pub(crate) struct Stack<T: Copy + Default> { - data: Box<[T]>, - len: usize, + data: Vec<T>, } impl<T: Copy + Default> Stack<T> { pub(crate) fn new(size: usize) -> Self { - let mut data = Vec::with_capacity(size); - data.resize_with(size, T::default); - Self { data: data.into_boxed_slice(), len: 0 } + Self { data: Vec::with_capacity(size) } } pub(crate) fn clear(&mut self) { - self.len = 0; + self.data.clear(); + } + + #[inline(always)] + pub(crate) fn len(&self) -> usize { + self.data.len() } #[inline(always)] pub(crate) fn push(&mut self, value: T) -> Result<()> { - if let Some(slot) = self.data.get_mut(self.len) { - *slot = value; - self.len += 1; - } else { + if self.data.len() == self.data.capacity() { cold_path(); return Err(Trap::ValueStackOverflow.into()); } + + self.data.push(value); Ok(()) } #[inline(always)] pub(crate) fn pop(&mut self) -> T { - self.len -= 1; - *self.data.get(self.len).unwrap_or_else(|| { + self.data.pop().unwrap_or_else(|| { cold_path(); unreachable!("ValueStack underflow, this is a bug"); }) @@ -54,7 +52,7 @@ impl<T: Copy + Default> Stack<T> { #[inline(always)] pub(crate) fn last(&self) -> &T { - self.data.get(self.len - 1).unwrap_or_else(|| { + self.data.last().unwrap_or_else(|| { cold_path(); unreachable!("ValueStack underflow, this is a bug"); }) @@ -86,42 +84,31 @@ impl<T: Copy + Default> Stack<T> { #[inline(always)] pub(crate) fn truncate_keep(&mut self, n: usize, end_keep: usize) { - let len = self.len; + let len = self.data.len(); debug_assert!(n <= len); - if n >= len { return; } - let dropped = len - n; - let keep = dropped.min(end_keep); - + let keep = (len - n).min(end_keep); if keep > 0 { self.data.copy_within(len - keep..len, n); } - - self.len = n + keep; + self.data.truncate(n + keep); } #[inline(always)] pub(crate) fn enter_locals(&mut self, param_count: usize, local_count: usize) -> Result<u32> { - let len = self.len; - debug_assert!(param_count <= local_count); - debug_assert!(param_count <= len); + debug_assert!(param_count <= local_count && param_count <= self.data.len()); - let start = len - param_count; + let start = self.data.len() - param_count; let end = start + local_count; - - if end > self.data.len() { + if end > self.data.capacity() { cold_path(); return Err(Trap::ValueStackOverflow.into()); } - if len != end { - self.data[len..end].fill(T::default()); - } - - self.len = end; + self.data.resize(end, T::default()); Ok(start as u32) } @@ -131,7 +118,7 @@ impl<T: Copy + Default> Stack<T> { return; } - let len = self.len; + let len = self.data.len(); let needed = count.checked_mul(2).unwrap_or_else(|| { cold_path(); unreachable!("Stack underflow, this is a bug"); @@ -148,10 +135,9 @@ impl<T: Copy + Default> Stack<T> { self.data.copy_within(src..len, dst); } - self.len = len - count; + self.data.truncate(len - count); } } - impl ValueStack { pub(crate) fn new(config: &Config) -> Self { Self { @@ -169,7 +155,7 @@ impl ValueStack { #[inline(always)] pub(crate) fn len(&self) -> usize { - self.stack_32.len + self.stack_64.len + self.stack_128.len + self.stack_32.len() + self.stack_64.len() + self.stack_128.len() } #[inline(always)] @@ -219,32 +205,13 @@ impl ValueStack { } pub(crate) fn enter_locals(&mut self, params: &ValueCounts, locals: &ValueCounts) -> Result<StackBase> { - let locals_base32 = if params.c32 == 0 && locals.c32 == 0 { - self.stack_32.len as u32 - } else { - self.stack_32.enter_locals(params.c32 as usize, locals.c32 as usize)? - }; - let locals_base64 = if params.c64 == 0 && locals.c64 == 0 { - self.stack_64.len as u32 - } else { - self.stack_64.enter_locals(params.c64 as usize, locals.c64 as usize)? - }; - let locals_base128 = if params.c128 == 0 && locals.c128 == 0 { - self.stack_128.len as u32 - } else { - self.stack_128.enter_locals(params.c128 as usize, locals.c128 as usize)? - }; + let locals_base32 = self.stack_32.enter_locals(params.c32 as usize, locals.c32 as usize)?; + let locals_base64 = self.stack_64.enter_locals(params.c64 as usize, locals.c64 as usize)?; + let locals_base128 = self.stack_128.enter_locals(params.c128 as usize, locals.c128 as usize)?; Ok(StackBase { s32: locals_base32, s64: locals_base64, s128: locals_base128 }) } pub(crate) fn truncate_keep_counts(&mut self, base: StackBase, keep: ValueCounts) { - if keep.is_empty() { - self.stack_32.len = base.s32 as usize; - self.stack_64.len = base.s64 as usize; - self.stack_128.len = base.s128 as usize; - return; - } - self.stack_32.truncate_keep(base.s32 as usize, keep.c32 as usize); self.stack_64.truncate_keep(base.s64 as usize, keep.c64 as usize); self.stack_128.truncate_keep(base.s128 as usize, keep.c128 as usize); @@ -260,7 +227,7 @@ impl ValueStack { &mut self, frame: &CallFrame, index: LocalAddr, - func: impl FnOnce(&mut T), + func: impl FnOnce(T) -> T, ) { T::local_update(self, frame, index, func) } diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index eae0c53..3d58879 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -148,7 +148,7 @@ mod sealed { pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> + Copy + Default { fn stack_push(stack: &mut ValueStack, value: Self) -> Result<()>; fn local_get(stack: &ValueStack, frame: &CallFrame, index: LocalAddr) -> Self; - fn local_update(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, func: impl FnOnce(&mut Self)); + fn local_update(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, func: impl FnOnce(Self) -> Self); fn local_set(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, value: Self); fn stack_pop(stack: &mut ValueStack) -> Self; fn stack_peek(stack: &ValueStack) -> Self; @@ -177,11 +177,9 @@ macro_rules! impl_internalvalue { } #[inline(always)] - fn local_update(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, func: impl FnOnce(&mut Self)) { + fn local_update(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, func: impl FnOnce(Self) -> Self) { let slot = stack.$stack.get_mut(frame.locals_base.$stack_base as usize + index as usize); - let mut value = $from_stack(*slot); - func(&mut value); - *slot = $to_stack(value); + *slot = $to_stack(func($from_stack(*slot))); } #[inline(always)] @@ -206,8 +204,8 @@ macro_rules! impl_internalvalue { impl_internalvalue! { Value32, stack_32, s32, u32, |v| v, |v| v, |v| v Value64, stack_64, s64, u64, |v| v, |v| v, |v| v - Value32, stack_32, s32, i32, |v: i32| u32::from_ne_bytes(v.to_ne_bytes()), |v: i32| u32::from_ne_bytes(v.to_ne_bytes()), |v: u32| i32::from_ne_bytes(v.to_ne_bytes()) - Value64, stack_64, s64, i64, |v: i64| u64::from_ne_bytes(v.to_ne_bytes()), |v: i64| u64::from_ne_bytes(v.to_ne_bytes()), |v: u64| i64::from_ne_bytes(v.to_ne_bytes()) + Value32, stack_32, s32, i32, |v: i32| v as u32, |v: i32| v as u32, |v: u32| v as i32 + Value64, stack_64, s64, i64, |v: i64| v as u64, |v: i64| v as u64, |v: u64| v as i64 Value32, stack_32, s32, f32, f32::to_bits, f32::to_bits, f32::from_bits Value64, stack_64, s64, f64, f64::to_bits, f64::to_bits, f64::from_bits ValueRef, stack_32, s32, ValueRef, |v| v, |v: ValueRef| v.raw(), |v: u32| ValueRef(v) diff --git a/crates/tinywasm/src/reference.rs b/crates/tinywasm/src/reference.rs index e5719c6..e1d3d48 100644 --- a/crates/tinywasm/src/reference.rs +++ b/crates/tinywasm/src/reference.rs @@ -117,8 +117,8 @@ impl Memory { } /// Store a slice of memory. - pub fn store(&self, store: &mut Store, offset: usize, len: usize, data: &[u8]) -> Result<()> { - self.instance_mut(store)?.store(offset, len, data) + pub fn store(&self, store: &mut Store, offset: usize, data: &[u8]) -> Result<()> { + self.instance_mut(store)?.store(offset, data) } /// Load a C-style string from memory. diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs index a5b18d4..64754e6 100644 --- a/crates/tinywasm/src/store/memory.rs +++ b/crates/tinywasm/src/store/memory.rs @@ -1,11 +1,10 @@ use core::hint::cold_path; +use crate::{Error, Result, log}; use alloc::vec; use alloc::vec::Vec; use tinywasm_types::{MemoryArch, MemoryType}; -use crate::{Error, Result, interpreter::Value128, log}; - /// A WebAssembly Memory Instance /// /// See <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances> @@ -36,8 +35,8 @@ impl MemoryInstance { Error::Trap(crate::Trap::MemoryOutOfBounds { offset: addr, len, max: self.data.len() }) } - pub(crate) fn store(&mut self, addr: usize, len: usize, data: &[u8]) -> Result<()> { - let Some(end) = addr.checked_add(len) else { + pub(crate) fn store(&mut self, addr: usize, data: &[u8]) -> Result<()> { + let Some(end) = addr.checked_add(data.len()) else { return Err(self.trap_oob(addr, data.len())); }; @@ -114,6 +113,7 @@ impl MemoryInstance { pub(crate) fn grow(&mut self, pages_delta: i64) -> Option<i64> { if pages_delta < 0 { + cold_path(); log::debug!("memory.grow failed: negative delta {}", pages_delta); return None; } @@ -124,12 +124,14 @@ impl MemoryInstance { let max_pages = self.kind.page_count_max().try_into().unwrap_or(usize::MAX); if new_pages > max_pages { + cold_path(); log::debug!("memory.grow failed: new_pages={}, max_pages={}", new_pages, max_pages); return None; } let new_size = (new_pages as u64).checked_mul(self.kind.page_size())?; if new_size > self.kind.max_size() { + cold_path(); log::debug!("memory.grow failed: new_size={}, max_size={}", new_size, self.kind.max_size()); return None; } @@ -139,8 +141,8 @@ impl MemoryInstance { return i64::try_from(current_pages).ok(); } - self.data.resize(new_size, 0); self.page_count = new_pages; + self.data.resize(new_size, 0); i64::try_from(current_pages).ok() } } @@ -172,7 +174,7 @@ macro_rules! impl_mem_traits { } } -impl_mem_traits!(u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, Value128, 16); +impl_mem_traits!(u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8); #[cfg(test)] mod memory_instance_tests { @@ -188,7 +190,7 @@ mod memory_instance_tests { fn test_memory_store_and_load() { let mut memory = create_test_memory(); let data_to_store = [1, 2, 3, 4]; - assert!(memory.store(0, data_to_store.len(), &data_to_store).is_ok()); + assert!(memory.store(0, &data_to_store).is_ok()); let loaded_data = memory.load(0, data_to_store.len()).unwrap(); assert_eq!(loaded_data, &data_to_store); } @@ -197,7 +199,7 @@ mod memory_instance_tests { fn test_memory_store_out_of_bounds() { let mut memory = create_test_memory(); let data_to_store = [1, 2, 3, 4]; - assert!(memory.store(memory.data.len(), data_to_store.len(), &data_to_store).is_err()); + assert!(memory.store(memory.data.len(), &data_to_store).is_err()); } #[test] @@ -263,7 +265,7 @@ mod memory_instance_tests { let mut memory = MemoryInstance::new(kind); let data_to_store = [1, 2]; - assert!(memory.store(0, data_to_store.len(), &data_to_store).is_err()); + assert!(memory.store(0, &data_to_store).is_err()); } #[test] @@ -274,7 +276,7 @@ mod memory_instance_tests { assert_eq!(memory.grow(1), Some(1)); let data_to_store = [1, 2]; - assert!(memory.store(0, data_to_store.len(), &data_to_store).is_ok()); + assert!(memory.store(0, &data_to_store).is_ok()); let loaded_data = memory.load(0, data_to_store.len()).unwrap(); assert_eq!(loaded_data, &data_to_store); diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 57601a4..e76673f 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use tinywasm_types::*; use crate::instance::ModuleInstanceInner; -use crate::interpreter::stack::Stack; +use crate::interpreter::stack::{CallStack, ValueStack}; use crate::interpreter::{TinyWasmValue, ValueRef}; use crate::{Engine, Error, ModuleInstance, Result, Trap}; @@ -36,7 +36,8 @@ pub struct Store { pub(crate) engine: Engine, pub(crate) execution_fuel: u32, pub(crate) state: State, - pub(crate) stack: Stack, + pub(crate) call_stack: CallStack, + pub(crate) value_stack: ValueStack, } #[cfg(feature = "debug")] @@ -45,7 +46,6 @@ impl core::fmt::Debug for Store { f.debug_struct("Store") .field("id", &self.id) .field("module_instances", &self.module_instances) - .field("data", &"...") .field("engine", &self.engine) .finish() } @@ -59,7 +59,8 @@ impl Store { id, module_instances: Vec::new(), state: State::default(), - stack: Stack::new(engine.config()), + call_stack: CallStack::new(engine.config()), + value_stack: ValueStack::new(engine.config()), engine, execution_fuel: 0, } @@ -406,7 +407,7 @@ impl Store { return Err(Error::Other(format!("memory {mem_addr} not found for data segment {i}"))); }; - match mem.store(offset as usize, data.data.len(), &data.data) { + match mem.store(offset as usize, &data.data) { Ok(()) => None, Err(Error::Trap(trap)) => return Ok((data_addrs.into_boxed_slice(), Some(trap))), Err(e) => return Err(e), diff --git a/crates/tinywasm/tests/internal_refs.rs b/crates/tinywasm/tests/internal_refs.rs index 98dc702..dd4179a 100644 --- a/crates/tinywasm/tests/internal_refs.rs +++ b/crates/tinywasm/tests/internal_refs.rs @@ -25,7 +25,7 @@ fn private_items_are_accessible_by_index() -> Result<()> { let func = instance.func_by_index(&store, 0)?; assert_eq!(func.call(&mut store, &[])?, vec![WasmValue::I32(7)]); - instance.memory_by_index(0)?.store(&mut store, 0, 4, &[1, 2, 3, 4])?; + instance.memory_by_index(0)?.store(&mut store, 0, &[1, 2, 3, 4])?; assert_eq!(instance.memory_by_index(0)?.load(&store, 0, 4)?, &[1, 2, 3, 4]); assert_eq!(instance.table_by_index(0)?.size(&store)?, 2); diff --git a/crates/tinywasm/tests/memory_ref_api.rs b/crates/tinywasm/tests/memory_ref_api.rs index dd2d01e..21c8c90 100644 --- a/crates/tinywasm/tests/memory_ref_api.rs +++ b/crates/tinywasm/tests/memory_ref_api.rs @@ -16,7 +16,7 @@ fn memory_ref_mut_copy_within_uses_src_then_dst_order() -> Result<()> { let instance = module.instantiate(&mut store, None)?; let memory = instance.memory("memory")?; - memory.store(&mut store, 0, 4, &[1, 2, 3, 4])?; + memory.store(&mut store, 0, &[1, 2, 3, 4])?; memory.copy_within(&mut store, 0, 4, 4)?; assert_eq!(memory.load(&store, 0, 8)?, &[1, 2, 3, 4, 1, 2, 3, 4]); diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 28d52a7..30cae5d 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -321,7 +321,7 @@ impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for ArcSlice<T> { #[cfg_attr(feature = "debug", derive(Debug))] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct WasmFunctionData { - pub v128_constants: Box<[i128]>, + pub v128_constants: Box<[[u8; 16]]>, pub branch_table_targets: Box<[u32]>, } diff --git a/examples/wasm-rust.rs b/examples/wasm-rust.rs index 4386531..2d2b91a 100644 --- a/examples/wasm-rust.rs +++ b/examples/wasm-rust.rs @@ -119,7 +119,7 @@ fn hello() -> Result<()> { let arg_ptr = instance.func::<(), i32>(&store, "arg_ptr")?.call(&mut store, ())?; let arg = b"world"; - instance.memory("memory")?.store(&mut store, arg_ptr as usize, arg.len(), arg)?; + instance.memory("memory")?.store(&mut store, arg_ptr as usize, arg)?; let hello = instance.func::<i32, ()>(&store, "hello")?; hello.call(&mut store, arg.len() as i32)?; |
