summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2024-05-11 21:07:41 +0200
committerHenry Gressmann <mail@henrygressmann.de>2024-05-11 22:55:38 +0200
commitb2b39468325b9ed7043fed48a15a77b83b13d63e (patch)
tree2fd26b72b784dc284edd48c0ac188c441db8c156
parent868aa006b7f1eabffd4aec3a03555012148a7df1 (diff)
chore: simplify code
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
-rw-r--r--crates/parser/src/conversion.rs52
-rw-r--r--crates/parser/src/visit.rs58
-rw-r--r--crates/tinywasm/src/imports.rs2
-rw-r--r--crates/tinywasm/src/runtime/interpreter/mod.rs146
-rw-r--r--crates/tinywasm/src/runtime/stack/block_stack.rs6
-rw-r--r--crates/tinywasm/src/runtime/stack/call_stack.rs23
-rw-r--r--crates/tinywasm/src/runtime/stack/value_stack.rs6
-rw-r--r--crates/tinywasm/tests/generated/2.0.csv1
-rw-r--r--crates/types/src/instructions.rs230
9 files changed, 175 insertions, 349 deletions
diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs
index e94986d..4e4434b 100644
--- a/crates/parser/src/conversion.rs
+++ b/crates/parser/src/conversion.rs
@@ -83,12 +83,11 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result<Im
size_initial: ty.initial.try_into().map_err(|_| {
crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", ty.initial))
})?,
- size_max: if let Some(max) = ty.maximum {
- Some(max.try_into().map_err(|_| {
+ size_max: match ty.maximum {
+ Some(max) => Some(max.try_into().map_err(|_| {
crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {}", max))
- })?)
- } else {
- None
+ })?),
+ None => None,
},
}),
wasmparser::TypeRef::Memory(ty) => ImportKind::Memory(convert_module_memory(ty)?),
@@ -105,10 +104,7 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result<Im
pub(crate) fn convert_module_memories<T: IntoIterator<Item = wasmparser::Result<wasmparser::MemoryType>>>(
memory_types: T,
) -> Result<Vec<MemoryType>> {
- let memory_type =
- memory_types.into_iter().map(|memory| convert_module_memory(memory?)).collect::<Result<Vec<_>>>()?;
-
- Ok(memory_type)
+ memory_types.into_iter().map(|memory| convert_module_memory(memory?)).collect::<Result<Vec<_>>>()
}
pub(crate) fn convert_module_memory(memory: wasmparser::MemoryType) -> Result<MemoryType> {
@@ -125,26 +121,23 @@ pub(crate) fn convert_module_memory(memory: wasmparser::MemoryType) -> Result<Me
pub(crate) fn convert_module_tables<'a, T: IntoIterator<Item = wasmparser::Result<wasmparser::Table<'a>>>>(
table_types: T,
) -> Result<Vec<TableType>> {
- let table_type = table_types.into_iter().map(|table| convert_module_table(table?)).collect::<Result<Vec<_>>>()?;
- Ok(table_type)
+ table_types.into_iter().map(|table| convert_module_table(table?)).collect::<Result<Vec<_>>>()
}
pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result<TableType> {
- let ty = convert_reftype(&table.ty.element_type);
-
let size_initial = table.ty.initial.try_into().map_err(|_| {
crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", table.ty.initial))
})?;
- let size_max = if let Some(max) = table.ty.maximum {
- Some(
+
+ let size_max = match table.ty.maximum {
+ Some(max) => Some(
max.try_into()
.map_err(|_| crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {}", max)))?,
- )
- } else {
- None
+ ),
+ None => None,
};
- Ok(TableType { element_type: ty, size_initial: size_initial, size_max })
+ Ok(TableType { element_type: convert_reftype(&table.ty.element_type), size_initial: size_initial, size_max })
}
pub(crate) fn convert_module_globals<'a, T: IntoIterator<Item = wasmparser::Result<wasmparser::Global<'a>>>>(
@@ -208,12 +201,8 @@ pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result<FuncType>
));
}
let ty = types.next().unwrap().unwrap_func();
-
- let params =
- ty.params().iter().map(|p| Ok(convert_valtype(p))).collect::<Result<Vec<ValType>>>()?.into_boxed_slice();
-
- let results =
- ty.results().iter().map(|p| Ok(convert_valtype(p))).collect::<Result<Vec<ValType>>>()?.into_boxed_slice();
+ let params = ty.params().iter().map(convert_valtype).collect::<Vec<ValType>>().into_boxed_slice();
+ let results = ty.results().iter().map(convert_valtype).collect::<Vec<ValType>>().into_boxed_slice();
Ok(FuncType { params, results })
}
@@ -235,14 +224,13 @@ pub(crate) fn convert_reftype(reftype: &wasmparser::RefType) -> ValType {
}
pub(crate) fn convert_valtype(valtype: &wasmparser::ValType) -> ValType {
- use wasmparser::ValType::*;
match valtype {
- I32 => ValType::I32,
- I64 => ValType::I64,
- F32 => ValType::F32,
- F64 => ValType::F64,
- Ref(r) => convert_reftype(r),
- V128 => unimplemented!("128-bit values are not supported yet"),
+ wasmparser::ValType::I32 => ValType::I32,
+ wasmparser::ValType::I64 => ValType::I64,
+ wasmparser::ValType::F32 => ValType::F32,
+ wasmparser::ValType::F64 => ValType::F64,
+ wasmparser::ValType::Ref(r) => convert_reftype(r),
+ wasmparser::ValType::V128 => unimplemented!("128-bit values are not supported yet"),
}
}
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index c3afee7..8b9e15d 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -3,7 +3,7 @@ use crate::{conversion::convert_blocktype, Result};
use crate::conversion::{convert_heaptype, convert_memarg, convert_valtype};
use alloc::string::ToString;
use alloc::{boxed::Box, format, vec::Vec};
-use tinywasm_types::{BlockArgsPacked, Instruction};
+use tinywasm_types::Instruction;
use wasmparser::{FuncValidator, FunctionBody, VisitOperator, WasmModuleResources};
struct ValidateThenVisit<'a, T, U>(T, &'a mut U);
@@ -65,16 +65,14 @@ macro_rules! define_primitive_operands {
($($name:ident, $instr:expr, $ty:ty),*) => {
$(
fn $name(&mut self, arg: $ty) -> Self::Output {
- self.instructions.push($instr(arg));
- Ok(())
+ Ok(self.instructions.push($instr(arg)))
}
)*
};
($($name:ident, $instr:expr, $ty:ty, $ty2:ty),*) => {
$(
fn $name(&mut self, arg: $ty, arg2: $ty) -> Self::Output {
- self.instructions.push($instr(arg, arg2));
- Ok(())
+ Ok(self.instructions.push($instr(arg, arg2)))
}
)*
};
@@ -112,8 +110,7 @@ impl FunctionBuilder {
#[inline]
fn visit(&mut self, op: Instruction) -> Result<()> {
- self.instructions.push(op);
- Ok(())
+ Ok(self.instructions.push(op))
}
}
@@ -162,7 +159,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
visit_i64_load16_u, I64Load16U,
visit_i64_load32_s, I64Load32S,
visit_i64_load32_u, I64Load32U,
- // visit_i32_store, I32Store,
+ // visit_i32_store, I32Store, custom implementation
visit_i64_store, I64Store,
visit_f32_store, F32Store,
visit_f64_store, F64Store,
@@ -325,15 +322,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
let arg = convert_memarg(memarg);
let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr };
- if self.instructions.len() < 3 {
- return self.visit(i32store);
- }
-
- #[cold]
- fn cold() {}
-
- if arg.mem_addr > 0xFF || arg.offset > 0xFFFF_FFFF {
- cold();
+ if self.instructions.len() < 3 || arg.mem_addr > 0xFF || arg.offset > 0xFFFF_FFFF {
return self.visit(i32store);
}
@@ -353,31 +342,22 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
}
fn visit_local_get(&mut self, idx: u32) -> Self::Output {
- if let Some(instruction) = self.instructions.last_mut() {
- match instruction {
- Instruction::LocalGet(a) => *instruction = Instruction::LocalGet2(*a, idx),
- Instruction::LocalGet2(a, b) => *instruction = Instruction::LocalGet3(*a, *b, idx),
- Instruction::LocalTee(a) => *instruction = Instruction::LocalTeeGet(*a, idx),
- _ => return self.visit(Instruction::LocalGet(idx)),
- };
- Ok(())
- } else {
- self.visit(Instruction::LocalGet(idx))
- }
+ let Some(instruction) = self.instructions.last_mut() else {
+ return self.visit(Instruction::LocalGet(idx));
+ };
+
+ match instruction {
+ Instruction::LocalGet(a) => *instruction = Instruction::LocalGet2(*a, idx),
+ Instruction::LocalGet2(a, b) => *instruction = Instruction::LocalGet3(*a, *b, idx),
+ Instruction::LocalTee(a) => *instruction = Instruction::LocalTeeGet(*a, idx),
+ _ => return self.visit(Instruction::LocalGet(idx)),
+ };
+
+ Ok(())
}
fn visit_local_set(&mut self, idx: u32) -> Self::Output {
self.visit(Instruction::LocalSet(idx))
- // if let Some(instruction) = self.instructions.last_mut() {
- // match instruction {
- // // Needs more testing, seems to make performance worse
- // // Instruction::LocalGet(a) => *instruction = Instruction::LocalGetSet(*a, idx),
- // _ => return self.visit(Instruction::LocalSet(idx)),
- // };
- // // Ok(())
- // } else {
- // self.visit(Instruction::LocalSet(idx))
- // }
}
fn visit_local_tee(&mut self, idx: u32) -> Self::Output {
@@ -426,7 +406,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
fn visit_if(&mut self, ty: wasmparser::BlockType) -> Self::Output {
self.label_ptrs.push(self.instructions.len());
- self.visit(Instruction::If(BlockArgsPacked::new(convert_blocktype(ty)), 0, 0))
+ self.visit(Instruction::If(convert_blocktype(ty).into(), 0, 0))
}
fn visit_else(&mut self) -> Self::Output {
diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs
index 7c9e955..c4bae3b 100644
--- a/crates/tinywasm/src/imports.rs
+++ b/crates/tinywasm/src/imports.rs
@@ -15,7 +15,7 @@ pub enum Function {
/// A host function
Host(Rc<HostFunction>),
- /// A function defined in WebAssembly
+ /// A pointer to a WebAssembly function
Wasm(Rc<WasmFunction>),
}
diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs
index da37e80..5e1500f 100644
--- a/crates/tinywasm/src/runtime/interpreter/mod.rs
+++ b/crates/tinywasm/src/runtime/interpreter/mod.rs
@@ -1,11 +1,11 @@
use alloc::format;
-use alloc::{string::ToString, vec::Vec};
+use alloc::string::ToString;
use core::ops::{BitAnd, BitOr, BitXor, Neg};
use tinywasm_types::{ElementKind, ValType};
use super::{InterpreterRuntime, Stack};
use crate::runtime::{BlockFrame, BlockType, CallFrame};
-use crate::{cold, log, unlikely};
+use crate::{cold, unlikely};
use crate::{Error, FuncContext, ModuleInstance, Result, Store, Trap};
mod macros;
@@ -23,13 +23,10 @@ impl InterpreterRuntime {
// #[inline(always)] // a small 2-3% performance improvement in some cases
pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> {
let mut call_frame = stack.call_stack.pop()?;
- let mut current_module = store.get_module_instance_raw(call_frame.func_instance.1);
+ let mut current_module = store.get_module_instance_raw(call_frame.module_addr);
loop {
match exec_one(&mut call_frame, stack, store, &current_module) {
- // return from the function
- Ok(ExecResult::Return) => return Ok(()),
-
// continue to the next instruction and increment the instruction pointer
Ok(ExecResult::Ok) => call_frame.instr_ptr += 1,
@@ -44,18 +41,25 @@ impl InterpreterRuntime {
// keeping the pointer seperate from the call frame is about 2% faster
// than storing it in the call frame
- if call_frame.func_instance.1 != current_module.id() {
- current_module.swap_with(call_frame.func_instance.1, store);
+ if call_frame.module_addr != current_module.id() {
+ current_module.swap_with(call_frame.module_addr, store);
}
}
+ // return from the function
+ Ok(ExecResult::Return) => {
+ cold();
+ return Ok(());
+ }
+
// trap the program
- Err(error) => {
+ Err(e) => {
+ cold();
call_frame.instr_ptr += 1;
// push the call frame back onto the stack so that it can be resumed
// if the trap can be handled
stack.call_stack.push(call_frame)?;
- return Err(error);
+ return Err(e);
}
}
}
@@ -75,28 +79,17 @@ enum ExecResult {
// this can be a 30%+ performance difference in some cases
#[inline(always)]
fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &ModuleInstance) -> Result<ExecResult> {
- let instrs = &cf.func_instance.0.instructions;
-
- if unlikely(cf.instr_ptr as usize >= instrs.len() || instrs.is_empty()) {
- log::error!("instr_ptr out of bounds: {} >= {}", cf.instr_ptr, instrs.len());
- return Err(Error::Other(format!("instr_ptr out of bounds: {} >= {}", cf.instr_ptr, instrs.len())));
- }
+ let instrs = &cf.func_instance.instructions;
// A match statement is probably the fastest way to do this without
// unreasonable complexity. This *should* be optimized to a jump table.
// See https://pliniker.github.io/post/dispatchers/
use tinywasm_types::Instruction::*;
- match &instrs[cf.instr_ptr as usize] {
+ match instrs.get(cf.instr_ptr as usize).expect("instr_ptr out of bounds, this should never happen") {
Nop => { /* do nothing */ }
- Unreachable => {
- cold();
- return Err(crate::Trap::Unreachable.into());
- }
+ Unreachable => return Err(crate::Trap::Unreachable.into()),
Drop => stack.values.pop().map(|_| ())?,
-
- Select(
- _valtype, // due to validation, we know that the type of the values on the stack are correct
- ) => {
+ Select(_valtype) => {
// due to validation, we know that the type of the values on the stack
let cond: i32 = stack.values.pop()?.into();
let val2 = stack.values.pop()?;
@@ -110,24 +103,32 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
Call(v) => {
// prepare the call frame
- let func_inst = store.get_func(module.resolve_func_addr(*v))?.clone();
-
+ let func_inst = store.get_func(module.resolve_func_addr(*v))?;
let wasm_func = match &func_inst.func {
- crate::Function::Wasm(wasm_func) => wasm_func.clone(),
+ crate::Function::Wasm(wasm_func) => wasm_func,
crate::Function::Host(host_func) => {
- let func = &host_func.func;
+ let func = &host_func.clone();
let params = stack.values.pop_params(&host_func.ty.params)?;
- let res = (func)(FuncContext { store, module_addr: module.id() }, &params)?;
+ let res = (func.func)(FuncContext { store, module_addr: module.id() }, &params)?;
stack.values.extend_from_typed(&res);
return Ok(ExecResult::Ok);
}
};
let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?;
- let call_frame = CallFrame::new(wasm_func, func_inst.owner, params, stack.blocks.len() as u32);
+ let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32);
// push the call frame
cf.instr_ptr += 1; // skip the call instruction
+
+ // this is sometimes faster, and seems more efficient, but sometimes it's also a lot slower
+ // stack.call_stack.push(core::mem::replace(cf, call_frame))?;
+ // if cf.module_addr != module.id() {
+ // module.swap_with(cf.module_addr, store);
+ // }
+ // cf.instr_ptr -= 1;
+ // return Ok(ExecResult::Ok);
+
stack.call_stack.push(cf.clone())?;
stack.call_stack.push(call_frame)?;
@@ -150,10 +151,9 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
let call_ty = module.func_ty(*type_addr);
let wasm_func = match func_inst.func {
- crate::Function::Wasm(ref f) => f.clone(),
+ crate::Function::Wasm(ref f) => f,
crate::Function::Host(host_func) => {
if unlikely(host_func.ty != *call_ty) {
- log::error!("indirect call type mismatch: {:?} != {:?}", host_func.ty, call_ty);
return Err(Trap::IndirectCallTypeMismatch {
actual: host_func.ty.clone(),
expected: call_ty.clone(),
@@ -170,16 +170,14 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
};
if unlikely(wasm_func.ty != *call_ty) {
- log::error!("indirect call type mismatch: {:?} != {:?}", wasm_func.ty, call_ty);
return Err(
Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into()
);
}
let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?;
- let call_frame = CallFrame::new(wasm_func, func_inst.owner, params, stack.blocks.len() as u32);
+ let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32);
- // push the call frame
cf.instr_ptr += 1; // skip the call instruction
stack.call_stack.push(cf.clone())?;
stack.call_stack.push(call_frame)?;
@@ -197,7 +195,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
cf.instr_ptr + *end_offset,
stack.values.len() as u32,
BlockType::If,
- &args.unpack(),
+ &(*args).into(),
module,
),
&mut stack.values,
@@ -207,20 +205,21 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
// falsy value is on the top of the stack
- if *else_offset != 0 {
- let label = BlockFrame::new(
- cf.instr_ptr + *else_offset,
- cf.instr_ptr + *end_offset,
- stack.values.len() as u32,
- BlockType::Else,
- &args.unpack(),
- module,
- );
- cf.instr_ptr += *else_offset;
- cf.enter_block(label, &mut stack.values, &mut stack.blocks);
- } else {
+ if *else_offset == 0 {
cf.instr_ptr += *end_offset;
+ return Ok(ExecResult::Ok);
}
+
+ let label = BlockFrame::new(
+ cf.instr_ptr + *else_offset,
+ cf.instr_ptr + *end_offset,
+ stack.values.len() as u32,
+ BlockType::Else,
+ &(*args).into(),
+ module,
+ );
+ cf.instr_ptr += *else_offset;
+ cf.enter_block(label, &mut stack.values, &mut stack.blocks);
}
Loop(args, end_offset) => {
@@ -254,30 +253,18 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
BrTable(default, len) => {
- let start = cf.instr_ptr + 1;
- let end = cf.instr_ptr + 1 + *len;
- let instr = cf.instructions()[start as usize..end as usize]
- .iter()
- .map(|i| match i {
- BrLabel(l) => Ok(*l),
- _ => {
- cold();
- panic!("Expected BrLabel, this should have been validated by the parser")
- }
- })
- .collect::<Result<Vec<_>>>()?;
-
- if unlikely(instr.len() != *len as usize) {
- panic!(
- "Expected {} BrLabel instructions, got {}, this should have been validated by the parser",
- len,
- instr.len()
- );
+ let start = (cf.instr_ptr + 1) as usize;
+ let end = start + *len as usize;
+ if end > cf.instructions().len() {
+ return Err(Error::Other(format!("br_table out of bounds: {} >= {}", end, cf.instructions().len())));
}
let idx = stack.values.pop_t::<i32>()? as usize;
- let to = instr.get(idx).unwrap_or(default);
- break_to!(cf, stack, to);
+ match cf.instructions()[start..end].get(idx) {
+ None => break_to!(cf, stack, default),
+ Some(BrLabel(to)) => break_to!(cf, stack, to),
+ _ => return Err(Error::Other("br_table with invalid label".to_string())),
+ }
}
Br(v) => break_to!(cf, stack, v),
@@ -294,29 +281,20 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
// We're essentially using else as a EndBlockFrame instruction for if blocks
Else(end_offset) => {
- let block =
- stack.blocks.pop().expect("else: no label to end, this should have been validated by the parser");
-
+ let block = stack.blocks.pop()?;
stack.values.truncate_keep(block.stack_ptr, block.results as u32);
cf.instr_ptr += *end_offset;
}
// remove the label from the label stack
EndBlockFrame => {
- let block = stack
- .blocks
- .pop()
- .expect("end blockframe: no label to end, this should have been validated by the parser");
-
+ let block = stack.blocks.pop()?;
stack.values.truncate_keep(block.stack_ptr, block.results as u32);
}
LocalGet(local_index) => stack.values.push(cf.get_local(*local_index)),
LocalSet(local_index) => cf.set_local(*local_index, stack.values.pop()?),
- LocalTee(local_index) => cf.set_local(
- *local_index,
- *stack.values.last().expect("localtee: stack is empty. this should have been validated by the parser"),
- ),
+ LocalTee(local_index) => cf.set_local(*local_index, *stack.values.last()?),
GlobalGet(global_index) => {
let global = store.get_global_val(module.resolve_global_addr(*global_index))?;
@@ -628,7 +606,6 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
// custom instructions
LocalGet2(a, b) => stack.values.extend_from_slice(&[cf.get_local(*a), cf.get_local(*b)]),
LocalGet3(a, b, c) => stack.values.extend_from_slice(&[cf.get_local(*a), cf.get_local(*b), cf.get_local(*c)]),
-
LocalTeeGet(a, b) => {
#[inline(always)]
fn local_tee_get(cf: &mut CallFrame, stack: &mut Stack, a: u32, b: u32) {
@@ -663,8 +640,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
}
i => {
cold();
- log::error!("unimplemented instruction: {:?}", i);
- return Err(Error::UnsupportedFeature(alloc::format!("unimplemented instruction: {:?}", i)));
+ return Err(Error::UnsupportedFeature(format!("unimplemented instruction: {:?}", i)));
}
};
diff --git a/crates/tinywasm/src/runtime/stack/block_stack.rs b/crates/tinywasm/src/runtime/stack/block_stack.rs
index 2b38cb9..a7b8ece 100644
--- a/crates/tinywasm/src/runtime/stack/block_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/block_stack.rs
@@ -8,7 +8,7 @@ pub(crate) struct BlockStack(Vec<BlockFrame>);
impl BlockStack {
pub(crate) fn new() -> Self {
let mut vec = Vec::new();
- vec.reserve(128); // gives a slight performance over with_capacity
+ vec.reserve(128);
Self(vec)
}
@@ -17,7 +17,7 @@ impl BlockStack {
self.0.len()
}
- #[inline]
+ #[inline(always)]
pub(crate) fn push(&mut self, block: BlockFrame) {
self.0.push(block);
}
@@ -63,7 +63,7 @@ pub(crate) struct BlockFrame {
}
impl BlockFrame {
- #[inline]
+ #[inline(always)]
pub(crate) fn new(
instr_ptr: u32,
end_instr_ptr: u32,
diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs
index d436657..060d530 100644
--- a/crates/tinywasm/src/runtime/stack/call_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/call_stack.rs
@@ -7,8 +7,7 @@ use crate::{Error, Result, Trap};
use super::BlockFrame;
-const CALL_STACK_SIZE: usize = 128;
-const CALL_STACK_MAX_SIZE: usize = 1024;
+const CALL_STACK_SIZE: usize = 1024;
#[derive(Debug)]
pub(crate) struct CallStack {
@@ -18,7 +17,10 @@ pub(crate) struct CallStack {
impl CallStack {
#[inline]
pub(crate) fn new(initial_frame: CallFrame) -> Self {
- let mut stack = Self { stack: Vec::with_capacity(CALL_STACK_SIZE) };
+ let mut stack = Vec::new();
+ stack.reserve_exact(CALL_STACK_SIZE);
+
+ let mut stack = Self { stack: stack };
stack.push(initial_frame).unwrap();
stack
}
@@ -38,7 +40,7 @@ impl CallStack {
#[inline]
pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> {
- if unlikely(self.stack.len() >= CALL_STACK_MAX_SIZE) {
+ if unlikely(self.stack.len() >= CALL_STACK_SIZE) {
return Err(Trap::CallStackOverflow.into());
}
self.stack.push(call_frame);
@@ -50,7 +52,8 @@ impl CallStack {
pub(crate) struct CallFrame {
pub(crate) instr_ptr: u32,
pub(crate) block_ptr: u32,
- pub(crate) func_instance: (Rc<WasmFunction>, ModuleInstanceAddr),
+ pub(crate) func_instance: Rc<WasmFunction>,
+ pub(crate) module_addr: ModuleInstanceAddr,
pub(crate) locals: Box<[RawWasmValue]>,
}
@@ -124,15 +127,15 @@ impl CallFrame {
block_ptr: u32,
) -> Self {
let locals = {
- let local_types = &wasm_func_inst.locals;
- let total_size = local_types.len() + params.len();
- let mut locals = Vec::with_capacity(total_size);
+ let total_size = wasm_func_inst.locals.len() + params.len();
+ let mut locals = Vec::new();
+ locals.reserve_exact(total_size);
locals.extend(params);
locals.resize_with(total_size, RawWasmValue::default);
locals.into_boxed_slice()
};
- Self { instr_ptr: 0, func_instance: (wasm_func_inst, owner), locals, block_ptr }
+ Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, locals, block_ptr }
}
#[inline]
@@ -147,6 +150,6 @@ impl CallFrame {
#[inline(always)]
pub(crate) fn instructions(&self) -> &[Instruction] {
- &self.func_instance.0.instructions
+ &self.func_instance.instructions
}
}
diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs
index aa00a64..354898e 100644
--- a/crates/tinywasm/src/runtime/stack/value_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/value_stack.rs
@@ -126,12 +126,10 @@ impl ValueStack {
#[inline]
pub(crate) fn pop_n_rev(&mut self, n: usize) -> Result<alloc::vec::Drain<'_, RawWasmValue>> {
- let len = self.stack.len();
- if unlikely(len < n) {
+ if unlikely(self.stack.len() < n) {
return Err(Error::ValueStackUnderflow);
}
- let res = self.stack.drain((len - n)..);
- Ok(res)
+ Ok(self.stack.drain((self.stack.len() - n)..))
}
}
diff --git a/crates/tinywasm/tests/generated/2.0.csv b/crates/tinywasm/tests/generated/2.0.csv
index c97b58e..11dd840 100644
--- a/crates/tinywasm/tests/generated/2.0.csv
+++ b/crates/tinywasm/tests/generated/2.0.csv
@@ -2,3 +2,4 @@
0.4.0,27549,334,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":183,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":720,"failed":60},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}]
0.4.1,27551,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}]
0.5.0,27551,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}]
+0.6.1,27572,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}]
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index 96e8810..ee624bd 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -15,8 +15,9 @@ pub enum BlockArgs {
/// This is needed to keep the size of the Instruction enum small.
/// Sadly, using #[repr(u8)] on BlockArgs itself is not possible because of the FuncType variant.
pub struct BlockArgsPacked([u8; 5]); // Modifying this directly can cause runtime errors, but no UB
-impl BlockArgsPacked {
- pub fn new(args: BlockArgs) -> Self {
+
+impl From<BlockArgs> for BlockArgsPacked {
+ fn from(args: BlockArgs) -> Self {
let mut packed = [0; 5];
match args {
BlockArgs::Empty => packed[0] = 0,
@@ -31,11 +32,14 @@ impl BlockArgsPacked {
}
Self(packed)
}
- pub fn unpack(&self) -> BlockArgs {
- match self.0[0] {
+}
+
+impl From<BlockArgsPacked> for BlockArgs {
+ fn from(packed: BlockArgsPacked) -> Self {
+ match packed.0[0] {
0 => BlockArgs::Empty,
- 1 => BlockArgs::Type(ValType::from_byte(self.0[1]).unwrap()),
- 2 => BlockArgs::FuncType(u32::from_le_bytes(self.0[1..].try_into().unwrap())),
+ 1 => BlockArgs::Type(ValType::from_byte(packed.0[1]).unwrap()),
+ 2 => BlockArgs::FuncType(u32::from_le_bytes(packed.0[1..].try_into().unwrap())),
_ => unreachable!(),
}
}
@@ -80,30 +84,27 @@ pub enum ConstInstruction {
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
// should be kept as small as possible (16 bytes max)
+#[rustfmt::skip]
pub enum Instruction {
- // Custom Instructions
+ // > Custom Instructions
BrLabel(LabelAddr),
-
// LocalGet + I32Const + I32Add
// One of the most common patterns in the Rust compiler output
I32LocalGetConstAdd(LocalAddr, i32),
-
// LocalGet + I32Const + I32Store => I32LocalGetConstStore + I32Const
// Also common, helps us skip the stack entirely.
// Has to be followed by an I32Const instruction
I32StoreLocal { local: LocalAddr, const_i32: i32, offset: u32, mem_addr: u8 },
-
// I64Xor + I64Const + I64RotL
// Commonly used by a few crypto libraries
I64XorConstRotl(i64),
-
// LocalTee + LocalGet
LocalTeeGet(LocalAddr, LocalAddr),
LocalGet2(LocalAddr, LocalAddr),
LocalGet3(LocalAddr, LocalAddr, LocalAddr),
LocalGetSet(LocalAddr, LocalAddr),
- // Control Instructions
+ // > Control Instructions
// See <https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions>
Unreachable,
Nop,
@@ -119,12 +120,12 @@ pub enum Instruction {
Call(FuncAddr),
CallIndirect(TypeAddr, TableAddr),
- // Parametric Instructions
+ // > Parametric Instructions
// See <https://webassembly.github.io/spec/core/binary/instructions.html#parametric-instructions>
Drop,
Select(Option<ValType>),
- // Variable Instructions
+ // > Variable Instructions
// See <https://webassembly.github.io/spec/core/binary/instructions.html#variable-instructions>
LocalGet(LocalAddr),
LocalSet(LocalAddr),
@@ -132,7 +133,7 @@ pub enum Instruction {
GlobalGet(GlobalAddr),
GlobalSet(GlobalAddr),
- // Memory Instructions
+ // > Memory Instructions
I32Load { offset: u64, mem_addr: MemAddr },
I64Load { offset: u64, mem_addr: MemAddr },
F32Load { offset: u64, mem_addr: MemAddr },
@@ -159,157 +160,43 @@ pub enum Instruction {
MemorySize(MemAddr, u8),
MemoryGrow(MemAddr, u8),
- // Constants
+ // > Constants
I32Const(i32),
I64Const(i64),
F32Const(f32),
F64Const(f64),
- // Reference Types
+ // > Reference Types
RefNull(ValType),
RefFunc(FuncAddr),
RefIsNull,
- // Numeric Instructions
+ // > Numeric Instructions
// See <https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions>
- I32Eqz,
- I32Eq,
- I32Ne,
- I32LtS,
- I32LtU,
- I32GtS,
- I32GtU,
- I32LeS,
- I32LeU,
- I32GeS,
- I32GeU,
- I64Eqz,
- I64Eq,
- I64Ne,
- I64LtS,
- I64LtU,
- I64GtS,
- I64GtU,
- I64LeS,
- I64LeU,
- I64GeS,
- I64GeU,
- F32Eq,
- F32Ne,
- F32Lt,
- F32Gt,
- F32Le,
- F32Ge,
- F64Eq,
- F64Ne,
- F64Lt,
- F64Gt,
- F64Le,
- F64Ge,
- I32Clz,
- I32Ctz,
- I32Popcnt,
- I32Add,
- I32Sub,
- I32Mul,
- I32DivS,
- I32DivU,
- I32RemS,
- I32RemU,
- I32And,
- I32Or,
- I32Xor,
- I32Shl,
- I32ShrS,
- I32ShrU,
- I32Rotl,
- I32Rotr,
- I64Clz,
- I64Ctz,
- I64Popcnt,
- I64Add,
- I64Sub,
- I64Mul,
- I64DivS,
- I64DivU,
- I64RemS,
- I64RemU,
- I64And,
- I64Or,
- I64Xor,
- I64Shl,
- I64ShrS,
- I64ShrU,
- I64Rotl,
- I64Rotr,
- F32Abs,
- F32Neg,
- F32Ceil,
- F32Floor,
- F32Trunc,
- F32Nearest,
- F32Sqrt,
- F32Add,
- F32Sub,
- F32Mul,
- F32Div,
- F32Min,
- F32Max,
- F32Copysign,
- F64Abs,
- F64Neg,
- F64Ceil,
- F64Floor,
- F64Trunc,
- F64Nearest,
- F64Sqrt,
- F64Add,
- F64Sub,
- F64Mul,
- F64Div,
- F64Min,
- F64Max,
- F64Copysign,
- I32WrapI64,
- I32TruncF32S,
- I32TruncF32U,
- I32TruncF64S,
- I32TruncF64U,
- I32Extend8S,
- I32Extend16S,
- I64Extend8S,
- I64Extend16S,
- I64Extend32S,
- I64ExtendI32S,
- I64ExtendI32U,
- I64TruncF32S,
- I64TruncF32U,
- I64TruncF64S,
- I64TruncF64U,
- F32ConvertI32S,
- F32ConvertI32U,
- F32ConvertI64S,
- F32ConvertI64U,
- F32DemoteF64,
- F64ConvertI32S,
- F64ConvertI32U,
- F64ConvertI64S,
- F64ConvertI64U,
- F64PromoteF32,
- I32ReinterpretF32,
- I64ReinterpretF64,
- F32ReinterpretI32,
- F64ReinterpretI64,
- I32TruncSatF32S,
- I32TruncSatF32U,
- I32TruncSatF64S,
- I32TruncSatF64U,
- I64TruncSatF32S,
- I64TruncSatF32U,
- I64TruncSatF64S,
- I64TruncSatF64U,
+ I32Eqz, I32Eq, I32Ne, I32LtS, I32LtU, I32GtS, I32GtU, I32LeS, I32LeU, I32GeS, I32GeU,
+ I64Eqz, I64Eq, I64Ne, I64LtS, I64LtU, I64GtS, I64GtU, I64LeS, I64LeU, I64GeS, I64GeU,
+ // Comparisons
+ F32Eq, F32Ne, F32Lt, F32Gt, F32Le, F32Ge,
+ F64Eq, F64Ne, F64Lt, F64Gt, F64Le, F64Ge,
+ I32Clz, I32Ctz, I32Popcnt, I32Add, I32Sub, I32Mul, I32DivS, I32DivU, I32RemS, I32RemU,
+ I64Clz, I64Ctz, I64Popcnt, I64Add, I64Sub, I64Mul, I64DivS, I64DivU, I64RemS, I64RemU,
+ // Bitwise
+ I32And, I32Or, I32Xor, I32Shl, I32ShrS, I32ShrU, I32Rotl, I32Rotr,
+ I64And, I64Or, I64Xor, I64Shl, I64ShrS, I64ShrU, I64Rotl, I64Rotr,
+ // Floating Point
+ F32Abs, F32Neg, F32Ceil, F32Floor, F32Trunc, F32Nearest, F32Sqrt, F32Add, F32Sub, F32Mul, F32Div, F32Min, F32Max, F32Copysign,
+ F64Abs, F64Neg, F64Ceil, F64Floor, F64Trunc, F64Nearest, F64Sqrt, F64Add, F64Sub, F64Mul, F64Div, F64Min, F64Max, F64Copysign,
+ I32WrapI64, I32TruncF32S, I32TruncF32U, I32TruncF64S, I32TruncF64U, I32Extend8S, I32Extend16S,
+ I64Extend8S, I64Extend16S, I64Extend32S, I64ExtendI32S, I64ExtendI32U, I64TruncF32S, I64TruncF32U, I64TruncF64S, I64TruncF64U,
+ F32ConvertI32S, F32ConvertI32U, F32ConvertI64S, F32ConvertI64U, F32DemoteF64,
+ F64ConvertI32S, F64ConvertI32U, F64ConvertI64S, F64ConvertI64U, F64PromoteF32,
+ // Reinterpretations (noops at runtime)
+ I32ReinterpretF32, I64ReinterpretF64, F32ReinterpretI32, F64ReinterpretI64,
+ // Saturating Float-to-Int Conversions
+ I32TruncSatF32S, I32TruncSatF32U, I32TruncSatF64S, I32TruncSatF64U,
+ I64TruncSatF32S, I64TruncSatF32U, I64TruncSatF64S, I64TruncSatF64U,
- // Table Instructions
+ // > Table Instructions
TableInit(TableAddr, ElemAddr),
TableGet(TableAddr),
TableSet(TableAddr),
@@ -318,7 +205,7 @@ pub enum Instruction {
TableSize(TableAddr),
TableFill(TableAddr),
- // Bulk Memory Instructions
+ // > Bulk Memory Instructions
MemoryInit(MemAddr, DataAddr),
MemoryCopy(MemAddr, MemAddr),
MemoryFill(MemAddr),
@@ -331,44 +218,37 @@ mod test_blockargs_packed {
#[test]
fn test_empty() {
- let args = BlockArgs::Empty;
- let packed = BlockArgsPacked::new(args);
- assert_eq!(packed.unpack(), BlockArgs::Empty);
+ let packed: BlockArgsPacked = BlockArgs::Empty.into();
+ assert_eq!(BlockArgs::from(packed), BlockArgs::Empty);
}
#[test]
fn test_val_type_i32() {
- let args = BlockArgs::Type(ValType::I32);
- let packed = BlockArgsPacked::new(args);
- assert_eq!(packed.unpack(), BlockArgs::Type(ValType::I32));
+ let packed: BlockArgsPacked = BlockArgs::Type(ValType::I32).into();
+ assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::I32));
}
#[test]
fn test_val_type_i64() {
- let args = BlockArgs::Type(ValType::I64);
- let packed = BlockArgsPacked::new(args);
- assert_eq!(packed.unpack(), BlockArgs::Type(ValType::I64));
+ let packed: BlockArgsPacked = BlockArgs::Type(ValType::I64).into();
+ assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::I64));
}
#[test]
fn test_val_type_f32() {
- let args = BlockArgs::Type(ValType::F32);
- let packed = BlockArgsPacked::new(args);
- assert_eq!(packed.unpack(), BlockArgs::Type(ValType::F32));
+ let packed: BlockArgsPacked = BlockArgs::Type(ValType::F32).into();
+ assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::F32));
}
#[test]
fn test_val_type_f64() {
- let args = BlockArgs::Type(ValType::F64);
- let packed = BlockArgsPacked::new(args);
- assert_eq!(packed.unpack(), BlockArgs::Type(ValType::F64));
+ let packed: BlockArgsPacked = BlockArgs::Type(ValType::F64).into();
+ assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::F64));
}
#[test]
fn test_func_type() {
- let func_type = 123; // Use an arbitrary u32 value
- let args = BlockArgs::FuncType(func_type);
- let packed = BlockArgsPacked::new(args);
- assert_eq!(packed.unpack(), BlockArgs::FuncType(func_type));
+ let packed: BlockArgsPacked = BlockArgs::FuncType(0x12345678).into();
+ assert_eq!(BlockArgs::from(packed), BlockArgs::FuncType(0x12345678));
}
}