summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2024-05-23 22:48:03 +0200
committerHenry Gressmann <mail@henrygressmann.de>2024-05-23 22:48:03 +0200
commit6c2c6b2ae229dfee35a3d6d65b11d5c4ad1f1fb5 (patch)
tree9bc1d5b7fb930920b4db45b537fab5630c299d3b /crates
parent919367200e482448d7511dc6eb6660cd61e76ef4 (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.rs89
-rw-r--r--crates/tinywasm/src/runtime/interpreter/mod.rs897
-rw-r--r--crates/tinywasm/src/runtime/stack/value_stack.rs5
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() }, &params)?;
- 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() }, &params)?;
+ 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() }, &params)?;
- 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() }, &params)?;
+ 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() {