summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/visit.rs6
-rw-r--r--crates/tinywasm/src/func.rs29
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs397
-rw-r--r--crates/tinywasm/src/interpreter/num_helpers.rs4
-rw-r--r--crates/tinywasm/src/interpreter/simd/instructions.rs98
-rw-r--r--crates/tinywasm/src/interpreter/simd/macros.rs4
-rw-r--r--crates/tinywasm/src/interpreter/simd/mod.rs60
-rw-r--r--crates/tinywasm/src/interpreter/simd/tests.rs10
-rw-r--r--crates/tinywasm/src/interpreter/simd/utils.rs6
-rw-r--r--crates/tinywasm/src/interpreter/stack/mod.rs20
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs89
-rw-r--r--crates/tinywasm/src/interpreter/values.rs12
-rw-r--r--crates/tinywasm/src/reference.rs4
-rw-r--r--crates/tinywasm/src/store/memory.rs22
-rw-r--r--crates/tinywasm/src/store/mod.rs11
-rw-r--r--crates/tinywasm/tests/internal_refs.rs2
-rw-r--r--crates/tinywasm/tests/memory_ref_api.rs2
-rw-r--r--crates/types/src/lib.rs2
18 files changed, 341 insertions, 437 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 }, &params)?;
- 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(&params, &locals);
+ let res = self.store.value_stack.enter_locals(&params, &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]>,
}