summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/conversion.rs18
-rw-r--r--crates/parser/src/lib.rs2
-rw-r--r--crates/parser/src/module.rs22
-rw-r--r--crates/parser/src/visit.rs33
-rw-r--r--crates/tinywasm/benches/argon2id.rs2
-rw-r--r--crates/tinywasm/src/error.rs27
-rw-r--r--crates/tinywasm/src/func.rs4
-rw-r--r--crates/tinywasm/src/imports.rs12
-rw-r--r--crates/tinywasm/src/instance.rs41
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs872
-rw-r--r--crates/tinywasm/src/interpreter/num_helpers.rs51
-rw-r--r--crates/tinywasm/src/interpreter/stack/block_stack.rs12
-rw-r--r--crates/tinywasm/src/interpreter/stack/call_stack.rs50
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs155
-rw-r--r--crates/tinywasm/src/interpreter/values.rs63
-rw-r--r--crates/tinywasm/src/reference.rs2
-rw-r--r--crates/tinywasm/src/store/memory.rs23
-rw-r--r--crates/tinywasm/src/store/mod.rs87
-rw-r--r--crates/tinywasm/tests/testsuite/run.rs4
-rw-r--r--crates/types/src/instructions.rs13
-rw-r--r--crates/types/src/lib.rs24
21 files changed, 739 insertions, 778 deletions
diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs
index 214487f..c733dcc 100644
--- a/crates/parser/src/conversion.rs
+++ b/crates/parser/src/conversion.rs
@@ -176,7 +176,7 @@ pub(crate) fn convert_module_code(
// maps a local's address to the index in the type's locals array
let mut local_addr_map = Vec::with_capacity(count as usize);
- let mut local_counts = LocalCounts::default();
+ let mut local_counts = ValueCounts::default();
for (i, local) in locals_reader.into_iter().enumerate() {
let local = local?;
@@ -186,20 +186,20 @@ pub(crate) fn convert_module_code(
for i in 0..validator.len_locals() {
match validator.get_local_type(i) {
Some(wasmparser::ValType::I32) | Some(wasmparser::ValType::F32) => {
- local_addr_map.push(local_counts.local_32);
- local_counts.local_32 += 1;
+ local_addr_map.push(local_counts.c32);
+ local_counts.c32 += 1;
}
Some(wasmparser::ValType::I64) | Some(wasmparser::ValType::F64) => {
- local_addr_map.push(local_counts.local_64);
- local_counts.local_64 += 1;
+ local_addr_map.push(local_counts.c64);
+ local_counts.c64 += 1;
}
Some(wasmparser::ValType::V128) => {
- local_addr_map.push(local_counts.local_128);
- local_counts.local_128 += 1;
+ local_addr_map.push(local_counts.c128);
+ local_counts.c128 += 1;
}
Some(wasmparser::ValType::Ref(_)) => {
- local_addr_map.push(local_counts.local_ref);
- local_counts.local_ref += 1;
+ local_addr_map.push(local_counts.cref);
+ local_counts.cref += 1;
}
None => return Err(crate::ParseError::UnsupportedOperator("Unknown local type".to_string())),
}
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 77349b2..40f5fe2 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -59,6 +59,7 @@ impl Parser {
sign_extension: true,
saturating_float_to_int: true,
function_references: true,
+ tail_call: true,
component_model: false,
component_model_nested_names: false,
@@ -71,7 +72,6 @@ impl Parser {
memory_control: false,
relaxed_simd: false,
simd: false,
- tail_call: false,
threads: false,
multi_memory: false, // should be working mostly
custom_page_sizes: false,
diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs
index 3ee619f..74da1d9 100644
--- a/crates/parser/src/module.rs
+++ b/crates/parser/src/module.rs
@@ -3,12 +3,12 @@ use crate::{conversion, ParseError, Result};
use alloc::string::ToString;
use alloc::{boxed::Box, format, vec::Vec};
use tinywasm_types::{
- Data, Element, Export, FuncType, Global, Import, Instruction, LocalCounts, MemoryType, TableType, TinyWasmModule,
- WasmFunction,
+ Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, TinyWasmModule, ValType,
+ ValueCounts, ValueCountsSmall, WasmFunction,
};
use wasmparser::{FuncValidatorAllocations, Payload, Validator};
-pub(crate) type Code = (Box<[Instruction]>, LocalCounts);
+pub(crate) type Code = (Box<[Instruction]>, ValueCounts);
#[derive(Default)]
pub(crate) struct ModuleReader {
@@ -193,10 +193,18 @@ impl ModuleReader {
.code
.into_iter()
.zip(self.code_type_addrs)
- .map(|((instructions, locals), ty_idx)| WasmFunction {
- instructions,
- locals,
- ty: self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone(),
+ .map(|((instructions, locals), ty_idx)| {
+ let mut params = ValueCountsSmall::default();
+ let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone();
+ for param in ty.params.iter() {
+ match param {
+ ValType::I32 | ValType::F32 => params.c32 += 1,
+ ValType::I64 | ValType::F64 => params.c64 += 1,
+ ValType::V128 => params.c128 += 1,
+ ValType::RefExtern | ValType::RefFunc => params.cref += 1,
+ }
+ }
+ WasmFunction { instructions, params, locals, ty }
})
.collect::<Vec<_>>()
.into_boxed_slice();
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index e9844aa..1f282f7 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -122,6 +122,7 @@ macro_rules! impl_visit_operator {
(@@sign_extension $($rest:tt)* ) => {};
(@@saturating_float_to_int $($rest:tt)* ) => {};
(@@bulk_memory $($rest:tt)* ) => {};
+ (@@tail_call $($rest:tt)* ) => {};
(@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {
#[cold]
fn $visit(&mut self $($(,$arg: $argty)*)?) {
@@ -317,6 +318,14 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U
}
+ fn visit_return_call(&mut self, function_index: u32) -> Self::Output {
+ self.instructions.push(Instruction::ReturnCall(function_index));
+ }
+
+ fn visit_return_call_indirect(&mut self, type_index: u32, table_index: u32) -> Self::Output {
+ self.instructions.push(Instruction::ReturnCallIndirect(type_index, table_index));
+ }
+
fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
@@ -385,6 +394,30 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
return;
};
+ match self.instructions.last() {
+ Some(Instruction::LocalGet32(from))
+ | Some(Instruction::LocalGet64(from))
+ | Some(Instruction::LocalGet128(from))
+ | Some(Instruction::LocalGetRef(from)) => {
+ let from = *from;
+ self.instructions.pop();
+ // validation will ensure that the last instruction is the correct local.get
+ match self.validator.get_operand_type(0) {
+ Some(Some(t)) => self.instructions.push(match t {
+ wasmparser::ValType::I32 => Instruction::LocalCopy32(from, resolved_idx),
+ wasmparser::ValType::F32 => Instruction::LocalCopy32(from, resolved_idx),
+ wasmparser::ValType::I64 => Instruction::LocalCopy64(from, resolved_idx),
+ wasmparser::ValType::F64 => Instruction::LocalCopy64(from, resolved_idx),
+ wasmparser::ValType::V128 => Instruction::LocalCopy128(from, resolved_idx),
+ wasmparser::ValType::Ref(_) => Instruction::LocalCopyRef(from, resolved_idx),
+ }),
+ _ => self.visit_unreachable(),
+ }
+ return;
+ }
+ _ => {}
+ }
+
match self.validator.get_operand_type(0) {
Some(Some(t)) => self.instructions.push(match t {
wasmparser::ValType::I32 => Instruction::LocalSet32(resolved_idx),
diff --git a/crates/tinywasm/benches/argon2id.rs b/crates/tinywasm/benches/argon2id.rs
index d87c78e..b951a56 100644
--- a/crates/tinywasm/benches/argon2id.rs
+++ b/crates/tinywasm/benches/argon2id.rs
@@ -25,7 +25,7 @@ fn argon2id_run(module: TinyWasmModule) -> Result<()> {
let mut store = Store::default();
let instance = ModuleInstance::instantiate(&mut store, module.into(), None)?;
let argon2 = instance.exported_func::<(i32, i32, i32), i32>(&store, "argon2id")?;
- argon2.call(&mut store, (1000, 1, 1))?;
+ argon2.call(&mut store, (1000, 2, 1))?;
Ok(())
}
diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs
index 0c698fa..c2413a1 100644
--- a/crates/tinywasm/src/error.rs
+++ b/crates/tinywasm/src/error.rs
@@ -1,5 +1,5 @@
use alloc::string::{String, ToString};
-use core::fmt::Display;
+use core::{fmt::Display, ops::ControlFlow};
use tinywasm_types::FuncType;
#[cfg(feature = "parser")]
@@ -23,15 +23,6 @@ pub enum Error {
/// A function did not return a value
FuncDidNotReturn,
- /// The stack is empty
- ValueStackUnderflow,
-
- /// The label stack is empty
- BlockStackUnderflow,
-
- /// The call stack is empty
- CallStackUnderflow,
-
/// An invalid label type was encountered
InvalidLabelType,
@@ -189,13 +180,10 @@ impl Display for Error {
Self::Trap(trap) => write!(f, "trap: {}", trap),
Self::Linker(err) => write!(f, "linking error: {}", err),
- Self::CallStackUnderflow => write!(f, "call stack empty"),
Self::InvalidLabelType => write!(f, "invalid label type"),
Self::Other(message) => write!(f, "unknown error: {}", message),
Self::UnsupportedFeature(feature) => write!(f, "unsupported feature: {}", feature),
Self::FuncDidNotReturn => write!(f, "function did not return"),
- Self::BlockStackUnderflow => write!(f, "label stack underflow"),
- Self::ValueStackUnderflow => write!(f, "value stack underflow"),
Self::InvalidStore => write!(f, "invalid store"),
}
}
@@ -249,3 +237,16 @@ impl From<tinywasm_parser::ParseError> for Error {
/// A wrapper around [`core::result::Result`] for tinywasm operations
pub type Result<T, E = Error> = crate::std::result::Result<T, E>;
+
+pub(crate) trait Controlify<T> {
+ fn to_cf(self) -> ControlFlow<Option<Error>, T>;
+}
+
+impl<T> Controlify<T> for Result<T, Error> {
+ fn to_cf(self) -> ControlFlow<Option<Error>, T> {
+ match self {
+ Ok(value) => ControlFlow::Continue(value),
+ Err(err) => ControlFlow::Break(Some(err)),
+ }
+ }
+}
diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs
index 681ca7e..f2017fe 100644
--- a/crates/tinywasm/src/func.rs
+++ b/crates/tinywasm/src/func.rs
@@ -48,7 +48,7 @@ impl FuncHandle {
return Err(Error::Other("Type mismatch".into()));
}
- let func_inst = store.get_func(self.addr)?;
+ let func_inst = store.get_func(&self.addr);
let wasm_func = match &func_inst.func {
Function::Host(host_func) => {
let func = &host_func.clone().func;
@@ -76,7 +76,7 @@ impl FuncHandle {
// assert!(stack.values.len() >= result_m);
// 2. Pop m values from the stack
- let res = stack.values.pop_results(&func_ty.results)?;
+ let res = stack.values.pop_results(&func_ty.results);
// The values are returned as the results of the invocation.
Ok(res)
diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs
index 82ae8c8..3d29dfc 100644
--- a/crates/tinywasm/src/imports.rs
+++ b/crates/tinywasm/src/imports.rs
@@ -143,8 +143,6 @@ impl Extern {
}
/// Create a new typed function import
- // TODO: currently, this is slower than `Extern::func` because of the type conversions.
- // we should be able to optimize this and make it even faster than `Extern::func`.
pub fn typed_func<P, R>(func: impl Fn(FuncContext<'_>, P) -> Result<R> + 'static) -> Self
where
P: FromWasmValueTuple + ValTypesFromTuple,
@@ -388,23 +386,23 @@ impl Imports {
match (val, &import.kind) {
(ExternVal::Global(global_addr), ImportKind::Global(ty)) => {
- let global = store.get_global(global_addr)?;
+ let global = store.get_global(&global_addr);
Self::compare_types(import, &global.ty, ty)?;
imports.globals.push(global_addr);
}
(ExternVal::Table(table_addr), ImportKind::Table(ty)) => {
- let table = store.get_table(table_addr)?;
+ let table = store.get_table(&table_addr);
Self::compare_table_types(import, &table.kind, ty)?;
imports.tables.push(table_addr);
}
(ExternVal::Memory(memory_addr), ImportKind::Memory(ty)) => {
- let mem = store.get_mem(memory_addr)?;
- let (size, kind) = { (mem.page_count(), mem.kind) };
+ let mem = store.get_mem(&memory_addr);
+ let (size, kind) = { (mem.page_count, mem.kind) };
Self::compare_memory_types(import, &kind, ty, Some(size))?;
imports.memories.push(memory_addr);
}
(ExternVal::Func(func_addr), ImportKind::Function(ty)) => {
- let func = store.get_func(func_addr)?;
+ let func = store.get_func(&func_addr);
let import_func_type = module
.0
.func_types
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index 74a1598..0f72676 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -127,45 +127,40 @@ impl ModuleInstance {
&self.0.func_addrs
}
- #[cold]
- fn not_found_error(name: &str) -> Error {
- Error::Other(format!("address for {} not found", name))
- }
-
// resolve a function address to the global store address
#[inline]
- pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> Result<FuncAddr> {
- self.0.func_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("function")).copied()
+ pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> &FuncAddr {
+ &self.0.func_addrs[addr as usize]
}
// resolve a table address to the global store address
#[inline]
- pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> Result<TableAddr> {
- self.0.table_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("table")).copied()
+ pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> &TableAddr {
+ &self.0.table_addrs[addr as usize]
}
// resolve a memory address to the global store address
#[inline]
- pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> Result<MemAddr> {
- self.0.mem_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("mem")).copied()
+ pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> &MemAddr {
+ &self.0.mem_addrs[addr as usize]
}
// resolve a data address to the global store address
#[inline]
- pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> Result<DataAddr> {
- self.0.data_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("data")).copied()
+ pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> &DataAddr {
+ &self.0.data_addrs[addr as usize]
}
// resolve a memory address to the global store address
#[inline]
- pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> Result<ElemAddr> {
- self.0.elem_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("elem")).copied()
+ pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> &ElemAddr {
+ &self.0.elem_addrs[addr as usize]
}
// resolve a global address to the global store address
#[inline]
- pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> Result<GlobalAddr> {
- self.0.global_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("global")).copied()
+ pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> &GlobalAddr {
+ &self.0.global_addrs[addr as usize]
}
/// Get an exported function by name
@@ -179,9 +174,7 @@ impl ModuleInstance {
return Err(Error::Other(format!("Export is not a function: {}", name)));
};
- let func_inst = store.get_func(func_addr)?;
- let ty = func_inst.func.ty();
-
+ let ty = store.get_func(&func_addr).func.ty();
Ok(FuncHandle { addr: func_addr, module_addr: self.id(), name: Some(name.to_string()), ty: ty.clone() })
}
@@ -217,13 +210,13 @@ impl ModuleInstance {
/// Get a memory by address
pub fn memory<'a>(&self, store: &'a Store, addr: MemAddr) -> Result<MemoryRef<'a>> {
- let mem = store.get_mem(self.resolve_mem_addr(addr)?)?;
+ let mem = store.get_mem(self.resolve_mem_addr(addr));
Ok(MemoryRef(mem))
}
/// Get a memory by address (mutable)
pub fn memory_mut<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result<MemoryRefMut<'a>> {
- let mem = store.get_mem_mut(self.resolve_mem_addr(addr)?)?;
+ let mem = store.get_mem_mut(self.resolve_mem_addr(addr));
Ok(MemoryRefMut(mem))
}
@@ -250,8 +243,8 @@ impl ModuleInstance {
}
};
- let func_addr = self.0.func_addrs.get(func_index as usize).expect("No func addr for start func, this is a bug");
- let func_inst = store.get_func(*func_addr)?;
+ let func_addr = self.resolve_func_addr(func_index);
+ let func_inst = store.get_func(func_addr);
let ty = func_inst.func.ty();
Ok(Some(FuncHandle { module_addr: self.id(), addr: *func_addr, ty: ty.clone(), name: None }))
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index 353f778..a9516f0 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -21,7 +21,7 @@ pub(super) struct Executor<'store, 'stack> {
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().ok_or_else(|| Error::CallStackUnderflow)?;
+ let current_frame = stack.call_stack.pop().expect("no call frame, this is a bug");
let current_module = store.get_module_instance_raw(current_frame.module_addr());
Ok(Self { cf: current_frame, module: current_module, stack, store })
}
@@ -29,329 +29,249 @@ impl<'store, 'stack> Executor<'store, 'stack> {
#[inline]
pub(crate) fn run_to_completion(&mut self) -> Result<()> {
loop {
- // TODO: the result checking takes about 10% of the time
- match self.exec_next()? {
- ControlFlow::Break(..) => return Ok(()),
- ControlFlow::Continue(..) => continue,
- };
+ if let ControlFlow::Break(res) = self.exec_next() {
+ return match res {
+ Some(e) => Err(e),
+ None => Ok(()),
+ };
+ }
}
}
#[inline(always)]
- fn exec_next(&mut self) -> Result<ControlFlow<()>> {
+ fn exec_next(&mut self) -> ControlFlow<Option<Error>> {
use tinywasm_types::Instruction::*;
match self.cf.fetch_instr() {
Nop => self.exec_noop(),
Unreachable => self.exec_unreachable()?,
- Drop32 => self.stack.values.drop::<Value32>()?,
- Drop64 => self.stack.values.drop::<Value64>()?,
- Drop128 => self.stack.values.drop::<Value128>()?,
- DropRef => self.stack.values.drop::<ValueRef>()?,
+ Drop32 => self.stack.values.drop::<Value32>(),
+ Drop64 => self.stack.values.drop::<Value64>(),
+ Drop128 => self.stack.values.drop::<Value128>(),
+ DropRef => self.stack.values.drop::<ValueRef>(),
- Select32 => self.stack.values.select::<Value32>()?,
- Select64 => self.stack.values.select::<Value64>()?,
- Select128 => self.stack.values.select::<Value128>()?,
- SelectRef => self.stack.values.select::<ValueRef>()?,
+ Select32 => self.stack.values.select::<Value32>(),
+ Select64 => self.stack.values.select::<Value64>(),
+ Select128 => self.stack.values.select::<Value128>(),
+ SelectRef => self.stack.values.select::<ValueRef>(),
Call(v) => return self.exec_call_direct(*v),
CallIndirect(ty, table) => return self.exec_call_indirect(*ty, *table),
- If(end, el) => self.exec_if(*end, *el, (Default::default(), Default::default()))?,
- IfWithType(ty, end, el) => self.exec_if(*end, *el, (Default::default(), (*ty).into()))?,
- IfWithFuncType(ty, end, el) => self.exec_if(*end, *el, self.resolve_functype(*ty))?,
- Else(end_offset) => self.exec_else(*end_offset)?,
- Loop(end) => {
- self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, (Default::default(), Default::default()))
- }
- LoopWithType(ty, end) => {
- self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, (Default::default(), (*ty).into()))
- }
- LoopWithFuncType(ty, end) => {
- self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, self.resolve_functype(*ty))
- }
- Block(end) => {
- self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, (Default::default(), Default::default()))
- }
- BlockWithType(ty, end) => {
- self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, (Default::default(), (*ty).into()))
- }
- BlockWithFuncType(ty, end) => {
- self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, self.resolve_functype(*ty))
- }
+ If(end, el) => self.exec_if(*end, *el, (Default::default(), Default::default())),
+ IfWithType(ty, end, el) => self.exec_if(*end, *el, (Default::default(), (*ty).into())),
+ IfWithFuncType(ty, end, el) => self.exec_if(*end, *el, self.resolve_functype(*ty)),
+ Else(end_offset) => self.exec_else(*end_offset),
+ Loop(end) => self.enter_block(*end, BlockType::Loop, (Default::default(), Default::default())),
+ LoopWithType(ty, end) => self.enter_block(*end, BlockType::Loop, (Default::default(), (*ty).into())),
+ LoopWithFuncType(ty, end) => self.enter_block(*end, BlockType::Loop, self.resolve_functype(*ty)),
+ Block(end) => self.enter_block(*end, BlockType::Block, (Default::default(), Default::default())),
+ BlockWithType(ty, end) => self.enter_block(*end, BlockType::Block, (Default::default(), (*ty).into())),
+ BlockWithFuncType(ty, end) => self.enter_block(*end, BlockType::Block, self.resolve_functype(*ty)),
Br(v) => return self.exec_br(*v),
BrIf(v) => return self.exec_br_if(*v),
BrTable(default, len) => return self.exec_brtable(*default, *len),
BrLabel(_) => {}
Return => return self.exec_return(),
- EndBlockFrame => self.exec_end_block()?,
+ EndBlockFrame => self.exec_end_block(),
- LocalGet32(local_index) => self.exec_local_get::<Value32>(*local_index)?,
- LocalGet64(local_index) => self.exec_local_get::<Value64>(*local_index)?,
- LocalGet128(local_index) => self.exec_local_get::<Value128>(*local_index)?,
- LocalGetRef(local_index) => self.exec_local_get::<ValueRef>(*local_index)?,
+ LocalGet32(local_index) => self.exec_local_get::<Value32>(*local_index),
+ LocalGet64(local_index) => self.exec_local_get::<Value64>(*local_index),
+ LocalGet128(local_index) => self.exec_local_get::<Value128>(*local_index),
+ LocalGetRef(local_index) => self.exec_local_get::<ValueRef>(*local_index),
- LocalSet32(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::<Value32>()?)?,
- LocalSet64(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::<Value64>()?)?,
- LocalSet128(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::<Value128>()?)?,
- LocalSetRef(local_index) => self.cf.locals.set(*local_index, self.stack.values.pop::<ValueRef>()?)?,
+ LocalSet32(local_index) => self.exec_local_set::<Value32>(*local_index),
+ LocalSet64(local_index) => self.exec_local_set::<Value64>(*local_index),
+ LocalSet128(local_index) => self.exec_local_set::<Value128>(*local_index),
+ LocalSetRef(local_index) => self.exec_local_set::<ValueRef>(*local_index),
- LocalTee32(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::<Value32>()?)?,
- LocalTee64(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::<Value64>()?)?,
- LocalTee128(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::<Value128>()?)?,
- LocalTeeRef(local_index) => self.cf.locals.set(*local_index, self.stack.values.peek::<ValueRef>()?)?,
+ LocalTee32(local_index) => self.exec_local_tee::<Value32>(*local_index),
+ LocalTee64(local_index) => self.exec_local_tee::<Value64>(*local_index),
+ LocalTee128(local_index) => self.exec_local_tee::<Value128>(*local_index),
+ LocalTeeRef(local_index) => self.exec_local_tee::<ValueRef>(*local_index),
- GlobalGet(global_index) => self.exec_global_get(*global_index)?,
- GlobalSet32(global_index) => self.exec_global_set::<Value32>(*global_index)?,
- GlobalSet64(global_index) => self.exec_global_set::<Value64>(*global_index)?,
- GlobalSet128(global_index) => self.exec_global_set::<Value128>(*global_index)?,
- GlobalSetRef(global_index) => self.exec_global_set::<ValueRef>(*global_index)?,
+ GlobalGet(global_index) => self.exec_global_get(*global_index),
+ GlobalSet32(global_index) => self.exec_global_set::<Value32>(*global_index),
+ GlobalSet64(global_index) => self.exec_global_set::<Value64>(*global_index),
+ GlobalSet128(global_index) => self.exec_global_set::<Value128>(*global_index),
+ GlobalSetRef(global_index) => self.exec_global_set::<ValueRef>(*global_index),
- I32Const(val) => self.stack.values.push(*val),
- I64Const(val) => self.stack.values.push(*val),
- F32Const(val) => self.stack.values.push::<i32>(val.to_bits() as i32),
- F64Const(val) => self.stack.values.push(val.to_bits() as i64),
- RefFunc(func_idx) => self.stack.values.push(Some(*func_idx)), // do we need to resolve the function index?
- RefNull(_) => self.stack.values.push(None),
- RefIsNull => self.exec_ref_is_null()?,
+ I32Const(val) => self.exec_const(*val),
+ I64Const(val) => self.exec_const(*val),
+ F32Const(val) => self.exec_const(*val),
+ F64Const(val) => self.exec_const(*val),
+ RefFunc(func_idx) => self.exec_const::<ValueRef>(Some(*func_idx)),
+ RefNull(_) => self.exec_const::<ValueRef>(None),
+ RefIsNull => self.exec_ref_is_null(),
- MemorySize(addr) => self.exec_memory_size(*addr)?,
- MemoryGrow(addr) => self.exec_memory_grow(*addr)?,
+ MemorySize(addr) => self.exec_memory_size(*addr),
+ MemoryGrow(addr) => self.exec_memory_grow(*addr),
// 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)?,
- ElemDrop(elem_index) => self.exec_elem_drop(*elem_index)?,
- TableCopy { from, to } => self.exec_table_copy(*from, *to)?,
-
- I32Store { mem_addr, offset } => {
- let v = self.stack.values.pop::<i32>()?;
- self.exec_mem_store::<i32, 4>(v, *mem_addr, *offset)?
- }
- I64Store { mem_addr, offset } => {
- let v = self.stack.values.pop::<i64>()?;
- self.exec_mem_store::<i64, 8>(v, *mem_addr, *offset)?
- }
- F32Store { mem_addr, offset } => {
- let v = self.stack.values.pop::<f32>()?;
- self.exec_mem_store::<f32, 4>(v, *mem_addr, *offset)?
- }
- F64Store { mem_addr, offset } => {
- let v = self.stack.values.pop::<f64>()?;
- self.exec_mem_store::<f64, 8>(v, *mem_addr, *offset)?
- }
- I32Store8 { mem_addr, offset } => {
- let v = self.stack.values.pop::<i32>()? as i8;
- self.exec_mem_store::<i8, 1>(v, *mem_addr, *offset)?
- }
- I32Store16 { mem_addr, offset } => {
- let v = self.stack.values.pop::<i32>()? as i16;
- self.exec_mem_store::<i16, 2>(v, *mem_addr, *offset)?
- }
- I64Store8 { mem_addr, offset } => {
- let v = self.stack.values.pop::<i64>()? as i8;
- self.exec_mem_store::<i8, 1>(v, *mem_addr, *offset)?
- }
- I64Store16 { mem_addr, offset } => {
- let v = self.stack.values.pop::<i64>()? as i16;
- self.exec_mem_store::<i16, 2>(v, *mem_addr, *offset)?
- }
- I64Store32 { mem_addr, offset } => {
- let v = self.stack.values.pop::<i64>()? as i32;
- self.exec_mem_store::<i32, 4>(v, *mem_addr, *offset)?
- }
+ MemoryCopy(from, to) => self.exec_memory_copy(*from, *to).to_cf()?,
+ MemoryFill(addr) => self.exec_memory_fill(*addr).to_cf()?,
+ MemoryInit(data_idx, mem_idx) => self.exec_memory_init(*data_idx, *mem_idx).to_cf()?,
+ DataDrop(data_index) => self.exec_data_drop(*data_index),
+ ElemDrop(elem_index) => self.exec_elem_drop(*elem_index),
+ TableCopy { from, to } => self.exec_table_copy(*from, *to).to_cf()?,
- I32Load { mem_addr, offset } => self.exec_mem_load::<i32, 4, _>(|v| v, *mem_addr, *offset)?,
- I64Load { mem_addr, offset } => self.exec_mem_load::<i64, 8, _>(|v| v, *mem_addr, *offset)?,
- F32Load { mem_addr, offset } => self.exec_mem_load::<f32, 4, _>(|v| v, *mem_addr, *offset)?,
- F64Load { mem_addr, offset } => self.exec_mem_load::<f64, 8, _>(|v| v, *mem_addr, *offset)?,
- I32Load8S { mem_addr, offset } => self.exec_mem_load::<i8, 1, _>(|v| v as i32, *mem_addr, *offset)?,
- I32Load8U { mem_addr, offset } => self.exec_mem_load::<u8, 1, _>(|v| v as i32, *mem_addr, *offset)?,
- I32Load16S { mem_addr, offset } => self.exec_mem_load::<i16, 2, _>(|v| v as i32, *mem_addr, *offset)?,
- I32Load16U { mem_addr, offset } => self.exec_mem_load::<u16, 2, _>(|v| v as i32, *mem_addr, *offset)?,
- I64Load8S { mem_addr, offset } => self.exec_mem_load::<i8, 1, _>(|v| v as i64, *mem_addr, *offset)?,
- I64Load8U { mem_addr, offset } => self.exec_mem_load::<u8, 1, _>(|v| v as i64, *mem_addr, *offset)?,
- I64Load16S { mem_addr, offset } => self.exec_mem_load::<i16, 2, _>(|v| v as i64, *mem_addr, *offset)?,
- I64Load16U { mem_addr, offset } => self.exec_mem_load::<u16, 2, _>(|v| v as i64, *mem_addr, *offset)?,
- I64Load32S { mem_addr, offset } => self.exec_mem_load::<i32, 4, _>(|v| v as i64, *mem_addr, *offset)?,
- I64Load32U { mem_addr, offset } => self.exec_mem_load::<u32, 4, _>(|v| v as i64, *mem_addr, *offset)?,
+ I32Store { mem_addr, offset } => self.exec_mem_store::<i32, i32, 4>(*mem_addr, *offset, |v| v)?,
+ I64Store { mem_addr, offset } => self.exec_mem_store::<i64, i64, 8>(*mem_addr, *offset, |v| v)?,
+ F32Store { mem_addr, offset } => self.exec_mem_store::<f32, f32, 4>(*mem_addr, *offset, |v| v)?,
+ F64Store { mem_addr, offset } => self.exec_mem_store::<f64, f64, 8>(*mem_addr, *offset, |v| v)?,
+ I32Store8 { mem_addr, offset } => self.exec_mem_store::<i32, i8, 1>(*mem_addr, *offset, |v| v as i8)?,
+ I32Store16 { mem_addr, offset } => self.exec_mem_store::<i32, i16, 2>(*mem_addr, *offset, |v| v as i16)?,
+ I64Store8 { mem_addr, offset } => self.exec_mem_store::<i64, i8, 1>(*mem_addr, *offset, |v| v as i8)?,
+ I64Store16 { mem_addr, offset } => self.exec_mem_store::<i64, i16, 2>(*mem_addr, *offset, |v| v as i16)?,
+ I64Store32 { mem_addr, offset } => self.exec_mem_store::<i64, i32, 4>(*mem_addr, *offset, |v| v as i32)?,
- I64Eqz => self.stack.values.replace_top::<i64, _>(|v| Ok((v == 0) as i32))?,
- I32Eqz => self.stack.values.replace_top::<i32, _>(|v| Ok((v == 0) as i32))?,
- I32Eq => self.stack.values.calculate::<i32, _>(|a, b| Ok((a == b) as i32))?,
- I64Eq => self.stack.values.calculate::<i64, _>(|a, b| Ok((a == b) as i32))?,
- F32Eq => self.stack.values.calculate::<f32, _>(|a, b| Ok((a == b) as i32))?,
- F64Eq => self.stack.values.calculate::<f64, _>(|a, b| Ok((a == b) as i32))?,
+ I32Load { mem_addr, offset } => self.exec_mem_load::<i32, 4, _>(*mem_addr, *offset, |v| v)?,
+ I64Load { mem_addr, offset } => self.exec_mem_load::<i64, 8, _>(*mem_addr, *offset, |v| v)?,
+ F32Load { mem_addr, offset } => self.exec_mem_load::<f32, 4, _>(*mem_addr, *offset, |v| v)?,
+ F64Load { mem_addr, offset } => self.exec_mem_load::<f64, 8, _>(*mem_addr, *offset, |v| v)?,
+ I32Load8S { mem_addr, offset } => self.exec_mem_load::<i8, 1, _>(*mem_addr, *offset, |v| v as i32)?,
+ I32Load8U { mem_addr, offset } => self.exec_mem_load::<u8, 1, _>(*mem_addr, *offset, |v| v as i32)?,
+ I32Load16S { mem_addr, offset } => self.exec_mem_load::<i16, 2, _>(*mem_addr, *offset, |v| v as i32)?,
+ I32Load16U { mem_addr, offset } => self.exec_mem_load::<u16, 2, _>(*mem_addr, *offset, |v| v as i32)?,
+ I64Load8S { mem_addr, offset } => self.exec_mem_load::<i8, 1, _>(*mem_addr, *offset, |v| v as i64)?,
+ I64Load8U { mem_addr, offset } => self.exec_mem_load::<u8, 1, _>(*mem_addr, *offset, |v| v as i64)?,
+ I64Load16S { mem_addr, offset } => self.exec_mem_load::<i16, 2, _>(*mem_addr, *offset, |v| v as i64)?,
+ I64Load16U { mem_addr, offset } => self.exec_mem_load::<u16, 2, _>(*mem_addr, *offset, |v| v as i64)?,
+ I64Load32S { mem_addr, offset } => self.exec_mem_load::<i32, 4, _>(*mem_addr, *offset, |v| v as i64)?,
+ I64Load32U { mem_addr, offset } => self.exec_mem_load::<u32, 4, _>(*mem_addr, *offset, |v| v as i64)?,
- I32Ne => self.stack.values.calculate::<i32, _>(|a, b| Ok((a != b) as i32))?,
- I64Ne => self.stack.values.calculate::<i64, _>(|a, b| Ok((a != b) as i32))?,
- F32Ne => self.stack.values.calculate::<f32, _>(|a, b| Ok((a != b) as i32))?,
- F64Ne => self.stack.values.calculate::<f64, _>(|a, b| Ok((a != b) as i32))?,
+ I64Eqz => self.stack.values.replace_top::<i64, _>(|v| Ok((v == 0) as i32)).to_cf()?,
+ I32Eqz => self.stack.values.replace_top_same::<i32>(|v| Ok((v == 0) as i32)).to_cf()?,
+ I32Eq => self.stack.values.calculate_same::<i32>(|a, b| Ok((a == b) as i32)).to_cf()?,
+ I64Eq => self.stack.values.calculate::<i64, _>(|a, b| Ok((a == b) as i32)).to_cf()?,
+ F32Eq => self.stack.values.calculate::<f32, _>(|a, b| Ok((a == b) as i32)).to_cf()?,
+ F64Eq => self.stack.values.calculate::<f64, _>(|a, b| Ok((a == b) as i32)).to_cf()?,
- I32LtS => self.stack.values.calculate::<i32, _>(|a, b| Ok((a < b) as i32))?,
- I64LtS => self.stack.values.calculate::<i64, _>(|a, b| Ok((a < b) as i32))?,
- I32LtU => self.stack.values.calculate::<u32, _>(|a, b| Ok((a < b) as i32))?,
- I64LtU => self.stack.values.calculate::<u64, _>(|a, b| Ok((a < b) as i32))?,
- F32Lt => self.stack.values.calculate::<f32, _>(|a, b| Ok((a < b) as i32))?,
- F64Lt => self.stack.values.calculate::<f64, _>(|a, b| Ok((a < b) as i32))?,
+ I32Ne => self.stack.values.calculate_same::<i32>(|a, b| Ok((a != b) as i32)).to_cf()?,
+ I64Ne => self.stack.values.calculate::<i64, _>(|a, b| Ok((a != b) as i32)).to_cf()?,
+ F32Ne => self.stack.values.calculate::<f32, _>(|a, b| Ok((a != b) as i32)).to_cf()?,
+ F64Ne => self.stack.values.calculate::<f64, _>(|a, b| Ok((a != b) as i32)).to_cf()?,
- I32LeS => self.stack.values.calculate::<i32, _>(|a, b| Ok((a <= b) as i32))?,
- I64LeS => self.stack.values.calculate::<i64, _>(|a, b| Ok((a <= b) as i32))?,
- I32LeU => self.stack.values.calculate::<u32, _>(|a, b| Ok((a <= b) as i32))?,
- I64LeU => self.stack.values.calculate::<u64, _>(|a, b| Ok((a <= b) as i32))?,
- F32Le => self.stack.values.calculate::<f32, _>(|a, b| Ok((a <= b) as i32))?,
- F64Le => self.stack.values.calculate::<f64, _>(|a, b| Ok((a <= b) as i32))?,
+ I32LtS => self.stack.values.calculate_same::<i32>(|a, b| Ok((a < b) as i32)).to_cf()?,
+ I64LtS => self.stack.values.calculate::<i64, _>(|a, b| Ok((a < b) as i32)).to_cf()?,
+ I32LtU => self.stack.values.calculate::<u32, _>(|a, b| Ok((a < b) as i32)).to_cf()?,
+ I64LtU => self.stack.values.calculate::<u64, _>(|a, b| Ok((a < b) as i32)).to_cf()?,
+ F32Lt => self.stack.values.calculate::<f32, _>(|a, b| Ok((a < b) as i32)).to_cf()?,
+ F64Lt => self.stack.values.calculate::<f64, _>(|a, b| Ok((a < b) as i32)).to_cf()?,
- I32GeS => self.stack.values.calculate::<i32, _>(|a, b| Ok((a >= b) as i32))?,
- I64GeS => self.stack.values.calculate::<i64, _>(|a, b| Ok((a >= b) as i32))?,
- I32GeU => self.stack.values.calculate::<u32, _>(|a, b| Ok((a >= b) as i32))?,
- I64GeU => self.stack.values.calculate::<u64, _>(|a, b| Ok((a >= b) as i32))?,
- F32Ge => self.stack.values.calculate::<f32, _>(|a, b| Ok((a >= b) as i32))?,
- F64Ge => self.stack.values.calculate::<f64, _>(|a, b| Ok((a >= b) as i32))?,
+ I32LeS => self.stack.values.calculate_same::<i32>(|a, b| Ok((a <= b) as i32)).to_cf()?,
+ I64LeS => self.stack.values.calculate::<i64, _>(|a, b| Ok((a <= b) as i32)).to_cf()?,
+ I32LeU => self.stack.values.calculate::<u32, _>(|a, b| Ok((a <= b) as i32)).to_cf()?,
+ I64LeU => self.stack.values.calculate::<u64, _>(|a, b| Ok((a <= b) as i32)).to_cf()?,
+ F32Le => self.stack.values.calculate::<f32, _>(|a, b| Ok((a <= b) as i32)).to_cf()?,
+ F64Le => self.stack.values.calculate::<f64, _>(|a, b| Ok((a <= b) as i32)).to_cf()?,
- I32GtS => self.stack.values.calculate::<i32, _>(|a, b| Ok((a > b) as i32))?,
- I64GtS => self.stack.values.calculate::<i64, _>(|a, b| Ok((a > b) as i32))?,
- I32GtU => self.stack.values.calculate::<u32, _>(|a, b| Ok((a > b) as i32))?,
- I64GtU => self.stack.values.calculate::<u64, _>(|a, b| Ok((a > b) as i32))?,
- F32Gt => self.stack.values.calculate::<f32, _>(|a, b| Ok((a > b) as i32))?,
- F64Gt => self.stack.values.calculate::<f64, _>(|a, b| Ok((a > b) as i32))?,
+ I32GeS => self.stack.values.calculate_same::<i32>(|a, b| Ok((a >= b) as i32)).to_cf()?,
+ I64GeS => self.stack.values.calculate::<i64, _>(|a, b| Ok((a >= b) as i32)).to_cf()?,
+ I32GeU => self.stack.values.calculate::<u32, _>(|a, b| Ok((a >= b) as i32)).to_cf()?,
+ I64GeU => self.stack.values.calculate::<u64, _>(|a, b| Ok((a >= b) as i32)).to_cf()?,
+ F32Ge => self.stack.values.calculate::<f32, _>(|a, b| Ok((a >= b) as i32)).to_cf()?,
+ F64Ge => self.stack.values.calculate::<f64, _>(|a, b| Ok((a >= b) as i32)).to_cf()?,
- I32Add => self.stack.values.calculate::<i32, _>(|a, b| Ok(a.wrapping_add(b)))?,
- I64Add => self.stack.values.calculate::<i64, _>(|a, b| Ok(a.wrapping_add(b)))?,
- F32Add => self.stack.values.calculate::<f32, _>(|a, b| Ok(a + b))?,
- F64Add => self.stack.values.calculate::<f64, _>(|a, b| Ok(a + b))?,
+ I32GtS => self.stack.values.calculate_same::<i32>(|a, b| Ok((a > b) as i32)).to_cf()?,
+ I64GtS => self.stack.values.calculate::<i64, _>(|a, b| Ok((a > b) as i32)).to_cf()?,
+ I32GtU => self.stack.values.calculate::<u32, _>(|a, b| Ok((a > b) as i32)).to_cf()?,
+ I64GtU => self.stack.values.calculate::<u64, _>(|a, b| Ok((a > b) as i32)).to_cf()?,
+ F32Gt => self.stack.values.calculate::<f32, _>(|a, b| Ok((a > b) as i32)).to_cf()?,
+ F64Gt => self.stack.values.calculate::<f64, _>(|a, b| Ok((a > b) as i32)).to_cf()?,
- I32Sub => self.stack.values.calculate::<i32, _>(|a, b| Ok(a.wrapping_sub(b)))?,
- I64Sub => self.stack.values.calculate::<i64, _>(|a, b| Ok(a.wrapping_sub(b)))?,
- F32Sub => self.stack.values.calculate::<f32, _>(|a, b| Ok(a - b))?,
- F64Sub => self.stack.values.calculate::<f64, _>(|a, b| Ok(a - b))?,
+ I32Add => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_add(b))).to_cf()?,
+ I64Add => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_add(b))).to_cf()?,
+ F32Add => self.stack.values.calculate_same::<f32>(|a, b| Ok(a + b)).to_cf()?,
+ F64Add => self.stack.values.calculate_same::<f64>(|a, b| Ok(a + b)).to_cf()?,
- F32Div => self.stack.values.calculate::<f32, _>(|a, b| Ok(a / b))?,
- F64Div => self.stack.values.calculate::<f64, _>(|a, b| Ok(a / b))?,
+ I32Sub => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_sub(b))).to_cf()?,
+ I64Sub => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_sub(b))).to_cf()?,
+ F32Sub => self.stack.values.calculate_same::<f32>(|a, b| Ok(a - b)).to_cf()?,
+ F64Sub => self.stack.values.calculate_same::<f64>(|a, b| Ok(a - b)).to_cf()?,
- I32Mul => self.stack.values.calculate::<i32, _>(|a, b| Ok(a.wrapping_mul(b)))?,
- I64Mul => self.stack.values.calculate::<i64, _>(|a, b| Ok(a.wrapping_mul(b)))?,
- F32Mul => self.stack.values.calculate::<f32, _>(|a, b| Ok(a * b))?,
- F64Mul => self.stack.values.calculate::<f64, _>(|a, b| Ok(a * b))?,
+ F32Div => self.stack.values.calculate_same::<f32>(|a, b| Ok(a / b)).to_cf()?,
+ F64Div => self.stack.values.calculate_same::<f64>(|a, b| Ok(a / b)).to_cf()?,
- // these can trap
- I32DivS => self.stack.values.calculate::<i32, _>(|a, b| {
- if unlikely(b == 0) {
- return Err(Error::Trap(Trap::DivisionByZero));
- }
- a.checked_div(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
- })?,
- I64DivS => self.stack.values.calculate::<i64, _>(|a, b| {
- if unlikely(b == 0) {
- return Err(Error::Trap(Trap::DivisionByZero));
- }
- a.checked_div(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
- })?,
- I32DivU => self.stack.values.calculate::<u32, _>(|a, b| {
- if unlikely(b == 0) {
- return Err(Error::Trap(Trap::DivisionByZero));
- }
- a.checked_div(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
- })?,
- I64DivU => self.stack.values.calculate::<u64, _>(|a, b| {
- if unlikely(b == 0) {
- return Err(Error::Trap(Trap::DivisionByZero));
- }
- a.checked_div(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
- })?,
+ I32Mul => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_mul(b))).to_cf()?,
+ I64Mul => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_mul(b))).to_cf()?,
+ F32Mul => self.stack.values.calculate_same::<f32>(|a, b| Ok(a * b)).to_cf()?,
+ F64Mul => self.stack.values.calculate_same::<f64>(|a, b| Ok(a * b)).to_cf()?,
- I32RemS => self.stack.values.calculate::<i32, _>(|a, b| {
- if unlikely(b == 0) {
- return Err(Error::Trap(Trap::DivisionByZero));
- }
- a.checked_wrapping_rem(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
- })?,
- I64RemS => self.stack.values.calculate::<i64, _>(|a, b| {
- if unlikely(b == 0) {
- return Err(Error::Trap(Trap::DivisionByZero));
- }
- a.checked_wrapping_rem(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
- })?,
- I32RemU => self.stack.values.calculate::<u32, _>(|a, b| {
- if unlikely(b == 0) {
- return Err(Error::Trap(Trap::DivisionByZero));
- }
- a.checked_wrapping_rem(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
- })?,
- I64RemU => self.stack.values.calculate::<u64, _>(|a, b| {
- if unlikely(b == 0) {
- return Err(Error::Trap(Trap::DivisionByZero));
- }
- a.checked_wrapping_rem(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
- })?,
+ I32DivS => self.stack.values.calculate_same::<i32>(|a, b| a.wasm_checked_div(b)).to_cf()?,
+ I64DivS => self.stack.values.calculate_same::<i64>(|a, b| a.wasm_checked_div(b)).to_cf()?,
+ I32DivU => self.stack.values.calculate_same::<u32>(|a, b| a.checked_div(b).ok_or_else(trap_0)).to_cf()?,
+ I64DivU => self.stack.values.calculate_same::<u64>(|a, b| a.checked_div(b).ok_or_else(trap_0)).to_cf()?,
+ I32RemS => self.stack.values.calculate_same::<i32>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
+ I64RemS => self.stack.values.calculate_same::<i64>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
+ I32RemU => self.stack.values.calculate_same::<u32>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
+ I64RemU => self.stack.values.calculate_same::<u64>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
- I32And => self.stack.values.calculate::<i32, _>(|a, b| Ok(a & b))?,
- I64And => self.stack.values.calculate::<i64, _>(|a, b| Ok(a & b))?,
- I32Or => self.stack.values.calculate::<i32, _>(|a, b| Ok(a | b))?,
- I64Or => self.stack.values.calculate::<i64, _>(|a, b| Ok(a | b))?,
- I32Xor => self.stack.values.calculate::<i32, _>(|a, b| Ok(a ^ b))?,
- I64Xor => self.stack.values.calculate::<i64, _>(|a, b| Ok(a ^ b))?,
- I32Shl => self.stack.values.calculate::<i32, _>(|a, b| Ok(a.wasm_shl(b)))?,
- I64Shl => self.stack.values.calculate::<i64, _>(|a, b| Ok(a.wasm_shl(b)))?,
- I32ShrS => self.stack.values.calculate::<i32, _>(|a, b| Ok(a.wasm_shr(b)))?,
- I64ShrS => self.stack.values.calculate::<i64, _>(|a, b| Ok(a.wasm_shr(b)))?,
- I32ShrU => self.stack.values.calculate::<u32, _>(|a, b| Ok(a.wasm_shr(b)))?,
- I64ShrU => self.stack.values.calculate::<u64, _>(|a, b| Ok(a.wasm_shr(b)))?,
- I32Rotl => self.stack.values.calculate::<i32, _>(|a, b| Ok(a.wasm_rotl(b)))?,
- I64Rotl => self.stack.values.calculate::<i64, _>(|a, b| Ok(a.wasm_rotl(b)))?,
- I32Rotr => self.stack.values.calculate::<i32, _>(|a, b| Ok(a.wasm_rotr(b)))?,
- I64Rotr => self.stack.values.calculate::<i64, _>(|a, b| Ok(a.wasm_rotr(b)))?,
+ I32And => self.stack.values.calculate_same::<i32>(|a, b| Ok(a & b)).to_cf()?,
+ I64And => self.stack.values.calculate_same::<i64>(|a, b| Ok(a & b)).to_cf()?,
+ I32Or => self.stack.values.calculate_same::<i32>(|a, b| Ok(a | b)).to_cf()?,
+ I64Or => self.stack.values.calculate_same::<i64>(|a, b| Ok(a | b)).to_cf()?,
+ I32Xor => self.stack.values.calculate_same::<i32>(|a, b| Ok(a ^ b)).to_cf()?,
+ I64Xor => self.stack.values.calculate_same::<i64>(|a, b| Ok(a ^ b)).to_cf()?,
+ I32Shl => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_shl(b))).to_cf()?,
+ I64Shl => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_shl(b))).to_cf()?,
+ I32ShrS => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
+ I64ShrS => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
+ I32ShrU => self.stack.values.calculate_same::<u32>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
+ I64ShrU => self.stack.values.calculate_same::<u64>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
+ I32Rotl => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_rotl(b))).to_cf()?,
+ I64Rotl => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_rotl(b))).to_cf()?,
+ I32Rotr => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_rotr(b))).to_cf()?,
+ I64Rotr => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_rotr(b))).to_cf()?,
- I32Clz => self.stack.values.replace_top::<i32, _>(|v| Ok(v.leading_zeros() as i32))?,
- I64Clz => self.stack.values.replace_top::<i64, _>(|v| Ok(v.leading_zeros() as i64))?,
- I32Ctz => self.stack.values.replace_top::<i32, _>(|v| Ok(v.trailing_zeros() as i32))?,
- I64Ctz => self.stack.values.replace_top::<i64, _>(|v| Ok(v.trailing_zeros() as i64))?,
- I32Popcnt => self.stack.values.replace_top::<i32, _>(|v| Ok(v.count_ones() as i32))?,
- I64Popcnt => self.stack.values.replace_top::<i64, _>(|v| Ok(v.count_ones() as i64))?,
+ I32Clz => self.stack.values.replace_top_same::<i32>(|v| Ok(v.leading_zeros() as i32)).to_cf()?,
+ I64Clz => self.stack.values.replace_top_same::<i64>(|v| Ok(v.leading_zeros() as i64)).to_cf()?,
+ I32Ctz => self.stack.values.replace_top_same::<i32>(|v| Ok(v.trailing_zeros() as i32)).to_cf()?,
+ I64Ctz => self.stack.values.replace_top_same::<i64>(|v| Ok(v.trailing_zeros() as i64)).to_cf()?,
+ I32Popcnt => self.stack.values.replace_top_same::<i32>(|v| Ok(v.count_ones() as i32)).to_cf()?,
+ I64Popcnt => self.stack.values.replace_top_same::<i64>(|v| Ok(v.count_ones() as i64)).to_cf()?,
- F32ConvertI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(v as f32))?,
- F32ConvertI64S => self.stack.values.replace_top::<i64, _>(|v| Ok(v as f32))?,
- F64ConvertI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(v as f64))?,
- F64ConvertI64S => self.stack.values.replace_top::<i64, _>(|v| Ok(v as f64))?,
- F32ConvertI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(v as f32))?,
- F32ConvertI64U => self.stack.values.replace_top::<u64, _>(|v| Ok(v as f32))?,
- F64ConvertI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(v as f64))?,
- F64ConvertI64U => self.stack.values.replace_top::<u64, _>(|v| Ok(v as f64))?,
+ F32ConvertI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(v as f32)).to_cf()?,
+ F32ConvertI64S => self.stack.values.replace_top::<i64, _>(|v| Ok(v as f32)).to_cf()?,
+ F64ConvertI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(v as f64)).to_cf()?,
+ F64ConvertI64S => self.stack.values.replace_top::<i64, _>(|v| Ok(v as f64)).to_cf()?,
+ F32ConvertI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(v as f32)).to_cf()?,
+ F32ConvertI64U => self.stack.values.replace_top::<u64, _>(|v| Ok(v as f32)).to_cf()?,
+ F64ConvertI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(v as f64)).to_cf()?,
+ F64ConvertI64U => self.stack.values.replace_top::<u64, _>(|v| Ok(v as f64)).to_cf()?,
- I32Extend8S => self.stack.values.replace_top::<i32, _>(|v| Ok((v as i8) as i32))?,
- I32Extend16S => self.stack.values.replace_top::<i32, _>(|v| Ok((v as i16) as i32))?,
- I64Extend8S => self.stack.values.replace_top::<i64, _>(|v| Ok((v as i8) as i64))?,
- I64Extend16S => self.stack.values.replace_top::<i64, _>(|v| Ok((v as i16) as i64))?,
- I64Extend32S => self.stack.values.replace_top::<i64, _>(|v| Ok((v as i32) as i64))?,
- I64ExtendI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(v as i64))?,
- I64ExtendI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(v as i64))?,
- I32WrapI64 => self.stack.values.replace_top::<i64, _>(|v| Ok(v as i32))?,
+ I32Extend8S => self.stack.values.replace_top_same::<i32>(|v| Ok((v as i8) as i32)).to_cf()?,
+ I32Extend16S => self.stack.values.replace_top_same::<i32>(|v| Ok((v as i16) as i32)).to_cf()?,
+ I64Extend8S => self.stack.values.replace_top_same::<i64>(|v| Ok((v as i8) as i64)).to_cf()?,
+ I64Extend16S => self.stack.values.replace_top_same::<i64>(|v| Ok((v as i16) as i64)).to_cf()?,
+ I64Extend32S => self.stack.values.replace_top_same::<i64>(|v| Ok((v as i32) as i64)).to_cf()?,
+ I64ExtendI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(v as i64)).to_cf()?,
+ I64ExtendI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(v as i64)).to_cf()?,
+ I32WrapI64 => self.stack.values.replace_top::<i64, _>(|v| Ok(v as i32)).to_cf()?,
- F32DemoteF64 => self.stack.values.replace_top::<f64, _>(|v| Ok(v as f32))?,
- F64PromoteF32 => self.stack.values.replace_top::<f32, _>(|v| Ok(v as f64))?,
+ F32DemoteF64 => self.stack.values.replace_top::<f64, _>(|v| Ok(v as f32)).to_cf()?,
+ F64PromoteF32 => self.stack.values.replace_top::<f32, _>(|v| Ok(v as f64)).to_cf()?,
- F32Abs => self.stack.values.replace_top::<f32, _>(|v| Ok(v.abs()))?,
- F64Abs => self.stack.values.replace_top::<f64, _>(|v| Ok(v.abs()))?,
- F32Neg => self.stack.values.replace_top::<f32, _>(|v| Ok(-v))?,
- F64Neg => self.stack.values.replace_top::<f64, _>(|v| Ok(-v))?,
- F32Ceil => self.stack.values.replace_top::<f32, _>(|v| Ok(v.ceil()))?,
- F64Ceil => self.stack.values.replace_top::<f64, _>(|v| Ok(v.ceil()))?,
- F32Floor => self.stack.values.replace_top::<f32, _>(|v| Ok(v.floor()))?,
- F64Floor => self.stack.values.replace_top::<f64, _>(|v| Ok(v.floor()))?,
- F32Trunc => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc()))?,
- F64Trunc => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc()))?,
- F32Nearest => self.stack.values.replace_top::<f32, _>(|v| Ok(v.tw_nearest()))?,
- F64Nearest => self.stack.values.replace_top::<f64, _>(|v| Ok(v.tw_nearest()))?,
- F32Sqrt => self.stack.values.replace_top::<f32, _>(|v| Ok(v.sqrt()))?,
- F64Sqrt => self.stack.values.replace_top::<f64, _>(|v| Ok(v.sqrt()))?,
- F32Min => self.stack.values.calculate::<f32, _>(|a, b| Ok(a.tw_minimum(b)))?,
- F64Min => self.stack.values.calculate::<f64, _>(|a, b| Ok(a.tw_minimum(b)))?,
- F32Max => self.stack.values.calculate::<f32, _>(|a, b| Ok(a.tw_maximum(b)))?,
- F64Max => self.stack.values.calculate::<f64, _>(|a, b| Ok(a.tw_maximum(b)))?,
- F32Copysign => self.stack.values.calculate::<f32, _>(|a, b| Ok(a.copysign(b)))?,
- F64Copysign => self.stack.values.calculate::<f64, _>(|a, b| Ok(a.copysign(b)))?,
+ F32Abs => self.stack.values.replace_top_same::<f32>(|v| Ok(v.abs())).to_cf()?,
+ F64Abs => self.stack.values.replace_top_same::<f64>(|v| Ok(v.abs())).to_cf()?,
+ F32Neg => self.stack.values.replace_top_same::<f32>(|v| Ok(-v)).to_cf()?,
+ F64Neg => self.stack.values.replace_top_same::<f64>(|v| Ok(-v)).to_cf()?,
+ F32Ceil => self.stack.values.replace_top_same::<f32>(|v| Ok(v.ceil())).to_cf()?,
+ F64Ceil => self.stack.values.replace_top_same::<f64>(|v| Ok(v.ceil())).to_cf()?,
+ F32Floor => self.stack.values.replace_top_same::<f32>(|v| Ok(v.floor())).to_cf()?,
+ F64Floor => self.stack.values.replace_top_same::<f64>(|v| Ok(v.floor())).to_cf()?,
+ F32Trunc => self.stack.values.replace_top_same::<f32>(|v| Ok(v.trunc())).to_cf()?,
+ F64Trunc => self.stack.values.replace_top_same::<f64>(|v| Ok(v.trunc())).to_cf()?,
+ F32Nearest => self.stack.values.replace_top_same::<f32>(|v| Ok(v.tw_nearest())).to_cf()?,
+ F64Nearest => self.stack.values.replace_top_same::<f64>(|v| Ok(v.tw_nearest())).to_cf()?,
+ F32Sqrt => self.stack.values.replace_top_same::<f32>(|v| Ok(v.sqrt())).to_cf()?,
+ F64Sqrt => self.stack.values.replace_top_same::<f64>(|v| Ok(v.sqrt())).to_cf()?,
+ F32Min => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.tw_minimum(b))).to_cf()?,
+ F64Min => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.tw_minimum(b))).to_cf()?,
+ F32Max => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.tw_maximum(b))).to_cf()?,
+ F64Max => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.tw_maximum(b))).to_cf()?,
+ F32Copysign => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.copysign(b))).to_cf()?,
+ F64Copysign => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.copysign(b))).to_cf()?,
// no-op instructions since types are erased at runtime
I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
@@ -365,160 +285,144 @@ impl<'store, 'stack> Executor<'store, 'stack> {
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)?,
- TableSet(table_idx) => self.exec_table_set(*table_idx)?,
- TableSize(table_idx) => self.exec_table_size(*table_idx)?,
- TableInit(elem_idx, table_idx) => self.exec_table_init(*elem_idx, *table_idx)?,
- TableGrow(table_idx) => self.exec_table_grow(*table_idx)?,
- TableFill(table_idx) => self.exec_table_fill(*table_idx)?,
+ TableGet(table_idx) => self.exec_table_get(*table_idx).to_cf()?,
+ TableSet(table_idx) => self.exec_table_set(*table_idx).to_cf()?,
+ TableSize(table_idx) => self.exec_table_size(*table_idx).to_cf()?,
+ TableInit(elem_idx, table_idx) => self.exec_table_init(*elem_idx, *table_idx).to_cf()?,
+ TableGrow(table_idx) => self.exec_table_grow(*table_idx).to_cf()?,
+ TableFill(table_idx) => self.exec_table_fill(*table_idx).to_cf()?,
+
+ I32TruncSatF32S => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as i32)).to_cf()?,
+ I32TruncSatF32U => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as u32)).to_cf()?,
+ I32TruncSatF64S => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as i32)).to_cf()?,
+ I32TruncSatF64U => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as u32)).to_cf()?,
+ I64TruncSatF32S => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as i64)).to_cf()?,
+ I64TruncSatF32U => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as u64)).to_cf()?,
+ I64TruncSatF64S => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as i64)).to_cf()?,
+ I64TruncSatF64U => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as u64)).to_cf()?,
- I32TruncSatF32S => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as i32))?,
- I32TruncSatF32U => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as u32))?,
- I32TruncSatF64S => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as i32))?,
- I32TruncSatF64U => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as u32))?,
- I64TruncSatF32S => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as i64))?,
- I64TruncSatF32U => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as u64))?,
- I64TruncSatF64S => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as i64))?,
- I64TruncSatF64U => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as u64))?,
- // 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),
- // I32ConstStoreLocal { local, const_i32, offset, mem_addr } => {
- // self.exec_i32_const_store_local(*local, *const_i32, *offset, *mem_addr)?
- // }
- // I32StoreLocal { local_a, local_b, offset, mem_addr } => {
- // self.exec_i32_store_local(*local_a, *local_b, *offset, *mem_addr)?
- // }
+ LocalCopy32(from, to) => self.exec_local_copy::<Value32>(*from, *to),
+ LocalCopy64(from, to) => self.exec_local_copy::<Value64>(*from, *to),
+ LocalCopy128(from, to) => self.exec_local_copy::<Value128>(*from, *to),
+ LocalCopyRef(from, to) => self.exec_local_copy::<ValueRef>(*from, *to),
+
+ instr => {
+ unreachable!("unimplemented instruction: {:?}", instr);
+ }
};
self.cf.incr_instr_ptr();
- Ok(ControlFlow::Continue(()))
+ ControlFlow::Continue(())
}
fn exec_noop(&self) {}
#[cold]
- fn exec_unreachable(&self) -> Result<()> {
- Err(Error::Trap(Trap::Unreachable))
+ fn exec_unreachable(&self) -> ControlFlow<Option<Error>> {
+ ControlFlow::Break(Some(Trap::Unreachable.into()))
}
- fn exec_call(&mut self, wasm_func: Rc<WasmFunction>, owner: ModuleInstanceAddr) -> Result<ControlFlow<()>> {
- let locals = match self.stack.values.pop_locals(&wasm_func.ty.params, wasm_func.locals) {
- Ok(locals) => locals,
- Err(e) => {
- cold();
- return Err(e);
- }
- };
-
+ fn exec_call(&mut self, wasm_func: Rc<WasmFunction>, owner: ModuleInstanceAddr) -> ControlFlow<Option<Error>> {
+ let locals = self.stack.values.pop_locals(&wasm_func.params, &wasm_func.locals);
let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.stack.blocks.len() as u32);
self.cf.incr_instr_ptr(); // skip the call instruction
self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
self.module.swap_with(self.cf.module_addr(), self.store);
- Ok(ControlFlow::Continue(()))
+ ControlFlow::Continue(())
}
- fn exec_call_direct(&mut self, v: u32) -> Result<ControlFlow<()>> {
- let func_inst = self.store.get_func(self.module.resolve_func_addr(v)?)?;
+ fn exec_call_direct(&mut self, v: u32) -> ControlFlow<Option<Error>> {
+ 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 = self.stack.values.pop_params(&host_func.ty.params)?;
- let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params)?;
+ 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).to_cf()?;
self.stack.values.extend_from_wasmvalues(&res);
self.cf.incr_instr_ptr();
- return Ok(ControlFlow::Continue(()));
+ return ControlFlow::Continue(());
}
};
self.exec_call(wasm_func.clone(), func_inst._owner)
}
- fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<ControlFlow<()>> {
+ fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> ControlFlow<Option<Error>> {
// verify that the table is of the right type, this should be validated by the parser already
let func_ref = {
- let table = self.store.get_table(self.module.resolve_table_addr(table_addr)?)?;
- let table_idx: u32 = self.stack.values.pop::<i32>()? as u32;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_addr));
+ let table_idx: u32 = self.stack.values.pop::<i32>() as u32;
assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref");
table
.get(table_idx)
- .map_err(|_| Error::Trap(Trap::UndefinedElement { index: table_idx as usize }))?
+ .map_err(|_| Error::Trap(Trap::UndefinedElement { index: table_idx as usize }))
+ .to_cf()?
.addr()
- .ok_or(Trap::UninitializedElement { index: table_idx as usize })?
+ .ok_or(Error::Trap(Trap::UninitializedElement { index: table_idx as usize }))
+ .to_cf()?
};
- let func_inst = self.store.get_func(func_ref)?;
+ let func_inst = self.store.get_func(&func_ref);
let call_ty = self.module.func_ty(type_addr);
let wasm_func = match &func_inst.func {
crate::Function::Wasm(f) => f,
crate::Function::Host(host_func) => {
if unlikely(host_func.ty != *call_ty) {
- return Err(Error::Trap(Trap::IndirectCallTypeMismatch {
- actual: host_func.ty.clone(),
- expected: call_ty.clone(),
- }));
+ return ControlFlow::Break(Some(
+ Trap::IndirectCallTypeMismatch { actual: host_func.ty.clone(), expected: call_ty.clone() }
+ .into(),
+ ));
}
let host_func = host_func.clone();
- 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)?;
+ let params = self.stack.values.pop_params(&host_func.ty.params);
+ let res =
+ match (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params) {
+ Ok(res) => res,
+ Err(e) => return ControlFlow::Break(Some(e)),
+ };
+
self.stack.values.extend_from_wasmvalues(&res);
self.cf.incr_instr_ptr();
- return Ok(ControlFlow::Continue(()));
+ return ControlFlow::Continue(());
}
};
- if wasm_func.ty == *call_ty {
- return self.exec_call(wasm_func.clone(), func_inst._owner);
+ if unlikely(wasm_func.ty != *call_ty) {
+ return ControlFlow::Break(Some(
+ Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into(),
+ ));
}
- cold();
- Err(Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into())
+ self.exec_call(wasm_func.clone(), func_inst._owner)
}
- fn exec_if(
- &mut self,
- else_offset: u32,
- end_offset: u32,
- (params, results): (StackHeight, StackHeight),
- ) -> Result<()> {
+ fn exec_if(&mut self, else_offset: u32, end_offset: u32, (params, results): (StackHeight, StackHeight)) {
// truthy value is on the top of the stack, so enter the then block
- if self.stack.values.pop::<i32>()? != 0 {
- self.enter_block(self.cf.instr_ptr(), end_offset, BlockType::If, (params, results));
- return Ok(());
+ if self.stack.values.pop::<i32>() != 0 {
+ self.enter_block(end_offset, BlockType::If, (params, results));
+ return;
}
// falsy value is on the top of the stack
if else_offset == 0 {
- *self.cf.instr_ptr_mut() += end_offset as usize;
- return Ok(());
+ self.cf.jump(end_offset as usize);
+ return;
}
- let old = self.cf.instr_ptr();
- *self.cf.instr_ptr_mut() += else_offset as usize;
- self.enter_block(old + else_offset as usize, end_offset - else_offset, BlockType::Else, (params, results));
- Ok(())
+ self.cf.jump(else_offset as usize);
+ self.enter_block(end_offset - else_offset, BlockType::Else, (params, results));
}
- fn exec_else(&mut self, end_offset: u32) -> Result<()> {
- self.exec_end_block()?;
- *self.cf.instr_ptr_mut() += end_offset as usize;
- Ok(())
+ fn exec_else(&mut self, end_offset: u32) {
+ self.exec_end_block();
+ self.cf.jump(end_offset as usize);
}
fn resolve_functype(&self, idx: u32) -> (StackHeight, StackHeight) {
let ty = self.module.func_ty(idx);
((&*ty.params).into(), (&*ty.results).into())
}
- fn enter_block(
- &mut self,
- instr_ptr: usize,
- end_instr_offset: u32,
- ty: BlockType,
- (params, results): (StackHeight, StackHeight),
- ) {
+ fn enter_block(&mut self, end_instr_offset: u32, ty: BlockType, (params, results): (StackHeight, StackHeight)) {
self.stack.blocks.push(BlockFrame {
- instr_ptr,
+ instr_ptr: self.cf.instr_ptr(),
end_instr_offset,
stack_ptr: self.stack.values.height(),
results,
@@ -526,35 +430,39 @@ impl<'store, 'stack> Executor<'store, 'stack> {
ty,
});
}
- fn exec_br(&mut self, to: u32) -> Result<ControlFlow<()>> {
+ fn exec_br(&mut self, to: u32) -> ControlFlow<Option<Error>> {
if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() {
return self.exec_return();
}
self.cf.incr_instr_ptr();
- Ok(ControlFlow::Continue(()))
+ ControlFlow::Continue(())
}
- fn exec_br_if(&mut self, to: u32) -> Result<ControlFlow<()>> {
- if self.stack.values.pop::<i32>()? != 0
+ fn exec_br_if(&mut self, to: u32) -> ControlFlow<Option<Error>> {
+ if self.stack.values.pop::<i32>() != 0
&& self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none()
{
return self.exec_return();
}
self.cf.incr_instr_ptr();
- Ok(ControlFlow::Continue(()))
+ ControlFlow::Continue(())
}
- fn exec_brtable(&mut self, default: u32, len: u32) -> Result<ControlFlow<()>> {
+ fn exec_brtable(&mut self, default: u32, len: u32) -> ControlFlow<Option<Error>> {
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())));
+ return ControlFlow::Break(Some(Error::Other(format!(
+ "br_table out of bounds: {} >= {}",
+ end,
+ self.cf.instructions().len()
+ ))));
}
- let idx = self.stack.values.pop::<i32>()?;
+ let idx = self.stack.values.pop::<i32>();
let to = match self.cf.instructions()[start..end].get(idx as usize) {
None => default,
Some(Instruction::BrLabel(to)) => *to,
- _ => return Err(Error::Other("br_table with invalid label".to_string())),
+ _ => return ControlFlow::Break(Some(Error::Other("br_table out of bounds".to_string()))),
};
if self.cf.break_to(to, &mut self.stack.values, &mut self.stack.blocks).is_none() {
@@ -562,12 +470,12 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
self.cf.incr_instr_ptr();
- Ok(ControlFlow::Continue(()))
+ ControlFlow::Continue(())
}
- fn exec_return(&mut self) -> Result<ControlFlow<()>> {
+ fn exec_return(&mut self) -> ControlFlow<Option<Error>> {
let old = self.cf.block_ptr();
match self.stack.call_stack.pop() {
- None => return Ok(ControlFlow::Break(())),
+ None => return ControlFlow::Break(None),
Some(cf) => self.cf = cf,
}
@@ -576,94 +484,96 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
self.module.swap_with(self.cf.module_addr(), self.store);
- Ok(ControlFlow::Continue(()))
+ ControlFlow::Continue(())
}
- fn exec_end_block(&mut self) -> Result<()> {
- let block = self.stack.blocks.pop()?;
+ fn exec_end_block(&mut self) {
+ let block = self.stack.blocks.pop();
self.stack.values.truncate_keep(&block.stack_ptr, &block.results);
- Ok(())
}
- fn exec_local_get<T: InternalValue>(&mut self, local_index: u16) -> Result<()> {
- let v = self.cf.locals.get::<T>(local_index)?;
+ fn exec_local_get<T: InternalValue>(&mut self, local_index: u16) {
+ let v = self.cf.locals.get::<T>(local_index);
self.stack.values.push(v);
- Ok(())
+ }
+ fn exec_local_set<T: InternalValue>(&mut self, local_index: u16) {
+ let v = self.stack.values.pop::<T>();
+ self.cf.locals.set(local_index, v);
+ }
+ fn exec_local_tee<T: InternalValue>(&mut self, local_index: u16) {
+ let v = self.stack.values.peek::<T>();
+ self.cf.locals.set(local_index, v);
}
- fn exec_global_get(&mut self, global_index: u32) -> Result<()> {
- self.stack.values.push_dyn(self.store.get_global_val(self.module.resolve_global_addr(global_index)?)?);
- Ok(())
+ fn exec_global_get(&mut self, global_index: u32) {
+ self.stack.values.push_dyn(self.store.get_global_val(self.module.resolve_global_addr(global_index)));
}
- fn exec_global_set<T: InternalValue>(&mut self, global_index: u32) -> Result<()>
- where
- TinyWasmValue: From<T>,
- {
- self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop::<T>()?.into())
+ fn exec_global_set<T: InternalValue>(&mut self, global_index: u32) {
+ self.store.set_global_val(self.module.resolve_global_addr(global_index), self.stack.values.pop::<T>().into());
}
- fn exec_ref_is_null(&mut self) -> Result<()> {
- let is_null = self.stack.values.pop::<ValueRef>()?.is_none() as i32;
+ fn exec_const<T: InternalValue>(&mut self, val: T) {
+ self.stack.values.push(val);
+ }
+ fn exec_ref_is_null(&mut self) {
+ let is_null = self.stack.values.pop::<ValueRef>().is_none() as i32;
self.stack.values.push::<i32>(is_null);
- Ok(())
}
- fn exec_memory_size(&mut self, addr: u32) -> Result<()> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?;
- self.stack.values.push::<i32>(mem.page_count() as i32);
- Ok(())
+ fn exec_memory_size(&mut self, addr: u32) {
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(addr));
+ self.stack.values.push::<i32>(mem.page_count as i32);
}
- fn exec_memory_grow(&mut self, addr: u32) -> Result<()> {
- let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(addr)?)?;
- let prev_size = mem.page_count() as i32;
- let pages_delta = self.stack.values.pop::<i32>()?;
+ fn exec_memory_grow(&mut self, addr: u32) {
+ let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(addr));
+ let prev_size = mem.page_count as i32;
+ let pages_delta = self.stack.values.pop::<i32>();
self.stack.values.push::<i32>(match mem.grow(pages_delta) {
Some(_) => prev_size,
None => -1,
});
- Ok(())
}
fn exec_memory_copy(&mut self, from: u32, to: u32) -> Result<()> {
- let size = self.stack.values.pop::<i32>()?;
- let src = self.stack.values.pop::<i32>()?;
- let dst = self.stack.values.pop::<i32>()?;
+ let size: i32 = self.stack.values.pop();
+ let src: i32 = self.stack.values.pop();
+ let dst: i32 = self.stack.values.pop();
if from == to {
- let mem_from = self.store.get_mem_mut(self.module.resolve_mem_addr(from)?)?;
+ let mem_from = self.store.get_mem_mut(self.module.resolve_mem_addr(from));
// 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, mem_to) =
- self.store.get_mems_mut(self.module.resolve_mem_addr(from)?, self.module.resolve_mem_addr(to)?)?;
+ self.store.get_mems_mut(self.module.resolve_mem_addr(from), self.module.resolve_mem_addr(to))?;
+
mem_to.copy_from_slice(dst as usize, mem_from.load(src as usize, size as usize)?)?;
}
Ok(())
}
fn exec_memory_fill(&mut self, addr: u32) -> Result<()> {
- let size = self.stack.values.pop::<i32>()?;
- let val = self.stack.values.pop::<i32>()?;
- let dst = self.stack.values.pop::<i32>()?;
+ let size: i32 = self.stack.values.pop();
+ let val: i32 = self.stack.values.pop();
+ let dst: i32 = self.stack.values.pop();
- let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(addr)?)?;
- mem.fill(dst as usize, size as usize, val as u8)?;
- Ok(())
+ let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(addr));
+ mem.fill(dst as usize, size as usize, val as u8)
}
fn exec_memory_init(&mut self, data_index: u32, mem_index: u32) -> Result<()> {
- let size = self.stack.values.pop::<i32>()?; // n
- let offset = self.stack.values.pop::<i32>()?; // s
- let dst = self.stack.values.pop::<i32>()?; // d
+ let size: i32 = self.stack.values.pop();
+ let offset: i32 = self.stack.values.pop();
+ let dst: i32 = self.stack.values.pop();
let data = self
.store
.data
.datas
- .get(self.module.resolve_data_addr(data_index)? as usize)
+ .get(*self.module.resolve_data_addr(data_index) as usize)
.ok_or_else(|| Error::Other("data not found".to_string()))?;
let mem = self
.store
.data
.memories
- .get_mut(self.module.resolve_mem_addr(mem_index)? as usize)
+ .get_mut(*self.module.resolve_mem_addr(mem_index) as usize)
.ok_or_else(|| Error::Other("memory not found".to_string()))?;
let data_len = data.data.as_ref().map(|d| d.len()).unwrap_or(0);
@@ -681,32 +591,30 @@ impl<'store, 'stack> Executor<'store, 'stack> {
None => return Err(Trap::MemoryOutOfBounds { offset: 0, len: 0, max: 0 }.into()),
};
- mem.store(dst as usize, size as usize, &data[offset as usize..((offset + size) as usize)])?;
- Ok(())
+ mem.store(dst as usize, size as usize, &data[offset as usize..((offset + size) as usize)])
}
- fn exec_data_drop(&mut self, data_index: u32) -> Result<()> {
- self.store.get_data_mut(self.module.resolve_data_addr(data_index)?).map(|d| d.drop())
+ fn exec_data_drop(&mut self, data_index: u32) {
+ self.store.get_data_mut(self.module.resolve_data_addr(data_index)).drop()
}
- fn exec_elem_drop(&mut self, elem_index: u32) -> Result<()> {
- self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)?).map(|e| e.drop())
+ fn exec_elem_drop(&mut self, elem_index: u32) {
+ self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)).drop()
}
fn exec_table_copy(&mut self, from: u32, to: u32) -> Result<()> {
- let size: i32 = self.stack.values.pop::<i32>()?;
- let src: i32 = self.stack.values.pop::<i32>()?;
- let dst: i32 = self.stack.values.pop::<i32>()?;
+ let size: i32 = self.stack.values.pop();
+ let src: i32 = self.stack.values.pop();
+ let dst: i32 = self.stack.values.pop();
if from == to {
// copy within the same memory
- self.store.get_table_mut(self.module.resolve_table_addr(from)?)?.copy_within(
+ self.store.get_table_mut(self.module.resolve_table_addr(from)).copy_within(
dst as usize,
src as usize,
size as usize,
)?;
} else {
// copy between two memories
- let (table_from, table_to) = self
- .store
- .get_tables_mut(self.module.resolve_table_addr(from)?, self.module.resolve_table_addr(to)?)?;
+ let (table_from, table_to) =
+ self.store.get_tables_mut(self.module.resolve_table_addr(from), self.module.resolve_table_addr(to))?;
table_to.copy_from_slice(dst as usize, table_from.load(src as usize, size as usize)?)?;
}
Ok(())
@@ -714,54 +622,55 @@ impl<'store, 'stack> Executor<'store, 'stack> {
fn exec_mem_load<LOAD: MemLoadable<LOAD_SIZE>, const LOAD_SIZE: usize, TARGET: InternalValue>(
&mut self,
- cast: fn(LOAD) -> TARGET,
mem_addr: tinywasm_types::MemAddr,
offset: u64,
- ) -> Result<()> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?;
-
- let val = self.stack.values.pop::<i32>()? as u64;
+ cast: fn(LOAD) -> TARGET,
+ ) -> ControlFlow<Option<Error>> {
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr));
+ let val = self.stack.values.pop::<i32>() as u64;
let Some(Ok(addr)) = offset.checked_add(val).map(|a| a.try_into()) else {
cold();
- return Err(Error::Trap(crate::Trap::MemoryOutOfBounds {
- offset: offset as usize,
+ return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
+ offset: val as usize,
len: LOAD_SIZE,
- max: mem.max_pages(),
- }));
+ max: 0,
+ })));
};
- let val = mem.load_as::<LOAD_SIZE, LOAD>(addr)?;
+ let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?;
self.stack.values.push(cast(val));
- Ok(())
+ ControlFlow::Continue(())
}
- fn exec_mem_store<T: MemStorable<N>, const N: usize>(
+ fn exec_mem_store<T: InternalValue, U: MemStorable<N>, const N: usize>(
&mut self,
- val: T,
mem_addr: tinywasm_types::MemAddr,
offset: u64,
- ) -> Result<()> {
- let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(mem_addr)?)?;
- let val = val.to_mem_bytes();
- let addr = self.stack.values.pop::<i32>()? as u64;
- mem.store((offset + addr) as usize, val.len(), &val)?;
- Ok(())
+ cast: fn(T) -> U,
+ ) -> ControlFlow<Option<Error>> {
+ let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(mem_addr));
+ let val = self.stack.values.pop::<T>();
+ let val = (cast(val)).to_mem_bytes();
+ let addr = self.stack.values.pop::<i32>() as u64;
+ if let Err(e) = mem.store((offset + addr) as usize, val.len(), &val) {
+ return ControlFlow::Break(Some(e));
+ }
+ ControlFlow::Continue(())
}
fn exec_table_get(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
- let idx: i32 = self.stack.values.pop::<i32>()?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index));
+ let idx: i32 = self.stack.values.pop::<i32>();
let v = table.get_wasm_val(idx as u32)?;
self.stack.values.push_dyn(v.into());
Ok(())
}
fn exec_table_set(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index)?)?;
- let val = self.stack.values.pop::<ValueRef>()?;
- let idx = self.stack.values.pop::<i32>()? as u32;
- table.set(idx, val.into())?;
- Ok(())
+ let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index));
+ let val = self.stack.values.pop::<ValueRef>();
+ let idx = self.stack.values.pop::<i32>() as u32;
+ table.set(idx, val.into())
}
fn exec_table_size(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index));
self.stack.values.push_dyn(table.size().into());
Ok(())
}
@@ -770,22 +679,22 @@ impl<'store, 'stack> Executor<'store, 'stack> {
.store
.data
.elements
- .get(self.module.resolve_elem_addr(elem_index)? as usize)
+ .get(*self.module.resolve_elem_addr(elem_index) as usize)
.ok_or_else(|| Error::Other("element not found".to_string()))?;
let table = self
.store
.data
.tables
- .get_mut(self.module.resolve_table_addr(table_index)? as usize)
+ .get_mut(*self.module.resolve_table_addr(table_index) as usize)
.ok_or_else(|| Error::Other("table not found".to_string()))?;
let elem_len = elem.items.as_ref().map(|items| items.len()).unwrap_or(0);
let table_len = table.size();
- let size: i32 = self.stack.values.pop::<i32>()?; // n
- let offset: i32 = self.stack.values.pop::<i32>()?; // s
- let dst: i32 = self.stack.values.pop::<i32>()?; // d
+ let size: i32 = self.stack.values.pop(); // n
+ let offset: i32 = self.stack.values.pop(); // s
+ let dst: i32 = self.stack.values.pop(); // d
if unlikely(((size + offset) as usize > elem_len) || ((dst + size) > table_len)) {
return Err(Trap::TableOutOfBounds { offset: offset as usize, len: size as usize, max: elem_len }.into());
@@ -803,29 +712,28 @@ impl<'store, 'stack> Executor<'store, 'stack> {
return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into());
};
- table.init(self.module.func_addrs(), dst, &items[offset as usize..(offset + size) as usize])?;
- Ok(())
+ table.init(self.module.func_addrs(), dst, &items[offset as usize..(offset + size) as usize])
}
fn exec_table_grow(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index)?)?;
+ let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index));
let sz = table.size();
- let n = self.stack.values.pop::<i32>()?;
- let val = self.stack.values.pop::<ValueRef>()?;
+ let n = self.stack.values.pop::<i32>();
+ let val = self.stack.values.pop::<ValueRef>();
match table.grow(n, val.into()) {
- Ok(_) => self.stack.values.push_dyn(sz.into()),
- Err(_) => self.stack.values.push_dyn((-1_i32).into()),
+ Ok(_) => self.stack.values.push(sz),
+ Err(_) => self.stack.values.push(-1_i32),
}
Ok(())
}
fn exec_table_fill(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index)?)?;
+ let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index));
- let n = self.stack.values.pop::<i32>()?;
- let val = self.stack.values.pop::<ValueRef>()?;
- let i = self.stack.values.pop::<i32>()?;
+ let n = self.stack.values.pop::<i32>();
+ let val = self.stack.values.pop::<ValueRef>();
+ let i = self.stack.values.pop::<i32>();
if unlikely(i + n > table.size()) {
return Err(Error::Trap(Trap::TableOutOfBounds {
@@ -839,7 +747,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
return Ok(());
}
- table.fill(self.module.func_addrs(), i as usize, n as usize, val.into())?;
- Ok(())
+ table.fill(self.module.func_addrs(), i as usize, n as usize, val.into())
+ }
+
+ fn exec_local_copy<T: InternalValue>(&mut self, from: u16, to: u16) {
+ let v = self.cf.locals.get::<T>(from);
+ self.cf.locals.set(to, v);
}
}
diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs
index 88a5e9e..89a8002 100644
--- a/crates/tinywasm/src/interpreter/num_helpers.rs
+++ b/crates/tinywasm/src/interpreter/num_helpers.rs
@@ -1,8 +1,9 @@
-pub(crate) trait CheckedWrappingRem
+pub(crate) trait TinywasmIntExt
where
Self: Sized,
{
- fn checked_wrapping_rem(self, rhs: Self) -> Option<Self>;
+ fn checked_wrapping_rem(self, rhs: Self) -> Result<Self>;
+ fn wasm_checked_div(self, rhs: Self) -> Result<Self>;
}
/// Doing the actual conversion from float to int is a bit tricky, because
@@ -33,28 +34,37 @@ macro_rules! checked_conv_float {
};
// Conversion with an intermediate unsigned type and error checking (three types)
($from:tt, $intermediate:tt, $to:tt, $self:expr) => {
- $self.stack.values.replace_top::<$from, $to>(|v| {
- let (min, max) = float_min_max!($from, $intermediate);
- if unlikely(v.is_nan()) {
- return Err(Error::Trap(crate::Trap::InvalidConversionToInt));
- }
- if unlikely(v <= min || v >= max) {
- return Err(Error::Trap(crate::Trap::IntegerOverflow));
- }
- Ok((v as $intermediate as $to).into())
- })?
+ $self
+ .stack
+ .values
+ .replace_top::<$from, $to>(|v| {
+ let (min, max) = float_min_max!($from, $intermediate);
+ if unlikely(v.is_nan()) {
+ return Err(Error::Trap(crate::Trap::InvalidConversionToInt));
+ }
+ if unlikely(v <= min || v >= max) {
+ return Err(Error::Trap(crate::Trap::IntegerOverflow));
+ }
+ Ok((v as $intermediate as $to).into())
+ })
+ .to_cf()?
};
}
pub(crate) use checked_conv_float;
pub(crate) use float_min_max;
+pub(super) fn trap_0() -> Error {
+ Error::Trap(crate::Trap::DivisionByZero)
+}
pub(crate) trait TinywasmFloatExt {
fn tw_minimum(self, other: Self) -> Self;
fn tw_maximum(self, other: Self) -> Self;
fn tw_nearest(self) -> Self;
}
+use crate::{Error, Result};
+
#[cfg(not(feature = "std"))]
use super::no_std_floats::NoStdFloatExt;
@@ -147,13 +157,22 @@ impl_wrapping_self_sh! { i32 i64 u32 u64 }
macro_rules! impl_checked_wrapping_rem {
($($t:ty)*) => ($(
- impl CheckedWrappingRem for $t {
+ impl TinywasmIntExt for $t {
+ #[inline]
+ fn checked_wrapping_rem(self, rhs: Self) -> Result<Self> {
+ if rhs == 0 {
+ Err(Error::Trap(crate::Trap::DivisionByZero))
+ } else {
+ Ok(self.wrapping_rem(rhs))
+ }
+ }
+
#[inline]
- fn checked_wrapping_rem(self, rhs: Self) -> Option<Self> {
+ fn wasm_checked_div(self, rhs: Self) -> Result<Self> {
if rhs == 0 {
- None
+ Err(Error::Trap(crate::Trap::DivisionByZero))
} else {
- Some(self.wrapping_rem(rhs))
+ self.checked_div(rhs).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))
}
}
}
diff --git a/crates/tinywasm/src/interpreter/stack/block_stack.rs b/crates/tinywasm/src/interpreter/stack/block_stack.rs
index 6121bec..2267194 100644
--- a/crates/tinywasm/src/interpreter/stack/block_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/block_stack.rs
@@ -1,4 +1,4 @@
-use crate::{cold, unlikely, Error, Result};
+use crate::unlikely;
use alloc::vec::Vec;
use crate::interpreter::values::{StackHeight, StackLocation};
@@ -37,14 +37,8 @@ impl BlockStack {
}
#[inline(always)]
- pub(crate) fn pop(&mut self) -> Result<BlockFrame> {
- match self.0.pop() {
- Some(frame) => Ok(frame),
- None => {
- cold();
- Err(Error::BlockStackUnderflow)
- }
- }
+ pub(crate) fn pop(&mut self) -> BlockFrame {
+ self.0.pop().expect("block stack underflow, this is a bug")
}
/// keep the top `len` blocks and discard the rest
diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs
index a7c6a74..03885f9 100644
--- a/crates/tinywasm/src/interpreter/stack/call_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs
@@ -1,7 +1,9 @@
+use core::ops::ControlFlow;
+
use super::BlockType;
use crate::interpreter::values::*;
-use crate::unlikely;
-use crate::{Result, Trap};
+use crate::Trap;
+use crate::{unlikely, Error};
use alloc::boxed::Box;
use alloc::{rc::Rc, vec, vec::Vec};
@@ -26,21 +28,21 @@ impl CallStack {
}
#[inline(always)]
- pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> {
+ pub(crate) fn push(&mut self, call_frame: CallFrame) -> ControlFlow<Option<Error>> {
if unlikely((self.stack.len() + 1) >= MAX_CALL_STACK_SIZE) {
- return Err(Trap::CallStackOverflow.into());
+ return ControlFlow::Break(Some(Trap::CallStackOverflow.into()));
}
self.stack.push(call_frame);
- Ok(())
+ ControlFlow::Continue(())
}
}
#[derive(Debug)]
pub(crate) struct CallFrame {
- pub(crate) instr_ptr: usize,
- pub(crate) block_ptr: u32,
- pub(crate) func_instance: Rc<WasmFunction>,
- pub(crate) module_addr: ModuleInstanceAddr,
+ instr_ptr: usize,
+ func_instance: Rc<WasmFunction>,
+ block_ptr: u32,
+ module_addr: ModuleInstanceAddr,
pub(crate) locals: Locals,
}
@@ -53,13 +55,11 @@ pub(crate) struct Locals {
}
impl Locals {
- // TODO: locals get_set
-
- pub(crate) fn get<T: InternalValue>(&self, local_index: LocalAddr) -> Result<T> {
+ pub(crate) fn get<T: InternalValue>(&self, local_index: LocalAddr) -> T {
T::local_get(self, local_index)
}
- pub(crate) fn set<T: InternalValue>(&mut self, local_index: LocalAddr, value: T) -> Result<()> {
+ pub(crate) fn set<T: InternalValue>(&mut self, local_index: LocalAddr, value: T) {
T::local_set(self, local_index, value)
}
}
@@ -71,13 +71,13 @@ impl CallFrame {
}
#[inline(always)]
- pub(crate) fn instr_ptr_mut(&mut self) -> &mut usize {
- &mut self.instr_ptr
+ pub(crate) fn incr_instr_ptr(&mut self) {
+ self.instr_ptr += 1;
}
#[inline(always)]
- pub(crate) fn incr_instr_ptr(&mut self) {
- self.instr_ptr += 1;
+ pub(crate) fn jump(&mut self, offset: usize) {
+ self.instr_ptr += offset;
}
#[inline(always)]
@@ -149,13 +149,13 @@ impl CallFrame {
) -> Self {
let locals = {
let mut locals_32 = Vec::new();
- locals_32.reserve_exact(wasm_func_inst.locals.local_32 as usize);
+ locals_32.reserve_exact(wasm_func_inst.locals.c32 as usize);
let mut locals_64 = Vec::new();
- locals_64.reserve_exact(wasm_func_inst.locals.local_64 as usize);
+ locals_64.reserve_exact(wasm_func_inst.locals.c64 as usize);
let mut locals_128 = Vec::new();
- locals_128.reserve_exact(wasm_func_inst.locals.local_128 as usize);
+ locals_128.reserve_exact(wasm_func_inst.locals.c128 as usize);
let mut locals_ref = Vec::new();
- locals_ref.reserve_exact(wasm_func_inst.locals.local_ref as usize);
+ locals_ref.reserve_exact(wasm_func_inst.locals.cref as usize);
for p in params {
match p.into() {
@@ -166,10 +166,10 @@ impl CallFrame {
}
}
- locals_32.resize_with(wasm_func_inst.locals.local_32 as usize, Default::default);
- locals_64.resize_with(wasm_func_inst.locals.local_64 as usize, Default::default);
- locals_128.resize_with(wasm_func_inst.locals.local_128 as usize, Default::default);
- locals_ref.resize_with(wasm_func_inst.locals.local_ref as usize, Default::default);
+ locals_32.resize_with(wasm_func_inst.locals.c32 as usize, Default::default);
+ locals_64.resize_with(wasm_func_inst.locals.c64 as usize, Default::default);
+ locals_128.resize_with(wasm_func_inst.locals.c128 as usize, Default::default);
+ locals_ref.resize_with(wasm_func_inst.locals.cref as usize, Default::default);
Locals {
locals_32: locals_32.into_boxed_slice(),
diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index 02d35c1..178c9ec 100644
--- a/crates/tinywasm/src/interpreter/stack/value_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs
@@ -1,12 +1,12 @@
use alloc::vec::Vec;
-use tinywasm_types::{LocalCounts, ValType, WasmValue};
+use tinywasm_types::{ValType, ValueCounts, ValueCountsSmall, WasmValue};
-use crate::{interpreter::values::*, Result};
+use crate::{interpreter::*, Result};
use super::Locals;
-pub(crate) const STACK_32_SIZE: usize = 1024 * 128;
-pub(crate) const STACK_64_SIZE: usize = 1024 * 128;
-pub(crate) const STACK_128_SIZE: usize = 1024 * 128;
+pub(crate) const STACK_32_SIZE: usize = 1024 * 32;
+pub(crate) const STACK_64_SIZE: usize = 1024 * 16;
+pub(crate) const STACK_128_SIZE: usize = 1024 * 8;
pub(crate) const STACK_REF_SIZE: usize = 1024;
#[derive(Debug)]
@@ -37,12 +37,12 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn peek<T: InternalValue>(&self) -> Result<T> {
+ pub(crate) fn peek<T: InternalValue>(&self) -> T {
T::stack_peek(self)
}
#[inline]
- pub(crate) fn pop<T: InternalValue>(&mut self) -> Result<T> {
+ pub(crate) fn pop<T: InternalValue>(&mut self) -> T {
T::stack_pop(self)
}
@@ -51,93 +51,88 @@ impl ValueStack {
T::stack_push(self, value)
}
- pub(crate) fn drop<T: InternalValue>(&mut self) -> Result<()> {
- T::stack_pop(self).map(|_| ())
+ #[inline]
+ pub(crate) fn drop<T: InternalValue>(&mut self) {
+ T::stack_pop(self);
}
- // TODO: this needs to re-introduce the top replacement optimization
- pub(crate) fn select<T: InternalValue>(&mut self) -> Result<()> {
- let cond: i32 = self.pop()?;
- let val2: T = self.pop()?;
+ #[inline]
+ pub(crate) fn select<T: InternalValue>(&mut self) {
+ let cond: i32 = self.pop();
+ let val2: T = self.pop();
if cond == 0 {
- self.drop::<T>()?;
+ self.drop::<T>();
self.push(val2);
}
- Ok(())
}
- // TODO: this needs to re-introduce the top replacement optimization
+ #[inline]
+ pub(crate) fn calculate_same<T: InternalValue>(&mut self, func: fn(T, T) -> Result<T>) -> Result<()> {
+ T::stack_calculate(self, func)
+ }
+
+ #[inline]
pub(crate) fn calculate<T: InternalValue, U: InternalValue>(&mut self, func: fn(T, T) -> Result<U>) -> Result<()> {
- let v2 = T::stack_pop(self)?;
- let v1 = T::stack_pop(self)?;
+ let v2 = T::stack_pop(self);
+ let v1 = T::stack_pop(self);
U::stack_push(self, func(v1, v2)?);
Ok(())
}
- // TODO: this needs to re-introduce the top replacement optimization
+ #[inline]
pub(crate) fn replace_top<T: InternalValue, U: InternalValue>(&mut self, func: fn(T) -> Result<U>) -> Result<()> {
- let v1 = T::stack_pop(self)?;
+ let v1 = T::stack_pop(self);
U::stack_push(self, func(v1)?);
Ok(())
}
- pub(crate) fn pop_dyn(&mut self, val_type: ValType) -> Result<TinyWasmValue> {
- match val_type {
- ValType::I32 => self.pop().map(TinyWasmValue::Value32),
- ValType::I64 => self.pop().map(TinyWasmValue::Value64),
- ValType::V128 => self.pop().map(TinyWasmValue::Value128),
- ValType::RefExtern => self.pop().map(TinyWasmValue::ValueRef),
- ValType::RefFunc => self.pop().map(TinyWasmValue::ValueRef),
- ValType::F32 => self.pop().map(TinyWasmValue::Value32),
- ValType::F64 => self.pop().map(TinyWasmValue::Value64),
- }
+ #[inline]
+ pub(crate) fn replace_top_same<T: InternalValue>(&mut self, func: fn(T) -> Result<T>) -> Result<()> {
+ T::replace_top(self, func)
}
- pub(crate) fn pop_params(&mut self, val_types: &[ValType]) -> Result<Vec<WasmValue>> {
- val_types.iter().map(|val_type| self.pop_wasmvalue(*val_type)).collect::<Result<Vec<_>>>()
+ pub(crate) fn pop_params(&mut self, val_types: &[ValType]) -> Vec<WasmValue> {
+ val_types.iter().map(|val_type| self.pop_wasmvalue(*val_type)).collect::<Vec<_>>()
}
- pub(crate) fn pop_results(&mut self, val_types: &[ValType]) -> Result<Vec<WasmValue>> {
- val_types.iter().rev().map(|val_type| self.pop_wasmvalue(*val_type)).collect::<Result<Vec<_>>>().map(|mut v| {
- v.reverse();
- v
- })
+ pub(crate) fn pop_results(&mut self, val_types: &[ValType]) -> Vec<WasmValue> {
+ let mut results = val_types.iter().rev().map(|val_type| self.pop_wasmvalue(*val_type)).collect::<Vec<_>>();
+ results.reverse();
+ results
}
- // TODO: a lot of optimization potential here
- pub(crate) fn pop_locals(&mut self, val_types: &[ValType], lc: LocalCounts) -> Result<Locals> {
- let mut locals_32 = Vec::new();
- locals_32.reserve_exact(lc.local_32 as usize);
- let mut locals_64 = Vec::new();
- locals_64.reserve_exact(lc.local_64 as usize);
- let mut locals_128 = Vec::new();
- locals_128.reserve_exact(lc.local_128 as usize);
- let mut locals_ref = Vec::new();
- locals_ref.reserve_exact(lc.local_ref as usize);
-
- for ty in val_types {
- match self.pop_dyn(*ty)? {
- TinyWasmValue::Value32(v) => locals_32.push(v),
- TinyWasmValue::Value64(v) => locals_64.push(v),
- TinyWasmValue::Value128(v) => locals_128.push(v),
- TinyWasmValue::ValueRef(v) => locals_ref.push(v),
- }
+ #[inline]
+ pub(crate) fn pop_locals(&mut self, pc: &ValueCountsSmall, lc: &ValueCounts) -> Locals {
+ Locals {
+ locals_32: {
+ let mut locals_32 = { alloc::vec![Value32::default(); lc.c32 as usize].into_boxed_slice() };
+ locals_32[0..pc.c32 as usize]
+ .copy_from_slice(&self.stack_32[(self.stack_32.len() - pc.c32 as usize)..]);
+ self.stack_32.truncate(self.stack_32.len() - pc.c32 as usize);
+ locals_32
+ },
+ locals_64: {
+ let mut locals_64 = { alloc::vec![Value64::default(); lc.c64 as usize].into_boxed_slice() };
+ locals_64[0..pc.c64 as usize]
+ .copy_from_slice(&self.stack_64[(self.stack_64.len() - pc.c64 as usize)..]);
+ self.stack_64.truncate(self.stack_64.len() - pc.c64 as usize);
+ locals_64
+ },
+ locals_128: {
+ let mut locals_128 = { alloc::vec![Value128::default(); lc.c128 as usize].into_boxed_slice() };
+ locals_128[0..pc.c128 as usize]
+ .copy_from_slice(&self.stack_128[(self.stack_128.len() - pc.c128 as usize)..]);
+ self.stack_128.truncate(self.stack_128.len() - pc.c128 as usize);
+ locals_128
+ },
+ locals_ref: {
+ let mut locals_ref = { alloc::vec![ValueRef::default(); lc.cref as usize].into_boxed_slice() };
+ locals_ref[0..pc.cref as usize]
+ .copy_from_slice(&self.stack_ref[(self.stack_ref.len() - pc.cref as usize)..]);
+ self.stack_ref.truncate(self.stack_ref.len() - pc.cref as usize);
+ locals_ref
+ },
}
- locals_32.reverse();
- locals_32.resize_with(lc.local_32 as usize, Default::default);
- locals_64.reverse();
- locals_64.resize_with(lc.local_64 as usize, Default::default);
- locals_128.reverse();
- locals_128.resize_with(lc.local_128 as usize, Default::default);
- locals_ref.reverse();
- locals_ref.resize_with(lc.local_ref as usize, Default::default);
-
- Ok(Locals {
- locals_32: locals_32.into_boxed_slice(),
- locals_64: locals_64.into_boxed_slice(),
- locals_128: locals_128.into_boxed_slice(),
- locals_ref: locals_ref.into_boxed_slice(),
- })
}
pub(crate) fn truncate_keep(&mut self, to: &StackLocation, keep: &StackHeight) {
@@ -165,21 +160,21 @@ impl ValueStack {
}
}
- pub(crate) fn pop_wasmvalue(&mut self, val_type: ValType) -> Result<WasmValue> {
+ pub(crate) fn pop_wasmvalue(&mut self, val_type: ValType) -> WasmValue {
match val_type {
- ValType::I32 => self.pop().map(WasmValue::I32),
- ValType::I64 => self.pop().map(WasmValue::I64),
- ValType::V128 => self.pop().map(WasmValue::V128),
- ValType::F32 => self.pop().map(WasmValue::F32),
- ValType::F64 => self.pop().map(WasmValue::F64),
- ValType::RefExtern => self.pop().map(|v| match v {
+ ValType::I32 => WasmValue::I32(self.pop()),
+ ValType::I64 => WasmValue::I64(self.pop()),
+ ValType::V128 => WasmValue::V128(self.pop()),
+ ValType::F32 => WasmValue::F32(self.pop()),
+ ValType::F64 => WasmValue::F64(self.pop()),
+ ValType::RefExtern => match self.pop() {
Some(v) => WasmValue::RefExtern(v),
None => WasmValue::RefNull(ValType::RefExtern),
- }),
- ValType::RefFunc => self.pop().map(|v| match v {
+ },
+ ValType::RefFunc => match self.pop() {
Some(v) => WasmValue::RefFunc(v),
None => WasmValue::RefNull(ValType::RefFunc),
- }),
+ },
}
}
diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs
index c934e51..35341fc 100644
--- a/crates/tinywasm/src/interpreter/values.rs
+++ b/crates/tinywasm/src/interpreter/values.rs
@@ -1,5 +1,5 @@
#![allow(missing_docs)]
-use crate::{Error, Result};
+use crate::Result;
use tinywasm_types::{LocalAddr, ValType, WasmValue};
use super::stack::{Locals, ValueStack};
@@ -137,18 +137,23 @@ mod sealed {
pub trait Sealed {}
}
-pub(crate) trait InternalValue: sealed::Sealed {
+pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> {
fn stack_push(stack: &mut ValueStack, value: Self);
- fn stack_pop(stack: &mut ValueStack) -> Result<Self>
+ fn replace_top(stack: &mut ValueStack, func: fn(Self) -> Result<Self>) -> Result<()>
where
Self: Sized;
- fn stack_peek(stack: &ValueStack) -> Result<Self>
+ fn stack_calculate(stack: &mut ValueStack, func: fn(Self, Self) -> Result<Self>) -> Result<()>
where
Self: Sized;
- fn local_get(locals: &Locals, index: LocalAddr) -> Result<Self>
+
+ fn stack_pop(stack: &mut ValueStack) -> Self
+ where
+ Self: Sized;
+ fn stack_peek(stack: &ValueStack) -> Self
where
Self: Sized;
- fn local_set(locals: &mut Locals, index: LocalAddr, value: Self) -> Result<()>;
+ fn local_get(locals: &Locals, index: LocalAddr) -> Self;
+ fn local_set(locals: &mut Locals, index: LocalAddr, value: Self);
}
macro_rules! impl_internalvalue {
@@ -169,33 +174,43 @@ macro_rules! impl_internalvalue {
stack.$stack.push($to_internal(value));
}
#[inline(always)]
- fn stack_pop(stack: &mut ValueStack) -> Result<Self> {
- match stack.$stack.pop() {
- Some(v) => Ok($to_outer(v)),
- None => {
- crate::cold();
- Err(Error::ValueStackUnderflow)
- },
+ fn stack_pop(stack: &mut ValueStack) -> Self {
+ ($to_outer)(stack.$stack.pop().expect("ValueStack underflow, this is a bug"))
+ }
+ #[inline(always)]
+ fn stack_peek(stack: &ValueStack) -> Self {
+ ($to_outer)(*stack.$stack.last().expect("ValueStack underflow, this is a bug"))
+ }
+
+ #[inline(always)]
+ fn stack_calculate(stack: &mut ValueStack, func: fn(Self, Self) -> Result<Self>) -> Result<()> {
+ let v2 = stack.$stack.pop();
+ let v1 = stack.$stack.last_mut();
+ if let (Some(v1), Some(v2)) = (v1, v2) {
+ *v1 = $to_internal(func($to_outer(*v1), $to_outer(v2))?);
+ } else {
+ unreachable!("ValueStack underflow, this is a bug");
}
+ Ok(())
}
+
#[inline(always)]
- fn stack_peek(stack: &ValueStack) -> Result<Self> {
- match stack.$stack.last() {
- Some(v) => Ok($to_outer(*v)),
- None => {
- crate::cold();
- Err(Error::ValueStackUnderflow)
- },
+ fn replace_top(stack: &mut ValueStack, func: fn(Self) -> Result<Self>) -> Result<()> {
+ if let Some(v) = stack.$stack.last_mut() {
+ *v = $to_internal(func($to_outer(*v))?);
+ Ok(())
+ } else {
+ unreachable!("ValueStack underflow, this is a bug");
}
}
+
#[inline(always)]
- fn local_get(locals: &Locals, index: LocalAddr) -> Result<Self> {
- Ok($to_outer(locals.$locals[index as usize]))
+ fn local_get(locals: &Locals, index: LocalAddr) -> Self {
+ $to_outer(locals.$locals[index as usize])
}
#[inline(always)]
- fn local_set(locals: &mut Locals, index: LocalAddr, value: Self) -> Result<()> {
+ fn local_set(locals: &mut Locals, index: LocalAddr, value: Self) {
locals.$locals[index as usize] = $to_internal(value);
- Ok(())
}
}
)*
diff --git a/crates/tinywasm/src/reference.rs b/crates/tinywasm/src/reference.rs
index 60ed61a..b9d65bc 100644
--- a/crates/tinywasm/src/reference.rs
+++ b/crates/tinywasm/src/reference.rs
@@ -60,7 +60,7 @@ impl MemoryRefMut<'_> {
/// Get the current size of the memory in pages
pub fn page_count(&mut self) -> usize {
- self.0.page_count()
+ self.0.page_count
}
/// Copy a slice of memory to another place in memory
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index eb2bccf..b86435d 100644
--- a/crates/tinywasm/src/store/memory.rs
+++ b/crates/tinywasm/src/store/memory.rs
@@ -75,36 +75,21 @@ impl MemoryInstance {
Ok(&self.data[addr..end])
}
- // this is a workaround since we can't use generic const expressions yet (https://github.com/rust-lang/rust/issues/76560)
pub(crate) fn load_as<const SIZE: usize, T: MemLoadable<SIZE>>(&self, addr: usize) -> Result<T> {
let Some(end) = addr.checked_add(SIZE) else {
- cold();
return Err(self.trap_oob(addr, SIZE));
};
if end > self.data.len() {
- cold();
return Err(self.trap_oob(addr, SIZE));
}
Ok(T::from_le_bytes(match self.data[addr..end].try_into() {
Ok(bytes) => bytes,
- Err(_) => {
- cold();
- return Err(Error::Trap(crate::Trap::MemoryOutOfBounds {
- offset: addr,
- len: SIZE,
- max: self.data.len(),
- }));
- }
+ Err(_) => return Err(self.trap_oob(addr, SIZE)),
}))
}
- #[inline]
- pub(crate) fn page_count(&self) -> usize {
- self.page_count
- }
-
pub(crate) fn fill(&mut self, addr: usize, len: usize, val: u8) -> Result<()> {
let end = addr.checked_add(len).ok_or_else(|| self.trap_oob(addr, len))?;
if end > self.data.len() {
@@ -144,7 +129,7 @@ impl MemoryInstance {
#[inline]
pub(crate) fn grow(&mut self, pages_delta: i32) -> Option<i32> {
- let current_pages = self.page_count();
+ let current_pages = self.page_count;
let new_pages = current_pages as i64 + pages_delta as i64;
debug_assert!(new_pages <= i32::MAX as i64, "page count should never be greater than i32::MAX");
@@ -256,9 +241,9 @@ mod memory_instance_tests {
#[test]
fn test_memory_grow() {
let mut memory = create_test_memory();
- let original_pages = memory.page_count();
+ let original_pages = memory.page_count;
assert_eq!(memory.grow(1), Some(original_pages as i32));
- assert_eq!(memory.page_count(), original_pages + 1);
+ assert_eq!(memory.page_count, original_pages + 1);
}
#[test]
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 7fc8460..bc4055d 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -1,4 +1,5 @@
use alloc::{boxed::Box, format, string::ToString, vec::Vec};
+use core::fmt::Debug;
use core::sync::atomic::{AtomicUsize, Ordering};
use tinywasm_types::*;
@@ -26,7 +27,6 @@ static STORE_ID: AtomicUsize = AtomicUsize::new(0);
/// functions, you should create a new store and then drop it when you're done (e.g. in a request handler)
///
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#store>
-#[derive(Debug)]
pub struct Store {
id: usize,
module_instances: Vec<ModuleInstance>,
@@ -35,6 +35,16 @@ pub struct Store {
pub(crate) runtime: Runtime,
}
+impl Debug for Store {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.debug_struct("Store")
+ .field("id", &self.id)
+ .field("module_instances", &self.module_instances)
+ .field("data", &"...")
+ .finish()
+ }
+}
+
#[derive(Debug, Clone, Copy)]
pub(crate) enum Runtime {
Default,
@@ -76,7 +86,7 @@ impl Default for Store {
}
}
-#[derive(Debug, Default)]
+#[derive(Default)]
/// Global state that can be manipulated by WebAssembly programs
///
/// Data should only be addressable by the module that owns it
@@ -112,42 +122,30 @@ impl Store {
/// Get the function at the actual index in the store
#[inline]
- pub(crate) fn get_func(&self, addr: FuncAddr) -> Result<&FunctionInstance> {
- self.data.funcs.get(addr as usize).ok_or_else(|| Self::not_found_error("function"))
+ pub(crate) fn get_func(&self, addr: &FuncAddr) -> &FunctionInstance {
+ &self.data.funcs[*addr as usize]
}
/// Get the memory at the actual index in the store
#[inline]
- pub(crate) fn get_mem(&self, addr: MemAddr) -> Result<&MemoryInstance> {
- match self.data.memories.get(addr as usize) {
- Some(mem) => Ok(mem),
- None => {
- cold();
- Err(Self::not_found_error("memory"))
- }
- }
+ pub(crate) fn get_mem(&self, addr: &MemAddr) -> &MemoryInstance {
+ &self.data.memories[*addr as usize]
}
/// Get the memory at the actual index in the store
- #[inline]
- pub(crate) fn get_mem_mut(&mut self, addr: MemAddr) -> Result<&mut MemoryInstance> {
- match self.data.memories.get_mut(addr as usize) {
- Some(mem) => Ok(mem),
- None => {
- cold();
- Err(Self::not_found_error("memory"))
- }
- }
+ #[inline(always)]
+ pub(crate) fn get_mem_mut(&mut self, addr: &MemAddr) -> &mut MemoryInstance {
+ &mut self.data.memories[*addr as usize]
}
/// Get the memory at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_mems_mut(
&mut self,
- addr: MemAddr,
- addr2: MemAddr,
+ addr: &MemAddr,
+ addr2: &MemAddr,
) -> Result<(&mut MemoryInstance, &mut MemoryInstance)> {
- match get_pair_mut(&mut self.data.memories, addr as usize, addr2 as usize) {
+ match get_pair_mut(&mut self.data.memories, *addr as usize, *addr2 as usize) {
Some(mems) => Ok(mems),
None => {
cold();
@@ -158,24 +156,24 @@ impl Store {
/// Get the table at the actual index in the store
#[inline]
- pub(crate) fn get_table(&self, addr: TableAddr) -> Result<&TableInstance> {
- self.data.tables.get(addr as usize).ok_or_else(|| Self::not_found_error("table"))
+ pub(crate) fn get_table(&self, addr: &TableAddr) -> &TableInstance {
+ &self.data.tables[*addr as usize]
}
/// Get the table at the actual index in the store
#[inline]
- pub(crate) fn get_table_mut(&mut self, addr: TableAddr) -> Result<&mut TableInstance> {
- self.data.tables.get_mut(addr as usize).ok_or_else(|| Self::not_found_error("table"))
+ pub(crate) fn get_table_mut(&mut self, addr: &TableAddr) -> &mut TableInstance {
+ &mut self.data.tables[*addr as usize]
}
/// Get two mutable tables at the actual index in the store
#[inline]
pub(crate) fn get_tables_mut(
&mut self,
- addr: TableAddr,
- addr2: TableAddr,
+ addr: &TableAddr,
+ addr2: &TableAddr,
) -> Result<(&mut TableInstance, &mut TableInstance)> {
- match get_pair_mut(&mut self.data.tables, addr as usize, addr2 as usize) {
+ match get_pair_mut(&mut self.data.tables, *addr as usize, *addr2 as usize) {
Some(tables) => Ok(tables),
None => {
cold();
@@ -186,37 +184,32 @@ impl Store {
/// Get the data at the actual index in the store
#[inline]
- pub(crate) fn get_data_mut(&mut self, addr: DataAddr) -> Result<&mut DataInstance> {
- self.data.datas.get_mut(addr as usize).ok_or_else(|| Self::not_found_error("data"))
+ pub(crate) fn get_data_mut(&mut self, addr: &DataAddr) -> &mut DataInstance {
+ &mut self.data.datas[*addr as usize]
}
/// Get the element at the actual index in the store
#[inline]
- pub(crate) fn get_elem_mut(&mut self, addr: ElemAddr) -> Result<&mut ElementInstance> {
- self.data.elements.get_mut(addr as usize).ok_or_else(|| Self::not_found_error("element"))
+ pub(crate) fn get_elem_mut(&mut self, addr: &ElemAddr) -> &mut ElementInstance {
+ &mut self.data.elements[*addr as usize]
}
/// Get the global at the actual index in the store
#[inline]
- pub(crate) fn get_global(&self, addr: GlobalAddr) -> Result<&GlobalInstance> {
- self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global"))
+ pub(crate) fn get_global(&self, addr: &GlobalAddr) -> &GlobalInstance {
+ &self.data.globals[*addr as usize]
}
/// Get the global at the actual index in the store
#[doc(hidden)]
- pub fn get_global_val(&self, addr: MemAddr) -> Result<TinyWasmValue> {
- self.data
- .globals
- .get(addr as usize)
- .ok_or_else(|| Self::not_found_error("global"))
- .map(|global| global.value.get())
+ pub fn get_global_val(&self, addr: &MemAddr) -> TinyWasmValue {
+ self.data.globals[*addr as usize].value.get()
}
/// Set the global at the actual index in the store
#[doc(hidden)]
- pub fn set_global_val(&mut self, addr: MemAddr, value: TinyWasmValue) -> Result<()> {
- let global = self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global"));
- global.map(|global| global.value.set(value))
+ pub fn set_global_val(&mut self, addr: &MemAddr, value: TinyWasmValue) {
+ self.data.globals[*addr as usize].value.set(value);
}
}
diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs
index c005b9a..0c5f3ff 100644
--- a/crates/tinywasm/tests/testsuite/run.rs
+++ b/crates/tinywasm/tests/testsuite/run.rs
@@ -414,9 +414,7 @@ impl TestSuite {
};
let module_global = match match module.export_addr(global) {
- Some(ExternVal::Global(addr)) => {
- store.get_global_val(addr).map_err(|_| eyre!("failed to get global"))
- }
+ Some(ExternVal::Global(addr)) => Ok(store.get_global_val(&addr)),
_ => Err(eyre!("no module to get global from")),
} {
Ok(module_global) => module_global,
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index dd201ad..d77d66d 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -57,16 +57,21 @@ pub enum Instruction {
// LocalGet2(LocalAddr, LocalAddr),
// LocalGet3(LocalAddr, LocalAddr, LocalAddr),
// LocalGetSet(LocalAddr, LocalAddr),
+
+ // LocalGetGet32(LocalAddr, LocalAddr), LocalGetGet64(LocalAddr, LocalAddr), LocalGetGet128(LocalAddr, LocalAddr),
+ // LocalTeeGet32(LocalAddr, LocalAddr), LocalTeeGet64(LocalAddr, LocalAddr), LocalTeeGet128(LocalAddr, LocalAddr),
+ LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr), LocalCopy128Ref(LocalAddr, LocalAddr), LocalCopyRef(LocalAddr, LocalAddr),
+ LocalsStore32(LocalAddr, LocalAddr, u32, MemAddr), LocalsStore64(LocalAddr, LocalAddr, u32, MemAddr), LocalsStore128(LocalAddr, LocalAddr, u32, MemAddr), LocalsStoreRef(LocalAddr, LocalAddr, u32, MemAddr),
// > Control Instructions
// See <https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions>
Unreachable,
Nop,
-
- Block(EndOffset),
+
+ Block(EndOffset),
BlockWithType(ValType, EndOffset),
BlockWithFuncType(TypeAddr, EndOffset),
-
+
Loop(EndOffset),
LoopWithType(ValType, EndOffset),
LoopWithFuncType(TypeAddr, EndOffset),
@@ -84,6 +89,8 @@ pub enum Instruction {
Return,
Call(FuncAddr),
CallIndirect(TypeAddr, TableAddr),
+ ReturnCall(FuncAddr),
+ ReturnCallIndirect(TypeAddr, TableAddr),
// > Parametric Instructions
// See <https://webassembly.github.io/spec/core/binary/instructions.html#parametric-instructions>
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index db39689..a4029e2 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -179,18 +179,28 @@ pub struct FuncType {
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
-pub struct LocalCounts {
- pub local_32: u32,
- pub local_64: u32,
- pub local_128: u32,
- pub local_ref: u32,
+pub struct ValueCounts {
+ pub c32: u32,
+ pub c64: u32,
+ pub c128: u32,
+ pub cref: u32,
}
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Default, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
+pub struct ValueCountsSmall {
+ pub c32: u16,
+ pub c64: u16,
+ pub c128: u16,
+ pub cref: u16,
+}
+
+#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
pub struct WasmFunction {
pub instructions: Box<[Instruction]>,
- pub locals: LocalCounts,
+ pub locals: ValueCounts,
+ pub params: ValueCountsSmall,
pub ty: FuncType,
}