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