summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHenry <mail@henrygressmann.de>2026-07-14 16:15:32 +0200
committerHenry <mail@henrygressmann.de>2026-07-14 16:15:32 +0200
commit089f5dd1dd73701b83181011f6268f5c1bcbbb6b (patch)
tree32f3c1907c12ae373605827c0f56463c986ffe52 /crates
parent6e28708ca6b78419117d27bbae916ac44b90d306 (diff)
chore: specialize local copy, use closures to improve traces
Signed-off-by: Henry <mail@henrygressmann.de>
Diffstat (limited to 'crates')
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs366
-rw-r--r--crates/tinywasm/src/interpreter/stack/call_stack.rs2
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs12
-rw-r--r--crates/tinywasm/src/interpreter/values.rs4
4 files changed, 221 insertions, 163 deletions
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index f0d995d..37b2f43 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -50,177 +50,217 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
}
#[inline(always)]
- fn exec_binop_32(&self, op: BinOp, lhs: Value32, rhs: Value32) -> Value32 {
- match op {
- BinOp::IAdd => ((lhs as i32).wrapping_add(rhs as i32)) as u32,
- BinOp::ISub => ((lhs as i32).wrapping_sub(rhs as i32)) as u32,
- BinOp::IMul => ((lhs as i32).wrapping_mul(rhs as i32)) as u32,
- BinOp::IAnd => lhs & rhs,
- BinOp::IOr => lhs | rhs,
- BinOp::IXor => lhs ^ rhs,
- BinOp::IShl => ((lhs as i32).wasm_shl(rhs as i32)) as u32,
- BinOp::IShrS => ((lhs as i32).wasm_shr(rhs as i32)) as u32,
- BinOp::IShrU => lhs.wasm_shr(rhs),
- BinOp::IRotl => ((lhs as i32).wasm_rotl(rhs as i32)) as u32,
- BinOp::IRotr => ((lhs as i32).wasm_rotr(rhs as i32)) as u32,
- BinOp::FAdd => (f32::from_bits(lhs) + f32::from_bits(rhs)).to_bits(),
- BinOp::FSub => (f32::from_bits(lhs) - f32::from_bits(rhs)).to_bits(),
- BinOp::FMul => (f32::from_bits(lhs) * f32::from_bits(rhs)).to_bits(),
- BinOp::FDiv => (f32::from_bits(lhs) / f32::from_bits(rhs)).to_bits(),
- BinOp::FMin => f32::from_bits(lhs).tw_minimum(f32::from_bits(rhs)).to_bits(),
- BinOp::FMax => f32::from_bits(lhs).tw_maximum(f32::from_bits(rhs)).to_bits(),
- BinOp::FCopysign => f32::from_bits(lhs).copysign(f32::from_bits(rhs)).to_bits(),
- }
- }
-
- #[inline(always)]
- fn exec_binop_64(&self, op: BinOp, lhs: Value64, rhs: Value64) -> Value64 {
- match op {
- BinOp::IAdd => ((lhs as i64).wrapping_add(rhs as i64)) as u64,
- BinOp::ISub => ((lhs as i64).wrapping_sub(rhs as i64)) as u64,
- BinOp::IMul => ((lhs as i64).wrapping_mul(rhs as i64)) as u64,
- BinOp::IAnd => lhs & rhs,
- BinOp::IOr => lhs | rhs,
- BinOp::IXor => lhs ^ rhs,
- BinOp::IShl => ((lhs as i64).wasm_shl(rhs as i64)) as u64,
- BinOp::IShrS => ((lhs as i64).wasm_shr(rhs as i64)) as u64,
- BinOp::IShrU => lhs.wasm_shr(rhs),
- BinOp::IRotl => ((lhs as i64).wasm_rotl(rhs as i64)) as u64,
- BinOp::IRotr => ((lhs as i64).wasm_rotr(rhs as i64)) as u64,
- BinOp::FAdd => (f64::from_bits(lhs) + f64::from_bits(rhs)).to_bits(),
- BinOp::FSub => (f64::from_bits(lhs) - f64::from_bits(rhs)).to_bits(),
- BinOp::FMul => (f64::from_bits(lhs) * f64::from_bits(rhs)).to_bits(),
- BinOp::FDiv => (f64::from_bits(lhs) / f64::from_bits(rhs)).to_bits(),
- BinOp::FMin => f64::from_bits(lhs).tw_minimum(f64::from_bits(rhs)).to_bits(),
- BinOp::FMax => f64::from_bits(lhs).tw_maximum(f64::from_bits(rhs)).to_bits(),
- BinOp::FCopysign => f64::from_bits(lhs).copysign(f64::from_bits(rhs)).to_bits(),
- }
- }
-
- #[inline(always)]
- fn exec_binop_128(&self, op: BinOp128, lhs: Value128, rhs: Value128) -> Value128 {
- match op {
- BinOp128::And => lhs.v128_and(rhs),
- BinOp128::AndNot => lhs.v128_andnot(rhs),
- BinOp128::Or => lhs.v128_or(rhs),
- BinOp128::Xor => lhs.v128_xor(rhs),
- BinOp128::I64x2Add => lhs.i64x2_add(rhs),
- BinOp128::I64x2Mul => lhs.i64x2_mul(rhs),
- }
- }
-
- #[inline(always)]
fn exec(&mut self) -> Result<Option<()>, Trap> {
macro_rules! stack_op {
(unary $ty:ty, |$v:ident| $expr:expr) => {{
- let $v = <$ty>::stack_pop(&mut self.store.value_stack);
- <$ty>::stack_push(&mut self.store.value_stack, $expr)?;
+ (|| -> Result<(), Trap> {
+ let $v = <$ty>::stack_pop(&mut self.store.value_stack);
+ <$ty>::stack_push(&mut self.store.value_stack, $expr)?;
+ Ok(())
+ })()?;
}};
(binary $ty:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{
- let $rhs = <$ty>::stack_pop(&mut self.store.value_stack);
- let $lhs = <$ty>::stack_pop(&mut self.store.value_stack);
- <$ty>::stack_push(&mut self.store.value_stack, $expr)?;
+ (|| -> Result<(), Trap> {
+ let $rhs = <$ty>::stack_pop(&mut self.store.value_stack);
+ let $lhs = <$ty>::stack_pop(&mut self.store.value_stack);
+ <$ty>::stack_push(&mut self.store.value_stack, $expr)?;
+ Ok(())
+ })()?;
}};
(binary try $ty:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{
- let $rhs = <$ty>::stack_pop(&mut self.store.value_stack);
- let $lhs = <$ty>::stack_pop(&mut self.store.value_stack);
- <$ty>::stack_push(&mut self.store.value_stack, $expr?)?;
+ (|| -> Result<(), Trap> {
+ let $rhs = <$ty>::stack_pop(&mut self.store.value_stack);
+ let $lhs = <$ty>::stack_pop(&mut self.store.value_stack);
+ <$ty>::stack_push(&mut self.store.value_stack, $expr?)?;
+ Ok(())
+ })()?;
}};
(unary $from:ty => $to:ty, |$v:ident| $expr:expr) => {{
- let $v = <$from>::stack_pop(&mut self.store.value_stack);
- <$to>::stack_push(&mut self.store.value_stack, $expr)?;
+ (|| -> Result<(), Trap> {
+ let $v = <$from>::stack_pop(&mut self.store.value_stack);
+ <$to>::stack_push(&mut self.store.value_stack, $expr)?;
+ Ok(())
+ })()?;
}};
(binary $from:ty => $to:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{
- let $rhs = <$from>::stack_pop(&mut self.store.value_stack);
- let $lhs = <$from>::stack_pop(&mut self.store.value_stack);
- <$to>::stack_push(&mut self.store.value_stack, $expr)?;
+ (|| -> Result<(), Trap> {
+ let $rhs = <$from>::stack_pop(&mut self.store.value_stack);
+ let $lhs = <$from>::stack_pop(&mut self.store.value_stack);
+ <$to>::stack_push(&mut self.store.value_stack, $expr)?;
+ Ok(())
+ })()?;
}};
(binary_into2 $from:ty => $to:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {{
- let $rhs = <$from>::stack_pop(&mut self.store.value_stack);
- let $lhs = <$from>::stack_pop(&mut self.store.value_stack);
- let out = $expr;
- <$to>::stack_push(&mut self.store.value_stack, out.0)?;
- <$to>::stack_push(&mut self.store.value_stack, out.1)?;
+ (|| -> Result<(), Trap> {
+ let $rhs = <$from>::stack_pop(&mut self.store.value_stack);
+ let $lhs = <$from>::stack_pop(&mut self.store.value_stack);
+ let out = $expr;
+ <$to>::stack_push(&mut self.store.value_stack, out.0)?;
+ <$to>::stack_push(&mut self.store.value_stack, out.1)?;
+ Ok(())
+ })()?;
}};
(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 = <$rhs_ty>::stack_pop(&mut self.store.value_stack);
- let $lhs = <$lhs_ty>::stack_pop(&mut self.store.value_stack);
- <$res>::stack_push(&mut self.store.value_stack, $expr)?;
+ (|| -> Result<(), Trap> {
+ let $rhs = <$rhs_ty>::stack_pop(&mut self.store.value_stack);
+ let $lhs = <$lhs_ty>::stack_pop(&mut self.store.value_stack);
+ <$res>::stack_push(&mut self.store.value_stack, $expr)?;
+ Ok(())
+ })()?;
}};
(ternary $ty:ty, |$a:ident, $b:ident, $c:ident| $expr:expr) => {{
- let $c = <$ty>::stack_pop(&mut self.store.value_stack);
- let $b = <$ty>::stack_pop(&mut self.store.value_stack);
- let $a = <$ty>::stack_pop(&mut self.store.value_stack);
- <$ty>::stack_push(&mut self.store.value_stack, $expr)?;
+ (|| -> Result<(), Trap> {
+ let $c = <$ty>::stack_pop(&mut self.store.value_stack);
+ let $b = <$ty>::stack_pop(&mut self.store.value_stack);
+ let $a = <$ty>::stack_pop(&mut self.store.value_stack);
+ <$ty>::stack_push(&mut self.store.value_stack, $expr)?;
+ Ok(())
+ })()?;
}};
(quaternary_into2 $from:ty => $to:ty, |$a:ident, $b:ident, $c:ident, $d:ident| $expr:expr) => {{
- let $d = <$from>::stack_pop(&mut self.store.value_stack);
- let $c = <$from>::stack_pop(&mut self.store.value_stack);
- let $b = <$from>::stack_pop(&mut self.store.value_stack);
- let $a = <$from>::stack_pop(&mut self.store.value_stack);
- let out = $expr;
- <$to>::stack_push(&mut self.store.value_stack, out.0)?;
- <$to>::stack_push(&mut self.store.value_stack, out.1)?;
+ (|| -> Result<(), Trap> {
+ let $d = <$from>::stack_pop(&mut self.store.value_stack);
+ let $c = <$from>::stack_pop(&mut self.store.value_stack);
+ let $b = <$from>::stack_pop(&mut self.store.value_stack);
+ let $a = <$from>::stack_pop(&mut self.store.value_stack);
+ let out = $expr;
+ <$to>::stack_push(&mut self.store.value_stack, out.0)?;
+ <$to>::stack_push(&mut self.store.value_stack, out.1)?;
+ Ok(())
+ })()?;
}};
(local_set_pop $ty:ty, $local_index:expr) => {{
- let val = <$ty>::stack_pop(&mut self.store.value_stack);
- <$ty>::local_set(&mut self.store.value_stack, &self.cf, *$local_index, val);
+ (|| {
+ let val = <$ty>::stack_pop(&mut self.store.value_stack);
+ <$ty>::local_set(&mut self.store.value_stack, &self.cf, *$local_index, val);
+ })();
}};
(local_tee $ty:ty, $local_index:expr) => {{
- let val = <$ty>::stack_peek(&self.store.value_stack);
- <$ty>::local_set(&mut self.store.value_stack, &self.cf, *$local_index, val);
+ (|| {
+ let val = <$ty>::stack_peek(&self.store.value_stack);
+ <$ty>::local_set(&mut self.store.value_stack, &self.cf, *$local_index, val);
+ })();
+ }};
+ }
+
+ macro_rules! exec_binop {
+ (32, $op:expr, $lhs:expr, $rhs:expr) => {{
+ match $op {
+ BinOp::IAdd => $lhs.wrapping_add($rhs),
+ BinOp::ISub => $lhs.wrapping_sub($rhs),
+ BinOp::IMul => $lhs.wrapping_mul($rhs),
+ BinOp::IAnd => $lhs & $rhs,
+ BinOp::IOr => $lhs | $rhs,
+ BinOp::IXor => $lhs ^ $rhs,
+ BinOp::IShl => (($lhs as i32).wasm_shl($rhs as i32)) as u32,
+ BinOp::IShrS => (($lhs as i32).wasm_shr($rhs as i32)) as u32,
+ BinOp::IShrU => $lhs.wasm_shr($rhs),
+ BinOp::IRotl => (($lhs as i32).wasm_rotl($rhs as i32)) as u32,
+ BinOp::IRotr => (($lhs as i32).wasm_rotr($rhs as i32)) as u32,
+ BinOp::FAdd => (f32::from_bits($lhs) + f32::from_bits($rhs)).to_bits(),
+ BinOp::FSub => (f32::from_bits($lhs) - f32::from_bits($rhs)).to_bits(),
+ BinOp::FMul => (f32::from_bits($lhs) * f32::from_bits($rhs)).to_bits(),
+ BinOp::FDiv => (f32::from_bits($lhs) / f32::from_bits($rhs)).to_bits(),
+ BinOp::FMin => f32::from_bits($lhs).tw_minimum(f32::from_bits($rhs)).to_bits(),
+ BinOp::FMax => f32::from_bits($lhs).tw_maximum(f32::from_bits($rhs)).to_bits(),
+ BinOp::FCopysign => f32::from_bits($lhs).copysign(f32::from_bits($rhs)).to_bits(),
+ }
+ }};
+ (64, $op:expr, $lhs:expr, $rhs:expr) => {{
+ match $op {
+ BinOp::IAdd => $lhs.wrapping_add($rhs),
+ BinOp::ISub => $lhs.wrapping_sub($rhs),
+ BinOp::IMul => $lhs.wrapping_mul($rhs),
+ BinOp::IAnd => $lhs & $rhs,
+ BinOp::IOr => $lhs | $rhs,
+ BinOp::IXor => $lhs ^ $rhs,
+ BinOp::IShl => (($lhs as i64).wasm_shl($rhs as i64)) as u64,
+ BinOp::IShrS => (($lhs as i64).wasm_shr($rhs as i64)) as u64,
+ BinOp::IShrU => $lhs.wasm_shr($rhs),
+ BinOp::IRotl => (($lhs as i64).wasm_rotl($rhs as i64)) as u64,
+ BinOp::IRotr => (($lhs as i64).wasm_rotr($rhs as i64)) as u64,
+ BinOp::FAdd => (f64::from_bits($lhs) + f64::from_bits($rhs)).to_bits(),
+ BinOp::FSub => (f64::from_bits($lhs) - f64::from_bits($rhs)).to_bits(),
+ BinOp::FMul => (f64::from_bits($lhs) * f64::from_bits($rhs)).to_bits(),
+ BinOp::FDiv => (f64::from_bits($lhs) / f64::from_bits($rhs)).to_bits(),
+ BinOp::FMin => f64::from_bits($lhs).tw_minimum(f64::from_bits($rhs)).to_bits(),
+ BinOp::FMax => f64::from_bits($lhs).tw_maximum(f64::from_bits($rhs)).to_bits(),
+ BinOp::FCopysign => f64::from_bits($lhs).copysign(f64::from_bits($rhs)).to_bits(),
+ }
+ }};
+ (128, $op:expr, $lhs:expr, $rhs:expr) => {{
+ match $op {
+ BinOp128::And => $lhs.v128_and($rhs),
+ BinOp128::AndNot => $lhs.v128_andnot($rhs),
+ BinOp128::Or => $lhs.v128_or($rhs),
+ BinOp128::Xor => $lhs.v128_xor($rhs),
+ BinOp128::I64x2Add => $lhs.i64x2_add($rhs),
+ BinOp128::I64x2Mul => $lhs.i64x2_mul($rhs),
+ }
}};
}
macro_rules! binop {
- (local_local $vt:ty, $exec:ident, $op:ident, $a:ident, $b:ident) => {{
- self.store.value_stack.push(self.$exec(
- *$op,
- <$vt>::local_get(&self.store.value_stack, &self.cf, *$a),
- <$vt>::local_get(&self.store.value_stack, &self.cf, *$b),
- ))?
+ (local_local $vt:ty, $width:tt, $op:ident, $a:ident, $b:ident) => {{
+ (|| -> Result<(), Trap> {
+ let lhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$a);
+ let rhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$b);
+ self.store.value_stack.push(exec_binop!($width, *$op, lhs, rhs))?;
+ Ok(())
+ })()?;
}};
- (local_local_set $vt:ty, $exec:ident, $op:ident, $a:ident, $b:ident, $dst:ident) => {{
- let value = self.$exec(
- *$op,
- <$vt>::local_get(&self.store.value_stack, &self.cf, *$a),
- <$vt>::local_get(&self.store.value_stack, &self.cf, *$b),
- );
- <$vt>::local_set(&mut self.store.value_stack, &self.cf, *$dst, value);
+ (local_local_set $vt:ty, $width:tt, $op:ident, $a:ident, $b:ident, $dst:ident) => {{
+ (|| {
+ let lhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$a);
+ let rhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$b);
+ let value = exec_binop!($width, *$op, lhs, rhs);
+ <$vt>::local_set(&mut self.store.value_stack, &self.cf, *$dst, value);
+ })();
}};
- (local_local_tee $vt:ty, $exec:ident, $op:ident, $a:ident, $b:ident, $dst:ident) => {{
- let value = self.$exec(
- *$op,
- <$vt>::local_get(&self.store.value_stack, &self.cf, *$a),
- <$vt>::local_get(&self.store.value_stack, &self.cf, *$b),
- );
- <$vt>::local_set(&mut self.store.value_stack, &self.cf, *$dst, value);
- self.store.value_stack.push(value)?;
+ (local_local_tee $vt:ty, $width:tt, $op:ident, $a:ident, $b:ident, $dst:ident) => {{
+ (|| -> Result<(), Trap> {
+ let lhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$a);
+ let rhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$b);
+ let value = exec_binop!($width, *$op, lhs, rhs);
+ <$vt>::local_set(&mut self.store.value_stack, &self.cf, *$dst, value);
+ self.store.value_stack.push(value)?;
+ Ok(())
+ })()?;
}};
- (local_const $vt:ty, $exec:ident, $op:ident, $local:ident, $rhs:expr) => {{
- self.store.value_stack.push(self.$exec(
- *$op,
- <$vt>::local_get(&self.store.value_stack, &self.cf, *$local),
- $rhs,
- ))?
+ (local_const $vt:ty, $width:tt, $op:ident, $local:ident, $rhs:expr) => {{
+ (|| -> Result<(), Trap> {
+ let lhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$local);
+ self.store.value_stack.push(exec_binop!($width, *$op, lhs, $rhs))?;
+ Ok(())
+ })()?;
}};
- (local_const_set $vt:ty, $exec:ident, $op:ident, $local:ident, $rhs:expr, $dst:ident) => {{
- let value = self.$exec(*$op, <$vt>::local_get(&self.store.value_stack, &self.cf, *$local), $rhs);
- <$vt>::local_set(&mut self.store.value_stack, &self.cf, *$dst, value);
+ (local_const_set $vt:ty, $width:tt, $op:ident, $local:ident, $rhs:expr, $dst:ident) => {{
+ (|| {
+ let lhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$local);
+ let value = exec_binop!($width, *$op, lhs, $rhs);
+ <$vt>::local_set(&mut self.store.value_stack, &self.cf, *$dst, value);
+ })();
}};
- (local_const_tee $vt:ty, $exec:ident, $op:ident, $local:ident, $rhs:expr, $dst:ident) => {{
- let value = self.$exec(*$op, <$vt>::local_get(&self.store.value_stack, &self.cf, *$local), $rhs);
- <$vt>::local_set(&mut self.store.value_stack, &self.cf, *$dst, value);
- self.store.value_stack.push(value)?;
+ (local_const_tee $vt:ty, $width:tt, $op:ident, $local:ident, $rhs:expr, $dst:ident) => {{
+ (|| -> Result<(), Trap> {
+ let lhs = <$vt>::local_get(&self.store.value_stack, &self.cf, *$local);
+ let value = exec_binop!($width, *$op, lhs, $rhs);
+ <$vt>::local_set(&mut self.store.value_stack, &self.cf, *$dst, value);
+ self.store.value_stack.push(value)?;
+ Ok(())
+ })()?;
}};
- (stack_global $vt:ty, $as_fn:ident, $exec:ident, $op:ident, $global:ident) => {{
- let global_val =
- self.store.state.get_global_val(self.module.resolve_global_addr(*$global)).$as_fn().unwrap();
- let stack_val = <$vt>::stack_pop(&mut self.store.value_stack);
- self.store.value_stack.push(self.$exec(*$op, stack_val, global_val))?;
+ (stack_global $vt:ty, $as_fn:ident, $width:tt, $op:ident, $global:ident) => {{
+ (|| -> Result<(), Trap> {
+ let global_val =
+ self.store.state.get_global_val(self.module.resolve_global_addr(*$global)).$as_fn().unwrap();
+ let stack_val = <$vt>::stack_pop(&mut self.store.value_stack);
+ self.store.value_stack.push(exec_binop!($width, *$op, stack_val, global_val))?;
+ Ok(())
+ })()?;
}};
}
@@ -239,8 +279,8 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
use tinywasm_types::Instruction::*;
#[rustfmt::skip]
match next {
- Nop | MergeBarrier => {}
- Unreachable => return Err(Trap::Unreachable),
+ Nop => {}
+ MergeBarrier | Unreachable => return Err(Trap::Unreachable),
Drop32 => { _ = Value32::stack_pop(&mut self.store.value_stack)},
Drop64 => { _ = Value64::stack_pop(&mut self.store.value_stack)},
Drop128 => { _ = Value128::stack_pop(&mut self.store.value_stack)},
@@ -254,7 +294,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
ReturnCall(v) => { self.exec_return_call_direct(*v)?; return Ok(None); }
ReturnCallSelf => { self.exec_return_call_self()?; return Ok(None); }
ReturnCallIndirect(ty, table) => { self.exec_call_indirect::<true>(*ty, *table)?; return Ok(None); }
- Jump(ip) => { self.cf.instr_ptr = *ip; return Ok(None); }
+ Jump(ip) => { self.cf.instr_ptr = *ip as usize; return Ok(None); }
JumpIfZero32(ip) => if self.exec_jump_zero_32(*ip) { return Ok(None) },
JumpIfNonZero32(ip) => if self.exec_jump_non_zero_32(*ip) { return Ok(None) },
JumpIfZero64(ip) => if self.exec_jump_zero_64(*ip) { return Ok(None) },
@@ -298,26 +338,26 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
MulAccLocal64(acc) => self.exec_binop_acc_local::<i64, _, _>(*acc, |a, b| a.wrapping_mul(b), |a, b| a.wrapping_add(b)),
FMulAccLocal32(acc) => self.exec_binop_acc_local::<f32, _, _>(*acc, |a, b| a * b, |a, b| a + b),
FMulAccLocal64(acc) => self.exec_binop_acc_local::<f64, _, _>(*acc, |a, b| a * b, |a, b| a + b),
- BinOpLocalLocal32(op, a, b) => binop!(local_local Value32, exec_binop_32, op, a, b),
- BinOpLocalLocal64(op, a, b) => binop!(local_local Value64, exec_binop_64, op, a, b),
- BinOpLocalLocal128(op, a, b) => binop!(local_local Value128, exec_binop_128, op, a, b),
- BinOpLocalLocalSet32(op, a, b, dst) => binop!(local_local_set Value32, exec_binop_32, op, a, b, dst),
- BinOpLocalLocalSet64(op, a, b, dst) => binop!(local_local_set Value64, exec_binop_64, op, a, b, dst),
- BinOpLocalLocalSet128(op, a, b, dst) => binop!(local_local_set Value128, exec_binop_128, op, a, b, dst),
- BinOpLocalLocalTee32(op, a, b, dst) => binop!(local_local_tee Value32, exec_binop_32, op, a, b, dst),
- BinOpLocalLocalTee64(op, a, b, dst) => binop!(local_local_tee Value64, exec_binop_64, op, a, b, dst),
- BinOpLocalLocalTee128(op, a, b, dst) => binop!(local_local_tee Value128, exec_binop_128, op, a, b, dst),
- BinOpLocalConst32(op, local_index, c) => binop!(local_const Value32, exec_binop_32, op, local_index, *c as u32),
- BinOpLocalConst64(op, local_index, c) => binop!(local_const Value64, exec_binop_64, op, local_index, *c as u64),
- BinOpLocalConst128(op, local_index, c) => binop!(local_const Value128, exec_binop_128, op, local_index, Value128(self.func.data.v128_const(*c))),
- BinOpLocalConstSet32(op, local_index, c, dst) => binop!(local_const_set Value32, exec_binop_32, op, local_index, *c as u32, dst),
- BinOpLocalConstSet64(op, local_index, c, dst) => binop!(local_const_set Value64, exec_binop_64, op, local_index, *c as u64, dst),
- BinOpLocalConstSet128(op, local_index, c, dst) => binop!(local_const_set Value128, exec_binop_128, op, local_index, Value128(self.func.data.v128_const(*c)), dst),
- BinOpLocalConstTee32(op, local_index, c, dst) => binop!(local_const_tee Value32, exec_binop_32, op, local_index, *c as u32, dst),
- BinOpLocalConstTee64(op, local_index, c, dst) => binop!(local_const_tee Value64, exec_binop_64, op, local_index, *c as u64, dst),
- BinOpLocalConstTee128(op, local_index, c, dst) => binop!(local_const_tee Value128, exec_binop_128, op, local_index, Value128(self.func.data.v128_const(*c)), dst),
- BinOpStackGlobal32(op, global_index) => binop!(stack_global Value32, as_32, exec_binop_32, op, global_index),
- BinOpStackGlobal64(op, global_index) => binop!(stack_global Value64, as_64, exec_binop_64, op, global_index),
+ BinOpLocalLocal32(op, a, b) => binop!(local_local Value32, 32, op, a, b),
+ BinOpLocalLocal64(op, a, b) => binop!(local_local Value64, 64, op, a, b),
+ BinOpLocalLocal128(op, a, b) => binop!(local_local Value128, 128, op, a, b),
+ BinOpLocalLocalSet32(op, a, b, dst) => binop!(local_local_set Value32, 32, op, a, b, dst),
+ BinOpLocalLocalSet64(op, a, b, dst) => binop!(local_local_set Value64, 64, op, a, b, dst),
+ BinOpLocalLocalSet128(op, a, b, dst) => binop!(local_local_set Value128, 128, op, a, b, dst),
+ BinOpLocalLocalTee32(op, a, b, dst) => binop!(local_local_tee Value32, 32, op, a, b, dst),
+ BinOpLocalLocalTee64(op, a, b, dst) => binop!(local_local_tee Value64, 64, op, a, b, dst),
+ BinOpLocalLocalTee128(op, a, b, dst) => binop!(local_local_tee Value128, 128, op, a, b, dst),
+ BinOpLocalConst32(op, local_index, c) => binop!(local_const Value32, 32, op, local_index, *c as u32),
+ BinOpLocalConst64(op, local_index, c) => binop!(local_const Value64, 64, op, local_index, *c as u64),
+ BinOpLocalConst128(op, local_index, c) => binop!(local_const Value128, 128, op, local_index, Value128(self.func.data.v128_const(*c))),
+ BinOpLocalConstSet32(op, local_index, c, dst) => binop!(local_const_set Value32, 32, op, local_index, *c as u32, dst),
+ BinOpLocalConstSet64(op, local_index, c, dst) => binop!(local_const_set Value64, 64, op, local_index, *c as u64, dst),
+ BinOpLocalConstSet128(op, local_index, c, dst) => binop!(local_const_set Value128, 128, op, local_index, Value128(self.func.data.v128_const(*c)), dst),
+ BinOpLocalConstTee32(op, local_index, c, dst) => binop!(local_const_tee Value32, 32, op, local_index, *c as u32, dst),
+ BinOpLocalConstTee64(op, local_index, c, dst) => binop!(local_const_tee Value64, 64, op, local_index, *c as u64, dst),
+ BinOpLocalConstTee128(op, local_index, c, dst) => binop!(local_const_tee Value128, 128, op, local_index, Value128(self.func.data.v128_const(*c)), dst),
+ BinOpStackGlobal32(op, global_index) => binop!(stack_global Value32, as_32, 32, op, global_index),
+ BinOpStackGlobal64(op, global_index) => binop!(stack_global Value64, as_64, 64, op, global_index),
SetLocalConst32(local_index, c) => i32::local_set(&mut self.store.value_stack, &self.cf, *local_index, *c),
SetLocalConst64(local_index, c) => i64::local_set(&mut self.store.value_stack, &self.cf, *local_index, *c),
SetLocalConst128(local_index, c) => Value128::local_set(&mut self.store.value_stack, &self.cf, *local_index, Value128(self.func.data.v128_const(*c))),
@@ -825,7 +865,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
#[inline(always)]
fn jump_if(&mut self, condition: bool, ip: u32) -> bool {
if condition {
- self.cf.instr_ptr = ip;
+ self.cf.instr_ptr = ip as usize;
}
condition
}
@@ -918,7 +958,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
default_ip
};
- self.cf.instr_ptr = target_ip;
+ self.cf.instr_ptr = target_ip as usize;
}
fn exec_drop_keep(&mut self, base32: u16, keep32: u8, base64: u16, keep64: u8, base128: u16, keep128: u8) {
@@ -1614,6 +1654,12 @@ impl<'store> Executor<'store, true> {
}
}
+#[cold]
+#[inline(never)]
+fn instruction_pointer_out_of_bounds(instr_ptr: usize, instruction_count: usize) -> ! {
+ panic!("Instruction pointer out of bounds: {instr_ptr} ({instruction_count} instructions)")
+}
+
#[inline(always)]
fn cmp_i32(lhs: i32, rhs: i32, op: CmpOp) -> bool {
match op {
diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs
index ad71302..62f1f8e 100644
--- a/crates/tinywasm/src/interpreter/stack/call_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs
@@ -67,7 +67,7 @@ impl CallStack {
#[derive(Clone, Copy)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub(crate) struct CallFrame {
- pub(crate) instr_ptr: u32,
+ pub(crate) instr_ptr: usize,
pub(crate) func_addr: FuncAddr,
pub(crate) locals_base: StackBase,
pub(crate) stack_offset: ValueCounts,
diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index ad16467..3aebacd 100644
--- a/crates/tinywasm/src/interpreter/stack/value_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs
@@ -79,6 +79,18 @@ impl<T: Copy + Default> Stack<T> {
}
#[inline(always)]
+ pub(crate) fn copy(&mut self, from: usize, to: usize) {
+ let val = self.data.get(from).unwrap_or_else(|| {
+ cold_path();
+ unreachable!("Stack index out of bounds, this is a bug");
+ });
+ *self.data.get_mut(to).unwrap_or_else(|| {
+ cold_path();
+ unreachable!("Stack index out of bounds, this is a bug");
+ }) = *val;
+ }
+
+ #[inline(always)]
pub(crate) fn truncate_keep(&mut self, n: usize, end_keep: usize) {
let len = self.data.len();
debug_assert!(n <= len);
diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs
index a880574..b312b5d 100644
--- a/crates/tinywasm/src/interpreter/values.rs
+++ b/crates/tinywasm/src/interpreter/values.rs
@@ -204,8 +204,8 @@ macro_rules! impl_internalvalue {
#[inline(always)]
fn local_copy(stack: &mut ValueStack, frame: &CallFrame, from: LocalAddr, to: LocalAddr) {
- let val = stack.$stack.get(frame.locals_base.$stack_base as usize + from as usize);
- stack.$stack.set(frame.locals_base.$stack_base as usize + to as usize, *val);
+ let base = frame.locals_base.$stack_base as usize;
+ stack.$stack.copy(base + from as usize, base + to as usize);
}
#[inline(always)]