diff options
| author | Henry Gressmann <mail@henrygressmann.de> | 2024-05-23 22:48:03 +0200 |
|---|---|---|
| committer | Henry Gressmann <mail@henrygressmann.de> | 2024-05-23 22:48:03 +0200 |
| commit | 6c2c6b2ae229dfee35a3d6d65b11d5c4ad1f1fb5 (patch) | |
| tree | 9bc1d5b7fb930920b4db45b537fab5630c299d3b /crates | |
| parent | 919367200e482448d7511dc6eb6660cd61e76ef4 (diff) | |
chore: prepare resumable execution
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/tinywasm/src/runtime/interpreter/macros.rs | 89 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/interpreter/mod.rs | 897 | ||||
| -rw-r--r-- | crates/tinywasm/src/runtime/stack/value_stack.rs | 5 |
3 files changed, 461 insertions, 530 deletions
diff --git a/crates/tinywasm/src/runtime/interpreter/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs index 8a092c0..7dcee61 100644 --- a/crates/tinywasm/src/runtime/interpreter/macros.rs +++ b/crates/tinywasm/src/runtime/interpreter/macros.rs @@ -10,24 +10,24 @@ // This is a bit hard to see from the spec, but it's vaild to use breaks to return // from a function, so we need to check if the label stack is empty macro_rules! break_to { - ($cf:ident, $stack:ident, $module:ident, $store:ident, $break_to_relative:ident) => {{ - if $cf.break_to(*$break_to_relative, &mut $stack.values, &mut $stack.blocks).is_none() { - if $stack.call_stack.is_empty() { - return Ok(()); + ($break_to_relative:expr, $self:expr) => {{ + if $self.cf.break_to($break_to_relative, &mut $self.stack.values, &mut $self.stack.blocks).is_none() { + if $self.stack.call_stack.is_empty() { + return Ok(ExecResult::Return); } - call!($cf, $stack, $module, $store) + return $self.process_call(); } }}; } /// Load a value from memory macro_rules! mem_load { - ($type:ty, $arg:expr, $stack:ident, $store:ident, $module:ident) => {{ - mem_load!($type, $type, $arg, $stack, $store, $module) + ($type:ty, $arg:expr, $self:expr) => {{ + mem_load!($type, $type, $arg, $self) }}; - ($load_type:ty, $target_type:ty, $arg:expr, $stack:ident, $store:ident, $module:ident) => {{ + ($load_type:ty, $target_type:ty, $arg:expr, $self:expr) => {{ #[inline(always)] fn mem_load_inner( store: &Store, @@ -56,17 +56,17 @@ macro_rules! mem_load { } let (mem_addr, offset) = $arg; - mem_load_inner($store, &$module, $stack, *mem_addr, *offset)?; + mem_load_inner($self.store, &$self.module, $self.stack, *mem_addr, *offset)?; }}; } /// Store a value to memory macro_rules! mem_store { - ($type:ty, $arg:expr, $stack:ident, $store:ident, $module:ident) => {{ - mem_store!($type, $type, $arg, $stack, $store, $module) + ($type:ty, $arg:expr, $self:expr) => {{ + mem_store!($type, $type, $arg, $self) }}; - ($store_type:ty, $target_type:ty, $arg:expr, $stack:ident, $store:ident, $module:ident) => {{ + ($store_type:ty, $target_type:ty, $arg:expr, $self:expr) => {{ #[inline(always)] fn mem_store_inner( store: &Store, @@ -83,8 +83,7 @@ macro_rules! mem_store { Ok(()) } - let (mem_addr, offset) = $arg; - mem_store_inner($store, &$module, $stack, *mem_addr, *offset)?; + mem_store_inner($self.store, &$self.module, $self.stack, *$arg.0, *$arg.1)?; }}; } @@ -110,21 +109,21 @@ macro_rules! float_min_max { /// Convert a value on the stack macro_rules! conv { - ($from:ty, $to:ty, $stack:ident) => { - $stack.values.replace_top(|v| (<$from>::from(v) as $to).into())? + ($from:ty, $to:ty, $self:expr) => { + $self.stack.values.replace_top(|v| (<$from>::from(v) as $to).into())? }; } /// Convert a value on the stack with error checking macro_rules! checked_conv_float { // Direct conversion with error checking (two types) - ($from:tt, $to:tt, $stack:ident) => { - checked_conv_float!($from, $to, $to, $stack) + ($from:tt, $to:tt, $self:expr) => { + checked_conv_float!($from, $to, $to, $self) }; // Conversion with an intermediate unsigned type and error checking (three types) - ($from:tt, $intermediate:tt, $to:tt, $stack:ident) => {{ + ($from:tt, $intermediate:tt, $to:tt, $self:expr) => {{ let (min, max) = float_min_max!($from, $intermediate); - let a: $from = $stack.values.pop()?.into(); + let a: $from = $self.stack.values.pop()?.into(); if unlikely(a.is_nan()) { return Err(Error::Trap(crate::Trap::InvalidConversionToInt)); @@ -134,14 +133,14 @@ macro_rules! checked_conv_float { return Err(Error::Trap(crate::Trap::IntegerOverflow)); } - $stack.values.push((a as $intermediate as $to).into()); + $self.stack.values.push((a as $intermediate as $to).into()); }}; } /// Compare two values on the stack macro_rules! comp { - ($op:tt, $to:ty, $stack:ident) => { - $stack.values.calculate(|a, b| { + ($op:tt, $to:ty, $self:ident) => { + $self.stack.values.calculate(|a, b| { ((<$to>::from(a) $op <$to>::from(b)) as i32).into() })? }; @@ -149,8 +148,8 @@ macro_rules! comp { /// Compare a value on the stack to zero macro_rules! comp_zero { - ($op:tt, $ty:ty, $stack:ident) => { - $stack.values.replace_top(|v| { + ($op:tt, $ty:ty, $self:expr) => { + $self.stack.values.replace_top(|v| { ((<$ty>::from(v) $op 0) as i32).into() })? }; @@ -158,15 +157,15 @@ macro_rules! comp_zero { /// Apply an arithmetic method to two values on the stack macro_rules! arithmetic { - ($op:ident, $to:ty, $stack:ident) => { - $stack.values.calculate(|a, b| { + ($op:ident, $to:ty, $self:expr) => { + $self.stack.values.calculate(|a, b| { (<$to>::from(a).$op(<$to>::from(b)) as $to).into() })? }; // also allow operators such as +, - - ($op:tt, $ty:ty, $stack:ident) => { - $stack.values.calculate(|a, b| { + ($op:tt, $ty:ty, $self:expr) => { + $self.stack.values.calculate(|a, b| { ((<$ty>::from(a) $op <$ty>::from(b)) as $ty).into() })? }; @@ -174,19 +173,19 @@ macro_rules! arithmetic { /// Apply an arithmetic method to a single value on the stack macro_rules! arithmetic_single { - ($op:ident, $ty:ty, $stack:ident) => { - arithmetic_single!($op, $ty, $ty, $stack) + ($op:ident, $ty:ty, $self:expr) => { + arithmetic_single!($op, $ty, $ty, $self) }; - ($op:ident, $from:ty, $to:ty, $stack:ident) => { - $stack.values.replace_top(|v| (<$from>::from(v).$op() as $to).into())? + ($op:ident, $from:ty, $to:ty, $self:expr) => { + $self.stack.values.replace_top(|v| (<$from>::from(v).$op() as $to).into())? }; } /// Apply an arithmetic operation to two values on the stack with error checking macro_rules! checked_int_arithmetic { - ($op:ident, $to:ty, $stack:ident) => { - $stack.values.calculate_trap(|a, b| { + ($op:ident, $to:ty, $self:expr) => { + $self.stack.values.calculate_trap(|a, b| { let a: $to = a.into(); let b: $to = b.into(); @@ -200,27 +199,10 @@ macro_rules! checked_int_arithmetic { }; } -macro_rules! call { - ($cf:expr, $stack:expr, $module:expr, $store:expr) => {{ - let old = $cf.block_ptr; - $cf = $stack.call_stack.pop()?; - - if old > $cf.block_ptr { - $stack.blocks.truncate(old); - } - - if $cf.module_addr != $module.id() { - $module.swap_with($cf.module_addr, $store); - } - - continue; - }}; -} - macro_rules! skip { ($code:expr) => { match $code { - Ok(_) => continue, + Ok(_) => return Ok(ExecResult::Continue), Err(e) => return Err(e), } }; @@ -229,7 +211,6 @@ macro_rules! skip { pub(super) use arithmetic; pub(super) use arithmetic_single; pub(super) use break_to; -pub(super) use call; pub(super) use checked_conv_float; pub(super) use checked_int_arithmetic; pub(super) use comp; diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 79076db..58a571e 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -5,8 +5,8 @@ use tinywasm_types::{BlockArgs, ElementKind, ValType}; use super::{InterpreterRuntime, RawWasmValue, Stack}; use crate::runtime::{BlockFrame, BlockType, CallFrame}; -use crate::{cold, unlikely, ModuleInstance}; -use crate::{Error, FuncContext, Result, Store, Trap}; +use crate::{cold, unlikely}; +use crate::{Error, FuncContext, ModuleInstance, Result, Store, Trap}; mod macros; mod traits; @@ -21,301 +21,347 @@ use no_std_floats::NoStdFloatExt; impl InterpreterRuntime { pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> { - let mut cf = stack.call_stack.pop()?; - let mut module = store.get_module_instance_raw(cf.module_addr); + let mut executor = Executor::new(store, stack)?; + executor.run_to_completion() + } +} + +struct Executor<'store, 'stack> { + store: &'store mut Store, + stack: &'stack mut Stack, + cf: CallFrame, + module: ModuleInstance, +} + +enum ExecResult { + Continue, + Return, +} + +impl<'store, 'stack> Executor<'store, 'stack> { + pub(crate) fn new(store: &'store mut Store, stack: &'stack mut Stack) -> Result<Self> { + let current_frame = stack.call_stack.pop()?; + let current_module = store.get_module_instance_raw(current_frame.module_addr); + Ok(Self { cf: current_frame, module: current_module, stack, store }) + } + + pub(crate) fn run_to_completion(&mut self) -> Result<()> { loop { - use tinywasm_types::Instruction::*; - match cf.fetch_instr() { - Nop => cold(), - Unreachable => self.exec_unreachable()?, - Drop => stack.values.pop().map(|_| ())?, - Select(_valtype) => self.exec_select(stack)?, + match self.exec_one()? { + ExecResult::Return => return Ok(()), + ExecResult::Continue => continue, + }; + } + } - Call(v) => skip!(self.exec_call(*v, store, stack, &mut cf, &mut module)), - CallIndirect(ty, table) => { - skip!(self.exec_call_indirect(*ty, *table, store, stack, &mut cf, &mut module)) - } - If(args, el, end) => skip!(self.exec_if((*args).into(), *el, *end, stack, &mut cf, &mut module)), - Loop(args, end) => self.enter_block(stack, cf.instr_ptr, *end, BlockType::Loop, args, &module), - Block(args, end) => self.enter_block(stack, cf.instr_ptr, *end, BlockType::Block, args, &module), + pub(crate) fn process_call(&mut self) -> Result<ExecResult> { + let old = self.cf.block_ptr; + self.cf = self.stack.call_stack.pop()?; - Br(v) => break_to!(cf, stack, module, store, v), - BrIf(v) => { - if i32::from(stack.values.pop()?) != 0 { - break_to!(cf, stack, module, store, v); - } + if old > self.cf.block_ptr { + self.stack.blocks.truncate(old); + } + + if self.cf.module_addr != self.module.id() { + self.module.swap_with(self.cf.module_addr, self.store); + } + + Ok(ExecResult::Continue) + } + + pub(crate) fn exec_one(&mut self) -> Result<ExecResult> { + use tinywasm_types::Instruction::*; + match self.cf.fetch_instr() { + Nop => cold(), + Unreachable => self.exec_unreachable()?, + Drop => self.stack.values.pop().map(|_| ())?, + Select(_valtype) => self.exec_select()?, + + Call(v) => skip!(self.exec_call(*v)), + CallIndirect(ty, table) => { + skip!(self.exec_call_indirect(*ty, *table)) + } + If(args, el, end) => skip!(self.exec_if((*args).into(), *el, *end)), + Loop(args, end) => self.enter_block(self.cf.instr_ptr, *end, BlockType::Loop, *args), + Block(args, end) => self.enter_block(self.cf.instr_ptr, *end, BlockType::Block, *args), + + Br(v) => break_to!(*v, self), + BrIf(v) => { + if i32::from(self.stack.values.pop()?) != 0 { + break_to!(*v, self); + } + } + BrTable(default, len) => { + let start = self.cf.instr_ptr + 1; + let end = start + *len as usize; + if end > self.cf.instructions().len() { + return Err(Error::Other(format!( + "br_table out of bounds: {} >= {}", + end, + self.cf.instructions().len() + ))); } - BrTable(default, len) => { - let start = cf.instr_ptr + 1; - let end = start + *len as usize; - if end > cf.instructions().len() { - return Err(Error::Other(format!( - "br_table out of bounds: {} >= {}", - end, - cf.instructions().len() - ))); - } - let idx: i32 = stack.values.pop()?.into(); - match cf.instructions()[start..end].get(idx as usize) { - None => break_to!(cf, stack, module, store, default), - Some(BrLabel(to)) => break_to!(cf, stack, module, store, to), - _ => return Err(Error::Other("br_table with invalid label".to_string())), - } + let idx: i32 = self.stack.values.pop()?.into(); + match self.cf.instructions()[start..end].get(idx as usize) { + None => break_to!(*default, self), + Some(BrLabel(to)) => break_to!(*to, self), + _ => return Err(Error::Other("br_table with invalid label".to_string())), } + } - Return => match stack.call_stack.is_empty() { - true => return Ok(()), - false => call!(cf, stack, module, store), - }, + Return => match self.stack.call_stack.is_empty() { + true => return Ok(ExecResult::Return), + false => return self.process_call(), + }, - // We're essentially using else as a EndBlockFrame instruction for if blocks - Else(end_offset) => self.exec_else(stack, *end_offset, &mut cf)?, + // We're essentially using else as a EndBlockFrame instruction for if blocks + Else(end_offset) => self.exec_else(*end_offset)?, - // remove the label from the label stack - EndBlockFrame => self.exec_end_block(stack)?, + // remove the label from the label stack + EndBlockFrame => self.exec_end_block()?, - LocalGet(local_index) => self.exec_local_get(*local_index, stack, &cf), - LocalSet(local_index) => self.exec_local_set(*local_index, stack, &mut cf)?, - LocalTee(local_index) => self.exec_local_tee(*local_index, stack, &mut cf)?, + LocalGet(local_index) => self.exec_local_get(*local_index), + LocalSet(local_index) => self.exec_local_set(*local_index)?, + LocalTee(local_index) => self.exec_local_tee(*local_index)?, - GlobalGet(global_index) => self.exec_global_get(*global_index, stack, store, &module)?, - GlobalSet(global_index) => self.exec_global_set(*global_index, stack, store, &module)?, + GlobalGet(global_index) => self.exec_global_get(*global_index)?, + GlobalSet(global_index) => self.exec_global_set(*global_index)?, - I32Const(val) => self.exec_const(*val, stack), - I64Const(val) => self.exec_const(*val, stack), - F32Const(val) => self.exec_const(*val, stack), - F64Const(val) => self.exec_const(*val, stack), + I32Const(val) => self.exec_const(*val), + I64Const(val) => self.exec_const(*val), + F32Const(val) => self.exec_const(*val), + F64Const(val) => self.exec_const(*val), - MemorySize(addr, byte) => self.exec_memory_size(*addr, *byte, stack, store, &module)?, - MemoryGrow(addr, byte) => self.exec_memory_grow(*addr, *byte, stack, store, &module)?, + MemorySize(addr, byte) => self.exec_memory_size(*addr, *byte)?, + MemoryGrow(addr, byte) => self.exec_memory_grow(*addr, *byte)?, - // Bulk memory operations - MemoryCopy(from, to) => self.exec_memory_copy(*from, *to, stack, store, &module)?, - MemoryFill(addr) => self.exec_memory_fill(*addr, stack, store, &module)?, - MemoryInit(data_idx, mem_idx) => self.exec_memory_init(*data_idx, *mem_idx, stack, store, &module)?, - DataDrop(data_index) => store.get_data_mut(module.resolve_data_addr(*data_index))?.drop(), + // Bulk memory operations + MemoryCopy(from, to) => self.exec_memory_copy(*from, *to)?, + MemoryFill(addr) => self.exec_memory_fill(*addr)?, + MemoryInit(data_idx, mem_idx) => self.exec_memory_init(*data_idx, *mem_idx)?, + DataDrop(data_index) => self.exec_data_drop(*data_index)?, - I32Store { mem_addr, offset } => mem_store!(i32, (mem_addr, offset), stack, store, module), - I64Store { mem_addr, offset } => mem_store!(i64, (mem_addr, offset), stack, store, module), - F32Store { mem_addr, offset } => mem_store!(f32, (mem_addr, offset), stack, store, module), - F64Store { mem_addr, offset } => mem_store!(f64, (mem_addr, offset), stack, store, module), - I32Store8 { mem_addr, offset } => mem_store!(i8, i32, (mem_addr, offset), stack, store, module), - I32Store16 { mem_addr, offset } => mem_store!(i16, i32, (mem_addr, offset), stack, store, module), - I64Store8 { mem_addr, offset } => mem_store!(i8, i64, (mem_addr, offset), stack, store, module), - I64Store16 { mem_addr, offset } => mem_store!(i16, i64, (mem_addr, offset), stack, store, module), - I64Store32 { mem_addr, offset } => mem_store!(i32, i64, (mem_addr, offset), stack, store, module), + I32Store { mem_addr, offset } => mem_store!(i32, (mem_addr, offset), self), + I64Store { mem_addr, offset } => mem_store!(i64, (mem_addr, offset), self), + F32Store { mem_addr, offset } => mem_store!(f32, (mem_addr, offset), self), + F64Store { mem_addr, offset } => mem_store!(f64, (mem_addr, offset), self), + I32Store8 { mem_addr, offset } => mem_store!(i8, i32, (mem_addr, offset), self), + I32Store16 { mem_addr, offset } => mem_store!(i16, i32, (mem_addr, offset), self), + I64Store8 { mem_addr, offset } => mem_store!(i8, i64, (mem_addr, offset), self), + I64Store16 { mem_addr, offset } => mem_store!(i16, i64, (mem_addr, offset), self), + I64Store32 { mem_addr, offset } => mem_store!(i32, i64, (mem_addr, offset), self), - I32Load { mem_addr, offset } => mem_load!(i32, (mem_addr, offset), stack, store, module), - I64Load { mem_addr, offset } => mem_load!(i64, (mem_addr, offset), stack, store, module), - F32Load { mem_addr, offset } => mem_load!(f32, (mem_addr, offset), stack, store, module), - F64Load { mem_addr, offset } => mem_load!(f64, (mem_addr, offset), stack, store, module), - I32Load8S { mem_addr, offset } => mem_load!(i8, i32, (mem_addr, offset), stack, store, module), - I32Load8U { mem_addr, offset } => mem_load!(u8, i32, (mem_addr, offset), stack, store, module), - I32Load16S { mem_addr, offset } => mem_load!(i16, i32, (mem_addr, offset), stack, store, module), - I32Load16U { mem_addr, offset } => mem_load!(u16, i32, (mem_addr, offset), stack, store, module), - I64Load8S { mem_addr, offset } => mem_load!(i8, i64, (mem_addr, offset), stack, store, module), - I64Load8U { mem_addr, offset } => mem_load!(u8, i64, (mem_addr, offset), stack, store, module), - I64Load16S { mem_addr, offset } => mem_load!(i16, i64, (mem_addr, offset), stack, store, module), - I64Load16U { mem_addr, offset } => mem_load!(u16, i64, (mem_addr, offset), stack, store, module), - I64Load32S { mem_addr, offset } => mem_load!(i32, i64, (mem_addr, offset), stack, store, module), - I64Load32U { mem_addr, offset } => mem_load!(u32, i64, (mem_addr, offset), stack, store, module), + I32Load { mem_addr, offset } => mem_load!(i32, (mem_addr, offset), self), + I64Load { mem_addr, offset } => mem_load!(i64, (mem_addr, offset), self), + F32Load { mem_addr, offset } => mem_load!(f32, (mem_addr, offset), self), + F64Load { mem_addr, offset } => mem_load!(f64, (mem_addr, offset), self), + I32Load8S { mem_addr, offset } => mem_load!(i8, i32, (mem_addr, offset), self), + I32Load8U { mem_addr, offset } => mem_load!(u8, i32, (mem_addr, offset), self), + I32Load16S { mem_addr, offset } => mem_load!(i16, i32, (mem_addr, offset), self), + I32Load16U { mem_addr, offset } => mem_load!(u16, i32, (mem_addr, offset), self), + I64Load8S { mem_addr, offset } => mem_load!(i8, i64, (mem_addr, offset), self), + I64Load8U { mem_addr, offset } => mem_load!(u8, i64, (mem_addr, offset), self), + I64Load16S { mem_addr, offset } => mem_load!(i16, i64, (mem_addr, offset), self), + I64Load16U { mem_addr, offset } => mem_load!(u16, i64, (mem_addr, offset), self), + I64Load32S { mem_addr, offset } => mem_load!(i32, i64, (mem_addr, offset), self), + I64Load32U { mem_addr, offset } => mem_load!(u32, i64, (mem_addr, offset), self), - I64Eqz => comp_zero!(==, i64, stack), - I32Eqz => comp_zero!(==, i32, stack), + I64Eqz => comp_zero!(==, i64, self), + I32Eqz => comp_zero!(==, i32, self), - I32Eq => comp!(==, i32, stack), - I64Eq => comp!(==, i64, stack), - F32Eq => comp!(==, f32, stack), - F64Eq => comp!(==, f64, stack), + I32Eq => comp!(==, i32, self), + I64Eq => comp!(==, i64, self), + F32Eq => comp!(==, f32, self), + F64Eq => comp!(==, f64, self), - I32Ne => comp!(!=, i32, stack), - I64Ne => comp!(!=, i64, stack), - F32Ne => comp!(!=, f32, stack), - F64Ne => comp!(!=, f64, stack), + I32Ne => comp!(!=, i32, self), + I64Ne => comp!(!=, i64, self), + F32Ne => comp!(!=, f32, self), + F64Ne => comp!(!=, f64, self), - I32LtS => comp!(<, i32, stack), - I64LtS => comp!(<, i64, stack), - I32LtU => comp!(<, u32, stack), - I64LtU => comp!(<, u64, stack), - F32Lt => comp!(<, f32, stack), - F64Lt => comp!(<, f64, stack), + I32LtS => comp!(<, i32, self), + I64LtS => comp!(<, i64, self), + I32LtU => comp!(<, u32, self), + I64LtU => comp!(<, u64, self), + F32Lt => comp!(<, f32, self), + F64Lt => comp!(<, f64, self), - I32LeS => comp!(<=, i32, stack), - I64LeS => comp!(<=, i64, stack), - I32LeU => comp!(<=, u32, stack), - I64LeU => comp!(<=, u64, stack), - F32Le => comp!(<=, f32, stack), - F64Le => comp!(<=, f64, stack), + I32LeS => comp!(<=, i32, self), + I64LeS => comp!(<=, i64, self), + I32LeU => comp!(<=, u32, self), + I64LeU => comp!(<=, u64, self), + F32Le => comp!(<=, f32, self), + F64Le => comp!(<=, f64, self), - I32GeS => comp!(>=, i32, stack), - I64GeS => comp!(>=, i64, stack), - I32GeU => comp!(>=, u32, stack), - I64GeU => comp!(>=, u64, stack), - F32Ge => comp!(>=, f32, stack), - F64Ge => comp!(>=, f64, stack), + I32GeS => comp!(>=, i32, self), + I64GeS => comp!(>=, i64, self), + I32GeU => comp!(>=, u32, self), + I64GeU => comp!(>=, u64, self), + F32Ge => comp!(>=, f32, self), + F64Ge => comp!(>=, f64, self), - I32GtS => comp!(>, i32, stack), - I64GtS => comp!(>, i64, stack), - I32GtU => comp!(>, u32, stack), - I64GtU => comp!(>, u64, stack), - F32Gt => comp!(>, f32, stack), - F64Gt => comp!(>, f64, stack), + I32GtS => comp!(>, i32, self), + I64GtS => comp!(>, i64, self), + I32GtU => comp!(>, u32, self), + I64GtU => comp!(>, u64, self), + F32Gt => comp!(>, f32, self), + F64Gt => comp!(>, f64, self), - I64Add => arithmetic!(wrapping_add, i64, stack), - I32Add => arithmetic!(wrapping_add, i32, stack), - F32Add => arithmetic!(+, f32, stack), - F64Add => arithmetic!(+, f64, stack), + I64Add => arithmetic!(wrapping_add, i64, self), + I32Add => arithmetic!(wrapping_add, i32, self), + F32Add => arithmetic!(+, f32, self), + F64Add => arithmetic!(+, f64, self), - I32Sub => arithmetic!(wrapping_sub, i32, stack), - I64Sub => arithmetic!(wrapping_sub, i64, stack), - F32Sub => arithmetic!(-, f32, stack), - F64Sub => arithmetic!(-, f64, stack), + I32Sub => arithmetic!(wrapping_sub, i32, self), + I64Sub => arithmetic!(wrapping_sub, i64, self), + F32Sub => arithmetic!(-, f32, self), + F64Sub => arithmetic!(-, f64, self), - F32Div => arithmetic!(/, f32, stack), - F64Div => arithmetic!(/, f64, stack), + F32Div => arithmetic!(/, f32, self), + F64Div => arithmetic!(/, f64, self), - I32Mul => arithmetic!(wrapping_mul, i32, stack), - I64Mul => arithmetic!(wrapping_mul, i64, stack), - F32Mul => arithmetic!(*, f32, stack), - F64Mul => arithmetic!(*, f64, stack), + I32Mul => arithmetic!(wrapping_mul, i32, self), + I64Mul => arithmetic!(wrapping_mul, i64, self), + F32Mul => arithmetic!(*, f32, self), + F64Mul => arithmetic!(*, f64, self), - // these can trap - I32DivS => checked_int_arithmetic!(checked_div, i32, stack), - I64DivS => checked_int_arithmetic!(checked_div, i64, stack), - I32DivU => checked_int_arithmetic!(checked_div, u32, stack), - I64DivU => checked_int_arithmetic!(checked_div, u64, stack), + // these can trap + I32DivS => checked_int_arithmetic!(checked_div, i32, self), + I64DivS => checked_int_arithmetic!(checked_div, i64, self), + I32DivU => checked_int_arithmetic!(checked_div, u32, self), + I64DivU => checked_int_arithmetic!(checked_div, u64, self), - I32RemS => checked_int_arithmetic!(checked_wrapping_rem, i32, stack), - I64RemS => checked_int_arithmetic!(checked_wrapping_rem, i64, stack), - I32RemU => checked_int_arithmetic!(checked_wrapping_rem, u32, stack), - I64RemU => checked_int_arithmetic!(checked_wrapping_rem, u64, stack), + I32RemS => checked_int_arithmetic!(checked_wrapping_rem, i32, self), + I64RemS => checked_int_arithmetic!(checked_wrapping_rem, i64, self), + I32RemU => checked_int_arithmetic!(checked_wrapping_rem, u32, self), + I64RemU => checked_int_arithmetic!(checked_wrapping_rem, u64, self), - I32And => arithmetic!(bitand, i32, stack), - I64And => arithmetic!(bitand, i64, stack), - I32Or => arithmetic!(bitor, i32, stack), - I64Or => arithmetic!(bitor, i64, stack), - I32Xor => arithmetic!(bitxor, i32, stack), - I64Xor => arithmetic!(bitxor, i64, stack), - I32Shl => arithmetic!(wasm_shl, i32, stack), - I64Shl => arithmetic!(wasm_shl, i64, stack), - I32ShrS => arithmetic!(wasm_shr, i32, stack), - I64ShrS => arithmetic!(wasm_shr, i64, stack), - I32ShrU => arithmetic!(wasm_shr, u32, stack), - I64ShrU => arithmetic!(wasm_shr, u64, stack), - I32Rotl => arithmetic!(wasm_rotl, i32, stack), - I64Rotl => arithmetic!(wasm_rotl, i64, stack), - I32Rotr => arithmetic!(wasm_rotr, i32, stack), - I64Rotr => arithmetic!(wasm_rotr, i64, stack), + I32And => arithmetic!(bitand, i32, self), + I64And => arithmetic!(bitand, i64, self), + I32Or => arithmetic!(bitor, i32, self), + I64Or => arithmetic!(bitor, i64, self), + I32Xor => arithmetic!(bitxor, i32, self), + I64Xor => arithmetic!(bitxor, i64, self), + I32Shl => arithmetic!(wasm_shl, i32, self), + I64Shl => arithmetic!(wasm_shl, i64, self), + I32ShrS => arithmetic!(wasm_shr, i32, self), + I64ShrS => arithmetic!(wasm_shr, i64, self), + I32ShrU => arithmetic!(wasm_shr, u32, self), + I64ShrU => arithmetic!(wasm_shr, u64, self), + I32Rotl => arithmetic!(wasm_rotl, i32, self), + I64Rotl => arithmetic!(wasm_rotl, i64, self), + I32Rotr => arithmetic!(wasm_rotr, i32, self), + I64Rotr => arithmetic!(wasm_rotr, i64, self), - I32Clz => arithmetic_single!(leading_zeros, i32, stack), - I64Clz => arithmetic_single!(leading_zeros, i64, stack), - I32Ctz => arithmetic_single!(trailing_zeros, i32, stack), - I64Ctz => arithmetic_single!(trailing_zeros, i64, stack), - I32Popcnt => arithmetic_single!(count_ones, i32, stack), - I64Popcnt => arithmetic_single!(count_ones, i64, stack), + I32Clz => arithmetic_single!(leading_zeros, i32, self), + I64Clz => arithmetic_single!(leading_zeros, i64, self), + I32Ctz => arithmetic_single!(trailing_zeros, i32, self), + I64Ctz => arithmetic_single!(trailing_zeros, i64, self), + I32Popcnt => arithmetic_single!(count_ones, i32, self), + I64Popcnt => arithmetic_single!(count_ones, i64, self), - F32ConvertI32S => conv!(i32, f32, stack), - F32ConvertI64S => conv!(i64, f32, stack), - F64ConvertI32S => conv!(i32, f64, stack), - F64ConvertI64S => conv!(i64, f64, stack), - F32ConvertI32U => conv!(u32, f32, stack), - F32ConvertI64U => conv!(u64, f32, stack), - F64ConvertI32U => conv!(u32, f64, stack), - F64ConvertI64U => conv!(u64, f64, stack), - I32Extend8S => conv!(i8, i32, stack), - I32Extend16S => conv!(i16, i32, stack), - I64Extend8S => conv!(i8, i64, stack), - I64Extend16S => conv!(i16, i64, stack), - I64Extend32S => conv!(i32, i64, stack), - I64ExtendI32U => conv!(u32, i64, stack), - I64ExtendI32S => conv!(i32, i64, stack), - I32WrapI64 => conv!(i64, i32, stack), + F32ConvertI32S => conv!(i32, f32, self), + F32ConvertI64S => conv!(i64, f32, self), + F64ConvertI32S => conv!(i32, f64, self), + F64ConvertI64S => conv!(i64, f64, self), + F32ConvertI32U => conv!(u32, f32, self), + F32ConvertI64U => conv!(u64, f32, self), + F64ConvertI32U => conv!(u32, f64, self), + F64ConvertI64U => conv!(u64, f64, self), + I32Extend8S => conv!(i8, i32, self), + I32Extend16S => conv!(i16, i32, self), + I64Extend8S => conv!(i8, i64, self), + I64Extend16S => conv!(i16, i64, self), + I64Extend32S => conv!(i32, i64, self), + I64ExtendI32U => conv!(u32, i64, self), + I64ExtendI32S => conv!(i32, i64, self), + I32WrapI64 => conv!(i64, i32, self), - F32DemoteF64 => conv!(f64, f32, stack), - F64PromoteF32 => conv!(f32, f64, stack), + F32DemoteF64 => conv!(f64, f32, self), + F64PromoteF32 => conv!(f32, f64, self), - F32Abs => arithmetic_single!(abs, f32, stack), - F64Abs => arithmetic_single!(abs, f64, stack), - F32Neg => arithmetic_single!(neg, f32, stack), - F64Neg => arithmetic_single!(neg, f64, stack), - F32Ceil => arithmetic_single!(ceil, f32, stack), - F64Ceil => arithmetic_single!(ceil, f64, stack), - F32Floor => arithmetic_single!(floor, f32, stack), - F64Floor => arithmetic_single!(floor, f64, stack), - F32Trunc => arithmetic_single!(trunc, f32, stack), - F64Trunc => arithmetic_single!(trunc, f64, stack), - F32Nearest => arithmetic_single!(tw_nearest, f32, stack), - F64Nearest => arithmetic_single!(tw_nearest, f64, stack), - F32Sqrt => arithmetic_single!(sqrt, f32, stack), - F64Sqrt => arithmetic_single!(sqrt, f64, stack), - F32Min => arithmetic!(tw_minimum, f32, stack), - F64Min => arithmetic!(tw_minimum, f64, stack), - F32Max => arithmetic!(tw_maximum, f32, stack), - F64Max => arithmetic!(tw_maximum, f64, stack), - F32Copysign => arithmetic!(copysign, f32, stack), - F64Copysign => arithmetic!(copysign, f64, stack), + F32Abs => arithmetic_single!(abs, f32, self), + F64Abs => arithmetic_single!(abs, f64, self), + F32Neg => arithmetic_single!(neg, f32, self), + F64Neg => arithmetic_single!(neg, f64, self), + F32Ceil => arithmetic_single!(ceil, f32, self), + F64Ceil => arithmetic_single!(ceil, f64, self), + F32Floor => arithmetic_single!(floor, f32, self), + F64Floor => arithmetic_single!(floor, f64, self), + F32Trunc => arithmetic_single!(trunc, f32, self), + F64Trunc => arithmetic_single!(trunc, f64, self), + F32Nearest => arithmetic_single!(tw_nearest, f32, self), + F64Nearest => arithmetic_single!(tw_nearest, f64, self), + F32Sqrt => arithmetic_single!(sqrt, f32, self), + F64Sqrt => arithmetic_single!(sqrt, f64, self), + F32Min => arithmetic!(tw_minimum, f32, self), + F64Min => arithmetic!(tw_minimum, f64, self), + F32Max => arithmetic!(tw_maximum, f32, self), + F64Max => arithmetic!(tw_maximum, f64, self), + F32Copysign => arithmetic!(copysign, f32, self), + F64Copysign => arithmetic!(copysign, f64, self), - // no-op instructions since types are erased at runtime - I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} + // no-op instructions since types are erased at runtime + I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} - // unsigned versions of these are a bit broken atm - I32TruncF32S => checked_conv_float!(f32, i32, stack), - I32TruncF64S => checked_conv_float!(f64, i32, stack), - I32TruncF32U => checked_conv_float!(f32, u32, i32, stack), - I32TruncF64U => checked_conv_float!(f64, u32, i32, stack), - I64TruncF32S => checked_conv_float!(f32, i64, stack), - I64TruncF64S => checked_conv_float!(f64, i64, stack), - I64TruncF32U => checked_conv_float!(f32, u64, i64, stack), - I64TruncF64U => checked_conv_float!(f64, u64, i64, stack), + // unsigned versions of these are a bit broken atm + I32TruncF32S => checked_conv_float!(f32, i32, self), + I32TruncF64S => checked_conv_float!(f64, i32, self), + I32TruncF32U => checked_conv_float!(f32, u32, i32, self), + I32TruncF64U => checked_conv_float!(f64, u32, i32, self), + I64TruncF32S => checked_conv_float!(f32, i64, self), + I64TruncF64S => checked_conv_float!(f64, i64, self), + I64TruncF32U => checked_conv_float!(f32, u64, i64, self), + I64TruncF64U => checked_conv_float!(f64, u64, i64, self), - TableGet(table_idx) => self.exec_table_get(*table_idx, stack, store, &module)?, - TableSet(table_idx) => self.exec_table_set(*table_idx, stack, store, &module)?, - TableSize(table_idx) => self.exec_table_size(*table_idx, stack, store, &module)?, - TableInit(table_idx, elem_idx) => self.exec_table_init(*elem_idx, *table_idx, store, &module)?, + TableGet(table_idx) => self.exec_table_get(*table_idx)?, + TableSet(table_idx) => self.exec_table_set(*table_idx)?, + TableSize(table_idx) => self.exec_table_size(*table_idx)?, + TableInit(table_idx, elem_idx) => self.exec_table_init(*elem_idx, *table_idx)?, - I32TruncSatF32S => arithmetic_single!(trunc, f32, i32, stack), - I32TruncSatF32U => arithmetic_single!(trunc, f32, u32, stack), - I32TruncSatF64S => arithmetic_single!(trunc, f64, i32, stack), - I32TruncSatF64U => arithmetic_single!(trunc, f64, u32, stack), - I64TruncSatF32S => arithmetic_single!(trunc, f32, i64, stack), - I64TruncSatF32U => arithmetic_single!(trunc, f32, u64, stack), - I64TruncSatF64S => arithmetic_single!(trunc, f64, i64, stack), - I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, stack), + I32TruncSatF32S => arithmetic_single!(trunc, f32, i32, self), + I32TruncSatF32U => arithmetic_single!(trunc, f32, u32, self), + I32TruncSatF64S => arithmetic_single!(trunc, f64, i32, self), + I32TruncSatF64U => arithmetic_single!(trunc, f64, u32, self), + I64TruncSatF32S => arithmetic_single!(trunc, f32, i64, self), + I64TruncSatF32U => arithmetic_single!(trunc, f32, u64, self), + I64TruncSatF64S => arithmetic_single!(trunc, f64, i64, self), + I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, self), - // custom instructions - LocalGet2(a, b) => self.exec_local_get2(*a, *b, stack, &cf), - LocalGet3(a, b, c) => self.exec_local_get3(*a, *b, *c, stack, &cf), - LocalTeeGet(a, b) => self.exec_local_tee_get(*a, *b, stack, &mut cf), - LocalGetSet(a, b) => self.exec_local_get_set(*a, *b, &mut cf), - I64XorConstRotl(rotate_by) => self.exec_i64_xor_const_rotl(*rotate_by, stack)?, - I32LocalGetConstAdd(local, val) => self.exec_i32_local_get_const_add(*local, *val, stack, &cf), - I32StoreLocal { local, const_i32: consti32, offset, mem_addr } => { - self.exec_i32_store_local(*local, *consti32, *offset, *mem_addr, &cf, store, &module)? - } - i => { - cold(); - return Err(Error::UnsupportedFeature(format!("unimplemented instruction: {:?}", i))); - } - }; + // custom instructions + LocalGet2(a, b) => self.exec_local_get2(*a, *b), + LocalGet3(a, b, c) => self.exec_local_get3(*a, *b, *c), + LocalTeeGet(a, b) => self.exec_local_tee_get(*a, *b), + LocalGetSet(a, b) => self.exec_local_get_set(*a, *b), + I64XorConstRotl(rotate_by) => self.exec_i64_xor_const_rotl(*rotate_by)?, + I32LocalGetConstAdd(local, val) => self.exec_i32_local_get_const_add(*local, *val), + I32StoreLocal { local, const_i32: consti32, offset, mem_addr } => { + self.exec_i32_store_local(*local, *consti32, *offset, *mem_addr)? + } + i => { + cold(); + return Err(Error::UnsupportedFeature(format!("unimplemented instruction: {:?}", i))); + } + }; - cf.instr_ptr += 1; - } + self.cf.instr_ptr += 1; + Ok(ExecResult::Continue) } #[inline(always)] - fn exec_end_block(&self, stack: &mut Stack) -> Result<()> { - let block = stack.blocks.pop()?; - stack.values.truncate_keep(block.stack_ptr, block.results as u32); + fn exec_end_block(&mut self) -> Result<()> { + let block = self.stack.blocks.pop()?; + self.stack.values.truncate_keep(block.stack_ptr, block.results as u32); Ok(()) } #[inline(always)] - fn exec_else(&self, stack: &mut Stack, end_offset: u32, cf: &mut CallFrame) -> Result<()> { - let block = stack.blocks.pop()?; - stack.values.truncate_keep(block.stack_ptr, block.results as u32); - cf.instr_ptr += end_offset as usize; + fn exec_else(&mut self, end_offset: u32) -> Result<()> { + let block = self.stack.blocks.pop()?; + self.stack.values.truncate_keep(block.stack_ptr, block.results as u32); + self.cf.instr_ptr += end_offset as usize; Ok(()) } @@ -326,167 +372,122 @@ impl InterpreterRuntime { } #[inline(always)] - fn exec_const(&self, val: impl Into<RawWasmValue>, stack: &mut Stack) { - stack.values.push(val.into()); + fn exec_const(&mut self, val: impl Into<RawWasmValue>) { + self.stack.values.push(val.into()); } #[allow(clippy::too_many_arguments)] #[inline(always)] - fn exec_i32_store_local( - &self, - local: u32, - const_i32: i32, - offset: u32, - mem_addr: u8, - cf: &CallFrame, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { - let mem = store.get_mem(module.resolve_mem_addr(mem_addr as u32))?; + fn exec_i32_store_local(&mut self, local: u32, const_i32: i32, offset: u32, mem_addr: u8) -> Result<()> { + let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32))?; let val = const_i32.to_le_bytes(); - let addr: u64 = cf.get_local(local).into(); + let addr: u64 = self.cf.get_local(local).into(); mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; Ok(()) } #[inline(always)] - fn exec_i32_local_get_const_add(&self, local: u32, val: i32, stack: &mut Stack, cf: &CallFrame) { - let local: i32 = cf.get_local(local).into(); - stack.values.push((local + val).into()); + fn exec_i32_local_get_const_add(&mut self, local: u32, val: i32) { + let local: i32 = self.cf.get_local(local).into(); + self.stack.values.push((local + val).into()); } #[inline(always)] - fn exec_i64_xor_const_rotl(&self, rotate_by: i64, stack: &mut Stack) -> Result<()> { - let val: i64 = stack.values.pop()?.into(); - let res = stack.values.last_mut()?; + fn exec_i64_xor_const_rotl(&mut self, rotate_by: i64) -> Result<()> { + let val: i64 = self.stack.values.pop()?.into(); + let res = self.stack.values.last_mut()?; let mask: i64 = (*res).into(); *res = (val ^ mask).rotate_left(rotate_by as u32).into(); Ok(()) } #[inline(always)] - fn exec_local_get(&self, local_index: u32, stack: &mut Stack, cf: &CallFrame) { - stack.values.push(cf.get_local(local_index)); + fn exec_local_get(&mut self, local_index: u32) { + self.stack.values.push(self.cf.get_local(local_index)); } #[inline(always)] - fn exec_local_get2(&self, a: u32, b: u32, stack: &mut Stack, cf: &CallFrame) { - stack.values.push(cf.get_local(a)); - stack.values.push(cf.get_local(b)); + fn exec_local_get2(&mut self, a: u32, b: u32) { + self.stack.values.extend_from_slice(&[self.cf.get_local(a), self.cf.get_local(b)]); } #[inline(always)] - fn exec_local_get3(&self, a: u32, b: u32, c: u32, stack: &mut Stack, cf: &CallFrame) { - stack.values.push(cf.get_local(a)); - stack.values.push(cf.get_local(b)); - stack.values.push(cf.get_local(c)); + fn exec_local_get3(&mut self, a: u32, b: u32, c: u32) { + self.stack.values.extend_from_slice(&[self.cf.get_local(a), self.cf.get_local(b), self.cf.get_local(c)]); } #[inline(always)] - fn exec_local_get_set(&self, a: u32, b: u32, cf: &mut CallFrame) { - cf.set_local(b, cf.get_local(a)) + fn exec_local_get_set(&mut self, a: u32, b: u32) { + self.cf.set_local(b, self.cf.get_local(a)) } #[inline(always)] - fn exec_local_set(&self, local_index: u32, stack: &mut Stack, cf: &mut CallFrame) -> Result<()> { - cf.set_local(local_index, stack.values.pop()?); + fn exec_local_set(&mut self, local_index: u32) -> Result<()> { + self.cf.set_local(local_index, self.stack.values.pop()?); Ok(()) } #[inline(always)] - fn exec_local_tee(&self, local_index: u32, stack: &mut Stack, cf: &mut CallFrame) -> Result<()> { - cf.set_local(local_index, *stack.values.last()?); + fn exec_local_tee(&mut self, local_index: u32) -> Result<()> { + self.cf.set_local(local_index, *self.stack.values.last()?); Ok(()) } #[inline(always)] - fn exec_local_tee_get(&self, a: u32, b: u32, stack: &mut Stack, cf: &mut CallFrame) { + fn exec_local_tee_get(&mut self, a: u32, b: u32) { let last = - stack.values.last().expect("localtee: stack is empty. this should have been validated by the parser"); - cf.set_local(a, *last); - stack.values.push(match a == b { + self.stack.values.last().expect("localtee: stack is empty. this should have been validated by the parser"); + self.cf.set_local(a, *last); + self.stack.values.push(match a == b { true => *last, - false => cf.get_local(b), + false => self.cf.get_local(b), }); } #[inline(always)] - fn exec_global_get( - &self, - global_index: u32, - stack: &mut Stack, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { - let global = store.get_global_val(module.resolve_global_addr(global_index))?; - stack.values.push(global); + fn exec_global_get(&mut self, global_index: u32) -> Result<()> { + self.stack.values.push(self.store.get_global_val(self.module.resolve_global_addr(global_index))?); Ok(()) } #[inline(always)] - fn exec_global_set( - &self, - global_index: u32, - stack: &mut Stack, - store: &mut Store, - module: &ModuleInstance, - ) -> Result<()> { - let idx = module.resolve_global_addr(global_index); - store.set_global_val(idx, stack.values.pop()?)?; - Ok(()) + fn exec_global_set(&mut self, global_index: u32) -> Result<()> { + self.store.set_global_val(self.module.resolve_global_addr(global_index), self.stack.values.pop()?) } #[inline(always)] - fn exec_table_get( - &self, - table_index: u32, - stack: &mut Stack, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { - let table_idx = module.resolve_table_addr(table_index); - let table = store.get_table(table_idx)?; - let idx: u32 = stack.values.pop()?.into(); + fn exec_table_get(&mut self, table_index: u32) -> Result<()> { + let table_idx = self.module.resolve_table_addr(table_index); + let table = self.store.get_table(table_idx)?; + let idx: u32 = self.stack.values.pop()?.into(); let v = table.borrow().get_wasm_val(idx)?; - stack.values.push(v.into()); + self.stack.values.push(v.into()); Ok(()) } #[inline(always)] - fn exec_table_set( - &self, - table_index: u32, - stack: &mut Stack, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { - let table_idx = module.resolve_table_addr(table_index); - let table = store.get_table(table_idx)?; - let val = stack.values.pop()?.into(); - let idx = stack.values.pop()?.into(); + fn exec_table_set(&mut self, table_index: u32) -> Result<()> { + let table_idx = self.module.resolve_table_addr(table_index); + let table = self.store.get_table(table_idx)?; + let val = self.stack.values.pop()?.into(); + let idx = self.stack.values.pop()?.into(); table.borrow_mut().set(idx, val)?; Ok(()) } #[inline(always)] - fn exec_table_size( - &self, - table_index: u32, - stack: &mut Stack, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { - let table_idx = module.resolve_table_addr(table_index); - let table = store.get_table(table_idx)?; - stack.values.push(table.borrow().size().into()); + fn exec_table_size(&mut self, table_index: u32) -> Result<()> { + let table_idx = self.module.resolve_table_addr(table_index); + let table = self.store.get_table(table_idx)?; + self.stack.values.push(table.borrow().size().into()); Ok(()) } #[inline(always)] - fn exec_table_init(&self, elem_index: u32, table_index: u32, store: &Store, module: &ModuleInstance) -> Result<()> { - let table_idx = module.resolve_table_addr(table_index); - let table = store.get_table(table_idx)?; - let elem = store.get_elem(module.resolve_elem_addr(elem_index))?; + fn exec_table_init(&self, elem_index: u32, table_index: u32) -> Result<()> { + let table_idx = self.module.resolve_table_addr(table_index); + let table = self.store.get_table(table_idx)?; + let elem = self.store.get_elem(self.module.resolve_elem_addr(elem_index))?; if let ElementKind::Passive = elem.kind { return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); @@ -496,56 +497,42 @@ impl InterpreterRuntime { return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); }; - table.borrow_mut().init(module.func_addrs(), 0, items)?; + table.borrow_mut().init(self.module.func_addrs(), 0, items)?; Ok(()) } #[inline(always)] - fn exec_select(&self, stack: &mut Stack) -> Result<()> { - let cond: i32 = stack.values.pop()?.into(); - let val2 = stack.values.pop()?; + fn exec_select(&mut self) -> Result<()> { + let cond: i32 = self.stack.values.pop()?.into(); + let val2 = self.stack.values.pop()?; // if cond != 0, we already have the right value on the stack if cond == 0 { - *stack.values.last_mut()? = val2; + *self.stack.values.last_mut()? = val2; } Ok(()) } #[inline(always)] - fn exec_memory_size( - &self, - addr: u32, - byte: u8, - stack: &mut Stack, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { + fn exec_memory_size(&mut self, addr: u32, byte: u8) -> Result<()> { if unlikely(byte != 0) { return Err(Error::UnsupportedFeature("memory.size with byte != 0".to_string())); } - let mem_idx = module.resolve_mem_addr(addr); - let mem = store.get_mem(mem_idx)?; - stack.values.push((mem.borrow().page_count() as i32).into()); + let mem_idx = self.module.resolve_mem_addr(addr); + let mem = self.store.get_mem(mem_idx)?; + self.stack.values.push((mem.borrow().page_count() as i32).into()); Ok(()) } #[inline(always)] - fn exec_memory_grow( - &self, - addr: u32, - byte: u8, - stack: &mut Stack, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { + fn exec_memory_grow(&mut self, addr: u32, byte: u8) -> Result<()> { if unlikely(byte != 0) { return Err(Error::UnsupportedFeature("memory.grow with byte != 0".to_string())); } - let mut mem = store.get_mem(module.resolve_mem_addr(addr))?.borrow_mut(); + let mut mem = self.store.get_mem(self.module.resolve_mem_addr(addr))?.borrow_mut(); let prev_size = mem.page_count() as i32; - let pages_delta = stack.values.last_mut()?; + let pages_delta = self.stack.values.last_mut()?; *pages_delta = match mem.grow(i32::from(*pages_delta)) { Some(_) => prev_size.into(), None => (-1).into(), @@ -555,56 +542,42 @@ impl InterpreterRuntime { } #[inline(always)] - fn exec_memory_copy( - &self, - from: u32, - to: u32, - stack: &mut Stack, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { - let size: i32 = stack.values.pop()?.into(); - let src: i32 = stack.values.pop()?.into(); - let dst: i32 = stack.values.pop()?.into(); + fn exec_memory_copy(&mut self, from: u32, to: u32) -> Result<()> { + let size: i32 = self.stack.values.pop()?.into(); + let src: i32 = self.stack.values.pop()?.into(); + let dst: i32 = self.stack.values.pop()?.into(); if from == to { - let mut mem_from = store.get_mem(module.resolve_mem_addr(from))?.borrow_mut(); + let mut mem_from = self.store.get_mem(self.module.resolve_mem_addr(from))?.borrow_mut(); // copy within the same memory mem_from.copy_within(dst as usize, src as usize, size as usize)?; } else { // copy between two memories - let mem_from = store.get_mem(module.resolve_mem_addr(from))?.borrow(); - let mut mem_to = store.get_mem(module.resolve_mem_addr(to))?.borrow_mut(); + let mem_from = self.store.get_mem(self.module.resolve_mem_addr(from))?.borrow(); + let mut mem_to = self.store.get_mem(self.module.resolve_mem_addr(to))?.borrow_mut(); mem_to.copy_from_slice(dst as usize, mem_from.load(src as usize, size as usize)?)?; } Ok(()) } #[inline(always)] - fn exec_memory_fill(&self, addr: u32, stack: &mut Stack, store: &Store, module: &ModuleInstance) -> Result<()> { - let size: i32 = stack.values.pop()?.into(); - let val: i32 = stack.values.pop()?.into(); - let dst: i32 = stack.values.pop()?.into(); + fn exec_memory_fill(&mut self, addr: u32) -> Result<()> { + let size: i32 = self.stack.values.pop()?.into(); + let val: i32 = self.stack.values.pop()?.into(); + let dst: i32 = self.stack.values.pop()?.into(); - let mem = store.get_mem(module.resolve_mem_addr(addr))?; + let mem = self.store.get_mem(self.module.resolve_mem_addr(addr))?; mem.borrow_mut().fill(dst as usize, size as usize, val as u8)?; Ok(()) } #[inline(always)] - fn exec_memory_init( - &self, - data_index: u32, - mem_index: u32, - stack: &mut Stack, - store: &Store, - module: &ModuleInstance, - ) -> Result<()> { - let size = i32::from(stack.values.pop()?) as usize; - let offset = i32::from(stack.values.pop()?) as usize; - let dst = i32::from(stack.values.pop()?) as usize; + fn exec_memory_init(&mut self, data_index: u32, mem_index: u32) -> Result<()> { + let size = i32::from(self.stack.values.pop()?) as usize; + let offset = i32::from(self.stack.values.pop()?) as usize; + let dst = i32::from(self.stack.values.pop()?) as usize; - let data = match &store.get_data(module.resolve_data_addr(data_index))?.data { + let data = match &self.store.get_data(self.module.resolve_data_addr(data_index))?.data { Some(data) => data, None => return Err(Trap::MemoryOutOfBounds { offset: 0, len: 0, max: 0 }.into()), }; @@ -613,56 +586,47 @@ impl InterpreterRuntime { return Err(Trap::MemoryOutOfBounds { offset, len: size, max: data.len() }.into()); } - let mem = store.get_mem(module.resolve_mem_addr(mem_index))?; + let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_index))?; mem.borrow_mut().store(dst, size, &data[offset..(offset + size)])?; Ok(()) } #[inline(always)] - fn exec_call( - &self, - v: u32, - store: &mut Store, - stack: &mut Stack, - cf: &mut CallFrame, - module: &mut ModuleInstance, - ) -> Result<()> { - let func_inst = store.get_func(module.resolve_func_addr(v))?; + fn exec_data_drop(&mut self, data_index: u32) -> Result<()> { + self.store.get_data_mut(self.module.resolve_data_addr(data_index))?.drop(); + Ok(()) + } + + #[inline(always)] + fn exec_call(&mut self, v: u32) -> Result<()> { + let func_inst = self.store.get_func(self.module.resolve_func_addr(v))?; let wasm_func = match &func_inst.func { crate::Function::Wasm(wasm_func) => wasm_func, crate::Function::Host(host_func) => { let func = &host_func.clone(); - let params = stack.values.pop_params(&host_func.ty.params)?; - let res = (func.func)(FuncContext { store, module_addr: module.id() }, ¶ms)?; - stack.values.extend_from_typed(&res); - cf.instr_ptr += 1; + let params = self.stack.values.pop_params(&host_func.ty.params)?; + let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; + self.stack.values.extend_from_typed(&res); + self.cf.instr_ptr += 1; return Ok(()); } }; - let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?; - let new_call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32); + let params = self.stack.values.pop_n_rev(wasm_func.ty.params.len())?; + let new_call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, self.stack.blocks.len() as u32); - cf.instr_ptr += 1; // skip the call instruction - stack.call_stack.push(core::mem::replace(cf, new_call_frame))?; - if cf.module_addr != module.id() { - module.swap_with(cf.module_addr, store); + self.cf.instr_ptr += 1; // skip the call instruction + self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; + if self.cf.module_addr != self.module.id() { + self.module.swap_with(self.cf.module_addr, self.store); } Ok(()) } #[inline(always)] - fn exec_call_indirect( - &self, - type_addr: u32, - table_addr: u32, - store: &mut Store, - stack: &mut Stack, - cf: &mut CallFrame, - module: &mut ModuleInstance, - ) -> Result<()> { - let table = store.get_table(module.resolve_table_addr(table_addr))?; - let table_idx: u32 = stack.values.pop()?.into(); + fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<()> { + let table = self.store.get_table(self.module.resolve_table_addr(table_addr))?; + let table_idx: u32 = self.stack.values.pop()?.into(); // verify that the table is of the right type, this should be validated by the parser already let func_ref = { @@ -671,8 +635,8 @@ impl InterpreterRuntime { table.get(table_idx)?.addr().ok_or(Trap::UninitializedElement { index: table_idx as usize })? }; - let func_inst = store.get_func(func_ref)?.clone(); - let call_ty = module.func_ty(type_addr); + let func_inst = self.store.get_func(func_ref)?.clone(); + let call_ty = self.module.func_ty(type_addr); let wasm_func = match func_inst.func { crate::Function::Wasm(ref f) => f, @@ -686,11 +650,10 @@ impl InterpreterRuntime { } let host_func = host_func.clone(); - let params = stack.values.pop_params(&host_func.ty.params)?; - let res = (host_func.func)(FuncContext { store, module_addr: module.id() }, ¶ms)?; - stack.values.extend_from_typed(&res); - - cf.instr_ptr += 1; + let params = self.stack.values.pop_params(&host_func.ty.params)?; + let res = (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms)?; + self.stack.values.extend_from_typed(&res); + self.cf.instr_ptr += 1; return Ok(()); } }; @@ -701,72 +664,54 @@ impl InterpreterRuntime { ); } - let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?; - let new_call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32); + let params = self.stack.values.pop_n_rev(wasm_func.ty.params.len())?; + let new_call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, self.stack.blocks.len() as u32); - cf.instr_ptr += 1; // skip the call instruction - stack.call_stack.push(core::mem::replace(cf, new_call_frame))?; - if cf.module_addr != module.id() { - module.swap_with(cf.module_addr, store); + self.cf.instr_ptr += 1; // skip the call instruction + self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; + if self.cf.module_addr != self.module.id() { + self.module.swap_with(self.cf.module_addr, self.store); } Ok(()) } #[inline(always)] - fn exec_if( - &self, - args: BlockArgs, - else_offset: u32, - end_offset: u32, - stack: &mut Stack, - cf: &mut CallFrame, - module: &mut ModuleInstance, - ) -> Result<()> { + fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<()> { // truthy value is on the top of the stack, so enter the then block - if i32::from(stack.values.pop()?) != 0 { - self.enter_block(stack, cf.instr_ptr, end_offset, BlockType::If, &args, module); - cf.instr_ptr += 1; + if i32::from(self.stack.values.pop()?) != 0 { + self.enter_block(self.cf.instr_ptr, end_offset, BlockType::If, args); + self.cf.instr_ptr += 1; return Ok(()); } // falsy value is on the top of the stack if else_offset == 0 { - cf.instr_ptr += end_offset as usize + 1; + self.cf.instr_ptr += end_offset as usize + 1; return Ok(()); } - let old = cf.instr_ptr; - cf.instr_ptr += else_offset as usize; - - self.enter_block(stack, old + else_offset as usize, end_offset - else_offset, BlockType::Else, &args, module); - - cf.instr_ptr += 1; + let old = self.cf.instr_ptr; + self.cf.instr_ptr += else_offset as usize; + self.enter_block(old + else_offset as usize, end_offset - else_offset, BlockType::Else, args); + self.cf.instr_ptr += 1; Ok(()) } #[inline(always)] - fn enter_block( - &self, - stack: &mut super::Stack, - instr_ptr: usize, - end_instr_offset: u32, - ty: BlockType, - args: &BlockArgs, - module: &ModuleInstance, - ) { + fn enter_block(&mut self, instr_ptr: usize, end_instr_offset: u32, ty: BlockType, args: BlockArgs) { let (params, results) = match args { BlockArgs::Empty => (0, 0), BlockArgs::Type(_) => (0, 1), BlockArgs::FuncType(t) => { - let ty = module.func_ty(*t); + let ty = self.module.func_ty(t); (ty.params.len() as u8, ty.results.len() as u8) } }; - stack.blocks.push(BlockFrame { + self.stack.blocks.push(BlockFrame { instr_ptr, end_instr_offset, - stack_ptr: stack.values.len() as u32 - params as u32, + stack_ptr: self.stack.values.len() as u32 - params as u32, results, params, ty, diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index 1573a5d..87522df 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -73,6 +73,11 @@ impl ValueStack { self.stack.push(value); } + #[inline(always)] + pub(crate) fn extend_from_slice(&mut self, values: &[RawWasmValue]) { + self.stack.extend_from_slice(values); + } + #[inline] pub(crate) fn last_mut(&mut self) -> Result<&mut RawWasmValue> { match self.stack.last_mut() { |
