summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHenry <mail@henrygressmann.de>2026-03-28 14:36:00 +0100
committerHenry <mail@henrygressmann.de>2026-03-28 14:36:00 +0100
commitaf3029bdc9461b2f8876b0564c3647dba27db97b (patch)
treef238480f6c782ec799760cb0fbb12915a209e5fd /crates
parent430ea402911855e8b8579f0e97b10699f22f758d (diff)
chore: cleanup, make value & block stack fixed size
Signed-off-by: Henry <mail@henrygressmann.de>
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/visit.rs30
-rw-r--r--crates/tinywasm/src/engine.rs84
-rw-r--r--crates/tinywasm/src/error.rs12
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs122
-rw-r--r--crates/tinywasm/src/interpreter/stack/block_stack.rs20
-rw-r--r--crates/tinywasm/src/interpreter/stack/call_stack.rs40
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs208
-rw-r--r--crates/tinywasm/src/interpreter/values.rs61
-rw-r--r--crates/tinywasm/src/store/memory.rs2
-rw-r--r--crates/tinywasm/src/store/mod.rs80
10 files changed, 332 insertions, 327 deletions
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index 8212763..cb9a3d2 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -157,7 +157,6 @@ macro_rules! impl_visit_operator {
(@@tail_call $($rest:tt)* ) => {};
(@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => {
- #[cold]
fn $visit(&mut self $($(,_: $argty)*)?) {
self.unsupported(stringify!($visit))
}
@@ -203,7 +202,11 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
wasmparser::ValType::V128 => Instruction::GlobalSet128(global_index),
wasmparser::ValType::Ref(_) => Instruction::GlobalSetRef(global_index),
}),
- _ => self.visit_unreachable(),
+ _ => {
+ {
+ self.visit_unreachable();
+ };
+ }
}
}
@@ -217,7 +220,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
wasmparser::ValType::V128 => Instruction::Drop128,
wasmparser::ValType::Ref(_) => Instruction::DropRef,
}),
- _ => self.visit_unreachable(),
+ _ => {
+ self.visit_unreachable();
+ }
}
}
@@ -225,7 +230,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
match self.validator.get_operand_type(1) {
Some(Some(t)) => self.visit_typed_select(t),
_ => self.visit_unreachable(),
- }
+ };
}
fn visit_local_get(&mut self, idx: u32) -> Self::Output {
@@ -245,7 +250,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
wasmparser::ValType::V128 => Instruction::LocalGet128(resolved_idx),
wasmparser::ValType::Ref(_) => Instruction::LocalGetRef(resolved_idx),
}),
- _ => self.visit_unreachable(),
+ _ => {
+ self.visit_unreachable();
+ }
}
}
@@ -276,7 +283,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
wasmparser::ValType::V128 => Instruction::LocalCopy128(from, resolved_idx),
wasmparser::ValType::Ref(_) => Instruction::LocalCopyRef(from, resolved_idx),
}),
- _ => self.visit_unreachable(),
+ _ => {
+ self.visit_unreachable();
+ }
}
return;
}
@@ -290,7 +299,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
wasmparser::ValType::V128 => Instruction::LocalSet128(resolved_idx),
wasmparser::ValType::Ref(_) => Instruction::LocalSetRef(resolved_idx),
}),
- _ => self.visit_unreachable(),
+ _ => {
+ self.visit_unreachable();
+ }
}
}
@@ -311,7 +322,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
wasmparser::ValType::V128 => Instruction::LocalTee128(resolved_idx),
wasmparser::ValType::Ref(_) => Instruction::LocalTeeRef(resolved_idx),
}),
- _ => self.visit_unreachable(),
+ _ => {
+ self.visit_unreachable();
+ }
}
}
@@ -483,7 +496,6 @@ macro_rules! impl_visit_simd_operator {
(@@simd $($rest:tt)* ) => {};
(@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => {
- #[cold]
fn $visit(&mut self $($(,$arg: $argty)*)?) {
self.unsupported(stringify!($visit))
}
diff --git a/crates/tinywasm/src/engine.rs b/crates/tinywasm/src/engine.rs
index a70ed58..261f18c 100644
--- a/crates/tinywasm/src/engine.rs
+++ b/crates/tinywasm/src/engine.rs
@@ -39,58 +39,40 @@ pub(crate) struct EngineInner {
// pub(crate) allocator: Box<dyn Allocator + Send + Sync>,
}
-// pub(crate) trait Allocator {}
-// pub(crate) struct DefaultAllocator;
-// impl Allocator for DefaultAllocator {}
-
/// Default initial size for the 32-bit value stack (i32, f32 values).
-pub const DEFAULT_VALUE_STACK_32_INIT_SIZE: usize = 32 * 1024; // 32KB
+pub const DEFAULT_VALUE_STACK_32_SIZE: usize = 64 * 1024; // 64k slots
/// Default initial size for the 64-bit value stack (i64, f64 values).
-pub const DEFAULT_VALUE_STACK_64_INIT_SIZE: usize = 16 * 1024; // 16KB
+pub const DEFAULT_VALUE_STACK_64_SIZE: usize = 32 * 1024; // 32k slots
/// Default initial size for the 128-bit value stack (v128 values).
-pub const DEFAULT_VALUE_STACK_128_INIT_SIZE: usize = 8 * 1024; // 8KB
+pub const DEFAULT_VALUE_STACK_128_SIZE: usize = 4 * 1024; // 4k slots
/// Default initial size for the reference value stack (funcref, externref values).
-pub const DEFAULT_VALUE_STACK_REF_INIT_SIZE: usize = 1024; // 1KB
+pub const DEFAULT_VALUE_STACK_REF_SIZE: usize = 4 * 1024; // 4k slots
-/// Default initial size for the block stack.
-pub const DEFAULT_BLOCK_STACK_INIT_SIZE: usize = 128;
+/// Default initial size for the block stack (control frames).
+pub const DEFAULT_BLOCK_STACK_SIZE: usize = 1024; // 1024 frames
-/// Default initial size for the call stack.
-pub const DEFAULT_CALL_STACK_INIT_SIZE: usize = 128;
+/// Default initial size for the call stack (function frames).
+pub const DEFAULT_CALL_STACK_SIZE: usize = 1024; // 1024 frames
/// Configuration for the WebAssembly interpreter
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Config {
/// Initial size of the 32-bit value stack (i32, f32 values).
- pub stack_32_init_size: usize,
+ pub stack_32_size: usize,
/// Initial size of the 64-bit value stack (i64, f64 values).
- pub stack_64_init_size: usize,
+ pub stack_64_size: usize,
/// Initial size of the 128-bit value stack (v128 values).
- pub stack_128_init_size: usize,
+ pub stack_128_size: usize,
/// Initial size of the reference value stack (funcref, externref values).
- pub stack_ref_init_size: usize,
- /// Optional maximum sizes for the stacks. If set, the interpreter will enforce these limits and return an error if they are exceeded.
- pub stack_32_max_size: Option<usize>,
- /// Optional maximum sizes for the stacks. If set, the interpreter will enforce these limits and return an error if they are exceeded.
- pub stack_64_max_size: Option<usize>,
- /// Optional maximum sizes for the stacks. If set, the interpreter will enforce these limits and return an error if they are exceeded.
- pub stack_128_max_size: Option<usize>,
- /// Optional maximum sizes for the stacks. If set, the interpreter will enforce these limits and return an error if they are exceeded.
- pub stack_ref_max_size: Option<usize>,
-
+ pub stack_ref_size: usize,
/// Initial size of the call stack.
- pub call_stack_init_size: usize,
- /// The maximum size of the call stack. If set, the interpreter will enforce this limit and return an error if it is exceeded.
- pub call_stack_max_size: Option<usize>,
-
+ pub call_stack_size: usize,
/// Initial size of the control stack (block stack).
- pub block_stack_init_size: usize,
- /// Optional maximum size for the control stack (block stack). If set, the interpreter will enforce this limit and return an error if it is exceeded.
- pub block_stack_max_size: Option<usize>,
+ pub block_stack_size: usize,
}
impl Config {
@@ -98,43 +80,17 @@ impl Config {
pub fn new() -> Self {
Self::default()
}
-
- /// Set the same maximum size for all stacks. If set, the interpreter will enforce this limit and return an error if it is exceeded.
- pub fn with_max_stack_size(mut self, max_size: usize) -> Self {
- self.stack_32_max_size = Some(max_size);
- self.stack_64_max_size = Some(max_size);
- self.stack_128_max_size = Some(max_size);
- self.stack_ref_max_size = Some(max_size);
- self.block_stack_max_size = Some(max_size);
- self
- }
-
- /// Set the same initial size for all stacks.
- pub fn with_initial_stack_size(mut self, init_size: usize) -> Self {
- self.stack_32_init_size = init_size;
- self.stack_64_init_size = init_size;
- self.stack_128_init_size = init_size;
- self.stack_ref_init_size = init_size;
- self.block_stack_init_size = init_size;
- self
- }
}
impl Default for Config {
fn default() -> Self {
Self {
- stack_32_init_size: DEFAULT_VALUE_STACK_32_INIT_SIZE,
- stack_64_init_size: DEFAULT_VALUE_STACK_64_INIT_SIZE,
- stack_128_init_size: DEFAULT_VALUE_STACK_128_INIT_SIZE,
- stack_ref_init_size: DEFAULT_VALUE_STACK_REF_INIT_SIZE,
- block_stack_init_size: DEFAULT_BLOCK_STACK_INIT_SIZE,
- call_stack_init_size: DEFAULT_CALL_STACK_INIT_SIZE,
- call_stack_max_size: None,
- stack_32_max_size: None,
- stack_64_max_size: None,
- stack_128_max_size: None,
- stack_ref_max_size: None,
- block_stack_max_size: None,
+ stack_32_size: DEFAULT_VALUE_STACK_32_SIZE,
+ stack_64_size: DEFAULT_VALUE_STACK_64_SIZE,
+ stack_128_size: DEFAULT_VALUE_STACK_128_SIZE,
+ stack_ref_size: DEFAULT_VALUE_STACK_REF_SIZE,
+ call_stack_size: DEFAULT_CALL_STACK_SIZE,
+ block_stack_size: DEFAULT_BLOCK_STACK_SIZE,
}
}
}
diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs
index 4b3a969..4788ac4 100644
--- a/crates/tinywasm/src/error.rs
+++ b/crates/tinywasm/src/error.rs
@@ -1,8 +1,8 @@
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::{fmt::Display, ops::ControlFlow};
-use tinywasm_types::FuncType;
use tinywasm_types::archive::TwasmError;
+use tinywasm_types::FuncType;
#[cfg(feature = "parser")]
pub use tinywasm_parser::ParseError;
@@ -121,6 +121,12 @@ pub enum Trap {
/// Call stack overflow
CallStackOverflow,
+ /// Block stack overflow
+ BlockStackOverflow,
+
+ /// Value stack overflow
+ ValueStackOverflow,
+
/// An undefined element was encountered
UndefinedElement {
/// The element index
@@ -153,6 +159,8 @@ impl Trap {
Self::InvalidConversionToInt => "invalid conversion to integer",
Self::IntegerOverflow => "integer overflow",
Self::CallStackOverflow => "call stack exhausted",
+ Self::BlockStackOverflow => "block stack exhausted",
+ Self::ValueStackOverflow => "value stack exhausted",
Self::UndefinedElement { .. } => "undefined element",
Self::UninitializedElement { .. } => "uninitialized element",
Self::IndirectCallTypeMismatch { .. } => "indirect call type mismatch",
@@ -235,6 +243,8 @@ impl Display for Trap {
Self::InvalidConversionToInt => write!(f, "invalid conversion to integer"),
Self::IntegerOverflow => write!(f, "integer overflow"),
Self::CallStackOverflow => write!(f, "call stack exhausted"),
+ Self::BlockStackOverflow => write!(f, "block stack exhausted"),
+ Self::ValueStackOverflow => write!(f, "value stack exhausted"),
Self::UndefinedElement { index } => write!(f, "undefined element: index={index}"),
Self::UninitializedElement { index } => {
write!(f, "uninitialized element: index={index}")
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index 8d2e211..dcdd2f8 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -80,33 +80,33 @@ impl<'store> Executor<'store> {
Drop64 => self.store.stack.values.drop::<Value64>(),
Drop128 => self.store.stack.values.drop::<Value128>(),
DropRef => self.store.stack.values.drop::<ValueRef>(),
- Select32 => self.store.stack.values.select::<Value32>(),
- Select64 => self.store.stack.values.select::<Value64>(),
- Select128 => self.store.stack.values.select::<Value128>(),
- SelectRef => self.store.stack.values.select::<ValueRef>(),
+ Select32 => self.store.stack.values.select::<Value32>().to_cf()?,
+ Select64 => self.store.stack.values.select::<Value64>().to_cf()?,
+ Select128 => self.store.stack.values.select::<Value128>().to_cf()?,
+ SelectRef => self.store.stack.values.select::<ValueRef>().to_cf()?,
Call(v) => return self.exec_call_direct::<false>(*v),
CallIndirect(ty, table) => return self.exec_call_indirect::<false>(*ty, *table),
ReturnCall(v) => return self.exec_call_direct::<true>(*v),
ReturnCallIndirect(ty, table) => return self.exec_call_indirect::<true>(*ty, *table),
- If(end, el) => self.exec_if(*end, *el, (StackHeight::default(), StackHeight::default())),
- IfWithType(ty, end, el) => self.exec_if(*end, *el, (StackHeight::default(), (*ty).into())),
- IfWithFuncType(ty, end, el) => self.exec_if(*end, *el, self.resolve_functype(*ty)),
+ If(end, el) => self.exec_if(*end, *el, (StackHeight::default(), StackHeight::default())).to_cf()?,
+ IfWithType(ty, end, el) => self.exec_if(*end, *el, (StackHeight::default(), (*ty).into())).to_cf()?,
+ IfWithFuncType(ty, end, el) => self.exec_if(*end, *el, self.resolve_functype(*ty)).to_cf()?,
Else(end_offset) => self.exec_else(*end_offset),
- Loop(end) => self.enter_block(*end, BlockType::Loop, (StackHeight::default(), StackHeight::default())),
- LoopWithType(ty, end) => self.enter_block(*end, BlockType::Loop, (StackHeight::default(), (*ty).into())),
- LoopWithFuncType(ty, end) => self.enter_block(*end, BlockType::Loop, self.resolve_functype(*ty)),
- Block(end) => self.enter_block(*end, BlockType::Block, (StackHeight::default(), StackHeight::default())),
- BlockWithType(ty, end) => self.enter_block(*end, BlockType::Block, (StackHeight::default(), (*ty).into())),
- BlockWithFuncType(ty, end) => self.enter_block(*end, BlockType::Block, self.resolve_functype(*ty)),
+ Loop(end) => self.enter_block(*end, BlockType::Loop, (StackHeight::default(), StackHeight::default())).to_cf()?,
+ LoopWithType(ty, end) => self.enter_block(*end, BlockType::Loop, (StackHeight::default(), (*ty).into())).to_cf()?,
+ LoopWithFuncType(ty, end) => self.enter_block(*end, BlockType::Loop, self.resolve_functype(*ty)).to_cf()?,
+ Block(end) => self.enter_block(*end, BlockType::Block, (StackHeight::default(), StackHeight::default())).to_cf()?,
+ BlockWithType(ty, end) => self.enter_block(*end, BlockType::Block, (StackHeight::default(), (*ty).into())).to_cf()?,
+ BlockWithFuncType(ty, end) => self.enter_block(*end, BlockType::Block, self.resolve_functype(*ty)).to_cf()?,
Br(v) => return self.exec_br(*v),
BrIf(v) => return self.exec_br_if(*v),
BrTable(default, len) => return self.exec_brtable(*default, *len),
Return => return self.exec_return(),
EndBlockFrame => self.exec_end_block(),
- LocalGet32(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value32>(*local_index)),
- LocalGet64(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value64>(*local_index)),
- LocalGet128(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value128>(*local_index)),
- LocalGetRef(local_index) => self.store.stack.values.push(self.cf.locals.get::<ValueRef>(*local_index)),
+ LocalGet32(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value32>(*local_index)).to_cf()?,
+ LocalGet64(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value64>(*local_index)).to_cf()?,
+ LocalGet128(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value128>(*local_index)).to_cf()?,
+ LocalGetRef(local_index) => self.store.stack.values.push(self.cf.locals.get::<ValueRef>(*local_index)).to_cf()?,
LocalSet32(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.pop::<Value32>()),
LocalSet64(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.pop::<Value64>()),
LocalSet128(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.pop::<Value128>()),
@@ -119,15 +119,15 @@ impl<'store> Executor<'store> {
LocalTee64(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.peek::<Value64>()),
LocalTee128(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.peek::<Value128>()),
LocalTeeRef(local_index) => self.cf.locals.set(*local_index, self.store.stack.values.peek::<ValueRef>()),
- GlobalGet(global_index) => self.exec_global_get(*global_index),
+ GlobalGet(global_index) => self.exec_global_get(*global_index).to_cf()?,
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.exec_const(*val),
- I64Const(val) => self.exec_const(*val),
- F32Const(val) => self.exec_const(*val),
- F64Const(val) => self.exec_const(*val),
+ I32Const(val) => self.exec_const(*val).to_cf()?,
+ I64Const(val) => self.exec_const(*val).to_cf()?,
+ F32Const(val) => self.exec_const(*val).to_cf()?,
+ F64Const(val) => self.exec_const(*val).to_cf()?,
I64Eqz => stack_op!(unary i64 => i32, |v| i32::from(v == 0)),
I32Eqz => stack_op!(unary i32, |v| i32::from(v == 0)),
I32Eq => stack_op!(binary i32, |a, b| i32::from(a == b)),
@@ -208,11 +208,11 @@ impl<'store> Executor<'store> {
I64Popcnt => stack_op!(unary i64, |v| i64::from(v.count_ones())),
// Reference types
- 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),
+ RefFunc(func_idx) => self.exec_const::<ValueRef>(Some(*func_idx)).to_cf()?,
+ RefNull(_) => self.exec_const::<ValueRef>(None).to_cf()?,
+ RefIsNull => self.exec_ref_is_null().to_cf()?,
+ MemorySize(addr) => self.exec_memory_size(*addr).to_cf()?,
+ MemoryGrow(addr) => self.exec_memory_grow(*addr).to_cf()?,
// Bulk memory operations
MemoryCopy(from, to) => self.exec_memory_copy(*from, *to).to_cf()?,
@@ -342,7 +342,7 @@ impl<'store> Executor<'store> {
V128Store64Lane(arg, lane) => self.exec_mem_store_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?,
V128Load32Zero(arg) => self.exec_mem_load::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i32x4([v, 0, 0, 0]))?,
V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i64x2([v, 0]))?,
- V128Const(arg) => self.exec_const::<Value128>(self.cf.data().v128_constants[*arg as usize].into()),
+ V128Const(arg) => self.exec_const::<Value128>(self.cf.data().v128_constants[*arg as usize].into()).to_cf()?,
I8x16ExtractLaneS(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i8(*lane) as i32),
I8x16ExtractLaneU(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_u8(*lane) as i32),
I16x8ExtractLaneS(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i16(*lane) as i32),
@@ -573,7 +573,7 @@ impl<'store> Executor<'store> {
let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals);
let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.store.stack.blocks.len() as u32);
self.cf.incr_instr_ptr(); // skip the call instruction
- self.store.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
+ self.store.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame)).to_cf()?;
}
self.module.swap_with(self.cf.module_addr(), self.store);
@@ -582,7 +582,7 @@ impl<'store> Executor<'store> {
fn exec_call_host(&mut self, host_func: Rc<imports::HostFunction>) -> ControlFlow<Option<Error>> {
let params = self.store.stack.values.pop_types(&host_func.ty.params).collect::<Box<_>>();
let res = host_func.call(FuncContext { store: self.store, module_addr: self.module.id() }, &params).to_cf()?;
- self.store.stack.values.extend_from_wasmvalues(&res);
+ self.store.stack.values.extend_from_wasmvalues(&res).to_cf()?;
self.cf.incr_instr_ptr();
ControlFlow::Continue(())
}
@@ -635,21 +635,26 @@ impl<'store> Executor<'store> {
}
}
- fn exec_if(&mut self, else_offset: u32, end_offset: u32, (params, results): (StackHeight, StackHeight)) {
+ fn exec_if(
+ &mut self,
+ else_offset: u32,
+ end_offset: u32,
+ (params, results): (StackHeight, StackHeight),
+ ) -> Result<()> {
// truthy value is on the top of the stack, so enter the then block
if self.store.stack.values.pop::<i32>() != 0 {
- self.enter_block(end_offset, BlockType::If, (params, results));
- return;
+ self.enter_block(end_offset, BlockType::If, (params, results))?;
+ return Ok(());
}
// falsy value is on the top of the stack
if else_offset == 0 {
self.cf.jump(end_offset);
- return;
+ return Ok(());
}
self.cf.jump(else_offset);
- self.enter_block(end_offset - else_offset, BlockType::Else, (params, results));
+ self.enter_block(end_offset - else_offset, BlockType::Else, (params, results))
}
fn exec_else(&mut self, end_offset: u32) {
self.exec_end_block();
@@ -659,7 +664,12 @@ impl<'store> Executor<'store> {
let ty = self.module.func_ty(idx);
((&*ty.params).into(), (&*ty.results).into())
}
- fn enter_block(&mut self, 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),
+ ) -> Result<()> {
self.store.stack.blocks.push(BlockFrame {
instr_ptr: self.cf.instr_ptr() as u32,
end_instr_offset,
@@ -667,7 +677,7 @@ impl<'store> Executor<'store> {
results,
params,
ty,
- });
+ })
}
fn exec_br(&mut self, to: u32) -> ControlFlow<Option<Error>> {
if self.cf.break_to(to, &mut self.store.stack.values, &mut self.store.stack.blocks).is_none() {
@@ -730,25 +740,23 @@ impl<'store> Executor<'store> {
self.store.stack.values.truncate_keep(block.stack_ptr, block.results);
}
- fn exec_global_get(&mut self, global_index: u32) {
- self.store
- .stack
- .values
- .push_dyn(self.store.state.get_global_val(self.module.resolve_global_addr(global_index)));
+ fn exec_global_get(&mut self, global_index: u32) -> Result<()> {
+ self.store.stack.values.push_dyn(self.store.state.get_global_val(self.module.resolve_global_addr(global_index)))
}
+
fn exec_global_set<T: InternalValue>(&mut self, global_index: u32) {
let val = self.store.stack.values.pop::<T>().into();
self.store.state.set_global_val(self.module.resolve_global_addr(global_index), val);
}
- fn exec_const<T: InternalValue>(&mut self, val: T) {
- self.store.stack.values.push(val);
+ fn exec_const<T: InternalValue>(&mut self, val: T) -> Result<()> {
+ self.store.stack.values.push(val)
}
- fn exec_ref_is_null(&mut self) {
+ fn exec_ref_is_null(&mut self) -> Result<()> {
let is_null = i32::from(self.store.stack.values.pop::<ValueRef>().is_none());
- self.store.stack.values.push::<i32>(is_null);
+ self.store.stack.values.push::<i32>(is_null)
}
- fn exec_memory_size(&mut self, addr: u32) {
+ fn exec_memory_size(&mut self, addr: u32) -> Result<()> {
let mem = self.store.state.get_mem(self.module.resolve_mem_addr(addr));
match mem.is_64bit() {
@@ -756,7 +764,7 @@ impl<'store> Executor<'store> {
false => self.store.stack.values.push::<i32>(mem.page_count as i32),
}
}
- fn exec_memory_grow(&mut self, addr: u32) {
+ fn exec_memory_grow(&mut self, addr: u32) -> Result<()> {
let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(addr));
let prev_size = mem.page_count;
@@ -772,9 +780,11 @@ impl<'store> Executor<'store> {
None => -1_i64,
},
) {
- (true, size) => self.store.stack.values.push::<i64>(size),
- (false, size) => self.store.stack.values.push::<i32>(size as i32),
+ (true, size) => self.store.stack.values.push::<i64>(size)?,
+ (false, size) => self.store.stack.values.push::<i32>(size as i32)?,
};
+
+ Ok(())
}
fn exec_memory_copy(&mut self, from: u32, to: u32) -> Result<()> {
@@ -871,7 +881,7 @@ impl<'store> Executor<'store> {
let offset = lane as usize * LOAD_SIZE;
imm[offset..offset + LOAD_SIZE].copy_from_slice(&val);
- self.store.stack.values.push(Value128::from_mem_bytes(imm));
+ self.store.stack.values.push(Value128::from_mem_bytes(imm)).to_cf()?;
ControlFlow::Continue(())
}
@@ -896,7 +906,7 @@ impl<'store> Executor<'store> {
})));
};
let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?;
- self.store.stack.values.push(cast(val));
+ self.store.stack.values.push(cast(val)).to_cf()?;
ControlFlow::Continue(())
}
@@ -950,7 +960,7 @@ impl<'store> Executor<'store> {
let idx: i32 = self.store.stack.values.pop::<i32>();
let table = self.store.state.get_table(self.module.resolve_table_addr(table_index));
let v = table.get_wasm_val(idx as u32)?;
- self.store.stack.values.push_dyn(v.into());
+ self.store.stack.values.push_dyn(v.into())?;
Ok(())
}
fn exec_table_set(&mut self, table_index: u32) -> Result<()> {
@@ -961,7 +971,7 @@ impl<'store> Executor<'store> {
}
fn exec_table_size(&mut self, table_index: u32) -> Result<()> {
let table = self.store.state.get_table(self.module.resolve_table_addr(table_index));
- self.store.stack.values.push(table.size());
+ self.store.stack.values.push(table.size())?;
Ok(())
}
fn exec_table_init(&mut self, elem_index: u32, table_index: u32) -> Result<()> {
@@ -1012,8 +1022,8 @@ impl<'store> Executor<'store> {
let val = self.store.stack.values.pop::<ValueRef>();
match table.grow(n, val.into()) {
- Ok(()) => self.store.stack.values.push(sz),
- Err(_) => self.store.stack.values.push(-1_i32),
+ Ok(()) => self.store.stack.values.push(sz)?,
+ Err(_) => self.store.stack.values.push(-1_i32)?,
}
Ok(())
diff --git a/crates/tinywasm/src/interpreter/stack/block_stack.rs b/crates/tinywasm/src/interpreter/stack/block_stack.rs
index e4d4c28..68dda84 100644
--- a/crates/tinywasm/src/interpreter/stack/block_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/block_stack.rs
@@ -2,30 +2,33 @@ use crate::engine::Config;
use alloc::vec::Vec;
use crate::interpreter::values::{StackHeight, StackLocation};
+use crate::{Result, Trap};
#[derive(Debug)]
pub(crate) struct BlockStack(Vec<BlockFrame>);
impl BlockStack {
pub(crate) fn new(config: &Config) -> Self {
- Self(Vec::with_capacity(config.block_stack_init_size))
+ Self(Vec::with_capacity(config.block_stack_size))
}
pub(crate) fn clear(&mut self) {
self.0.clear();
}
- #[inline(always)]
pub(crate) fn len(&self) -> usize {
self.0.len()
}
- #[inline(always)]
- pub(crate) fn push(&mut self, block: BlockFrame) {
+ pub(crate) fn push(&mut self, block: BlockFrame) -> Result<()> {
+ if self.0.len() >= self.0.capacity() {
+ return Err(Trap::BlockStackOverflow.into());
+ }
+
self.0.push(block);
+ Ok(())
}
- #[inline]
/// get the label at the given index, where 0 is the top of the stack
pub(crate) fn get_relative_to(&self, index: u32, offset: u32) -> Option<&BlockFrame> {
let len = (self.0.len() as u32) - offset;
@@ -38,13 +41,14 @@ impl BlockStack {
Some(&self.0[self.0.len() - index as usize - 1])
}
- #[inline(always)]
pub(crate) fn pop(&mut self) -> BlockFrame {
- self.0.pop().expect("block stack underflow, this is a bug")
+ match self.0.pop() {
+ Some(frame) => frame,
+ None => unreachable!("Block stack underflow, this is a bug"),
+ }
}
/// keep the top `len` blocks and discard the rest
- #[inline(always)]
pub(crate) fn truncate(&mut self, len: u32) {
self.0.truncate(len as usize);
}
diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs
index 4b0fad6..688dde8 100644
--- a/crates/tinywasm/src/interpreter/stack/call_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs
@@ -1,43 +1,36 @@
-use core::ops::ControlFlow;
-
use super::BlockType;
-use crate::Trap;
use crate::interpreter::{Value128, values::*};
-use crate::{Error, unlikely};
+use crate::{Result, Trap, unlikely};
use alloc::boxed::Box;
use alloc::{rc::Rc, vec::Vec};
use tinywasm_types::{ArcSlice, Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmFunctionData, WasmValue};
-pub(crate) const MAX_CALL_STACK_SIZE: usize = 1024;
-
#[derive(Debug)]
pub(crate) struct CallStack {
stack: Vec<CallFrame>,
}
impl CallStack {
- #[inline]
pub(crate) fn new(config: &crate::engine::Config) -> Self {
- Self { stack: Vec::with_capacity(config.call_stack_init_size) }
+ Self { stack: Vec::with_capacity(config.call_stack_size) }
}
pub(crate) fn clear(&mut self) {
self.stack.clear();
}
- #[inline]
pub(crate) fn pop(&mut self) -> Option<CallFrame> {
self.stack.pop()
}
- #[inline]
- pub(crate) fn push(&mut self, call_frame: CallFrame) -> ControlFlow<Option<Error>> {
- if unlikely((self.stack.len() + 1) >= MAX_CALL_STACK_SIZE) {
- return ControlFlow::Break(Some(Trap::CallStackOverflow.into()));
+ pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> {
+ if unlikely(self.stack.len() >= self.stack.capacity()) {
+ return Err(Trap::CallStackOverflow.into());
}
+
self.stack.push(call_frame);
- ControlFlow::Continue(())
+ Ok(())
}
}
@@ -69,42 +62,34 @@ impl Locals {
}
impl CallFrame {
- #[inline]
pub(crate) fn instr_ptr(&self) -> usize {
self.instr_ptr
}
- #[inline]
- #[allow(dead_code)]
pub(crate) fn data(&self) -> &WasmFunctionData {
&self.func_instance.data
}
- #[inline(always)]
pub(crate) fn incr_instr_ptr(&mut self) {
self.instr_ptr += 1;
}
- #[inline]
pub(crate) fn jump(&mut self, offset: u32) {
self.instr_ptr += offset as usize;
}
- #[inline]
pub(crate) fn module_addr(&self) -> ModuleInstanceAddr {
self.module_addr
}
#[inline(always)]
pub(crate) fn fetch_instr(&self) -> &Instruction {
- self
- .func_instance
- .instructions
- .get(self.instr_ptr)
- .unwrap_or_else(|| unreachable!("Instruction pointer out of bounds, this is a bug"))
+ match self.func_instance.instructions.get(self.instr_ptr) {
+ Some(instr) => instr,
+ None => unreachable!("Instruction pointer out of bounds, this is a bug"),
+ }
}
- #[inline]
pub(crate) fn block_ptr(&self) -> u32 {
self.block_ptr
}
@@ -125,7 +110,6 @@ impl CallFrame {
/// Break to a block at the given index (relative to the current frame)
/// Returns `None` if there is no block at the given index (e.g. if we need to return, this is handled by the caller)
- #[inline]
pub(crate) fn break_to(
&mut self,
break_to_relative: u32,
@@ -168,7 +152,6 @@ impl CallFrame {
Some(())
}
- #[inline]
pub(crate) fn new(
func_instance: Rc<WasmFunction>,
module_addr: ModuleInstanceAddr,
@@ -206,7 +189,6 @@ impl CallFrame {
Self { instr_ptr: 0, func_instance, module_addr, block_ptr, locals }
}
- #[inline]
pub(crate) fn new_raw(
func_instance: Rc<WasmFunction>,
module_addr: ModuleInstanceAddr,
diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index cec08a3..b579a04 100644
--- a/crates/tinywasm/src/interpreter/stack/value_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs
@@ -1,25 +1,108 @@
+use alloc::boxed::Box;
use alloc::vec::Vec;
use tinywasm_types::{ExternRef, FuncRef, ValType, ValueCounts, ValueCountsSmall, WasmValue};
-use crate::{Result, engine::Config, interpreter::*};
+use crate::{Result, Trap, engine::Config, interpreter::*};
use super::Locals;
#[derive(Debug)]
pub(crate) struct ValueStack {
- pub(crate) stack_32: Vec<Value32>,
- pub(crate) stack_64: Vec<Value64>,
- pub(crate) stack_128: Vec<Value128>,
- pub(crate) stack_ref: Vec<ValueRef>,
+ pub(crate) stack_32: Stack<Value32>,
+ pub(crate) stack_64: Stack<Value64>,
+ pub(crate) stack_128: Stack<Value128>,
+ pub(crate) stack_ref: Stack<ValueRef>,
+}
+
+#[derive(Debug)]
+pub(crate) struct Stack<T> {
+ data: Box<[T]>,
+ len: usize,
+}
+
+impl<T: Copy + Default> Stack<T> {
+ pub(crate) fn with_size(size: usize) -> Self {
+ let mut data = Vec::with_capacity(size);
+ data.resize_with(size, T::default);
+ Self { data: data.into_boxed_slice(), len: 0 }
+ }
+
+ pub(crate) fn len(&self) -> usize {
+ self.len
+ }
+
+ pub(crate) fn clear(&mut self) {
+ self.len = 0;
+ }
+
+ pub(crate) fn push(&mut self, value: T) -> Result<()> {
+ if self.len >= self.data.len() {
+ return Err(Trap::ValueStackOverflow.into());
+ }
+
+ self.data[self.len] = value;
+ self.len += 1;
+ Ok(())
+ }
+
+ pub(crate) fn pop(&mut self) -> T {
+ if self.len == 0 {
+ unreachable!("ValueStack underflow, this is a bug");
+ }
+
+ self.len -= 1;
+ self.data[self.len]
+ }
+
+ pub(crate) fn last(&self) -> &T {
+ if self.len == 0 {
+ unreachable!("ValueStack underflow, this is a bug");
+ }
+ &self.data[self.len - 1]
+ }
+
+ pub(crate) fn last_mut(&mut self) -> &mut T {
+ if self.len == 0 {
+ unreachable!("ValueStack underflow, this is a bug");
+ }
+ &mut self.data[self.len - 1]
+ }
+
+ pub(crate) fn truncate_keep(&mut self, n: usize, end_keep: usize) {
+ if self.len <= n {
+ return;
+ }
+
+ let keep_tail = end_keep.min(self.len - n);
+ if keep_tail == 0 {
+ self.len = n;
+ return;
+ }
+
+ let tail_start = self.len - keep_tail;
+ self.data.copy_within(tail_start..self.len, n);
+ self.len = n + keep_tail;
+ }
+
+ pub(crate) fn pop_to_locals(&mut self, param_count: usize, local_count: usize) -> Box<[T]> {
+ let mut locals = alloc::vec![T::default(); local_count].into_boxed_slice();
+ let start =
+ self.len.checked_sub(param_count).unwrap_or_else(|| unreachable!("value stack underflow, this is a bug"));
+ debug_assert!(param_count <= local_count, "param count exceeds local count");
+
+ locals[..param_count].copy_from_slice(&self.data[start..self.len]);
+ self.len = start;
+ locals
+ }
}
impl ValueStack {
pub(crate) fn new(config: &Config) -> Self {
Self {
- stack_32: Vec::with_capacity(config.stack_32_init_size),
- stack_64: Vec::with_capacity(config.stack_64_init_size),
- stack_128: Vec::with_capacity(config.stack_128_init_size),
- stack_ref: Vec::with_capacity(config.stack_ref_init_size),
+ stack_32: Stack::with_size(config.stack_32_size),
+ stack_64: Stack::with_size(config.stack_64_size),
+ stack_128: Stack::with_size(config.stack_128_size),
+ stack_ref: Stack::with_size(config.stack_ref_size),
}
}
@@ -43,86 +126,73 @@ impl ValueStack {
self.stack_32.len() + self.stack_64.len() + self.stack_128.len() + self.stack_ref.len()
}
- #[inline]
pub(crate) fn peek<T: InternalValue>(&self) -> T {
T::stack_peek(self)
}
- #[inline]
pub(crate) fn pop<T: InternalValue>(&mut self) -> T {
T::stack_pop(self)
}
- #[inline]
- pub(crate) fn push<T: InternalValue>(&mut self, value: T) {
- T::stack_push(self, value);
+ pub(crate) fn push<T: InternalValue>(&mut self, value: T) -> Result<()> {
+ T::stack_push(self, value)
}
- #[inline]
pub(crate) fn drop<T: InternalValue>(&mut self) {
T::stack_pop(self);
}
- #[inline]
- pub(crate) fn select<T: InternalValue>(&mut self) {
+ pub(crate) fn select<T: InternalValue>(&mut self) -> Result<()> {
let cond: i32 = self.pop();
let val2: T = self.pop();
if cond == 0 {
self.drop::<T>();
- self.push(val2);
+ self.push(val2)?;
}
+ Ok(())
}
- #[inline]
pub(crate) fn binary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
T::stack_calculate(self, func)
}
- #[inline]
- #[allow(dead_code)]
pub(crate) fn ternary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
T::stack_calculate3(self, func)
}
- #[inline]
pub(crate) fn binary<T: InternalValue, U: InternalValue>(
&mut self,
func: impl FnOnce(T, T) -> Result<U>,
) -> Result<()> {
let v2 = T::stack_pop(self);
let v1 = T::stack_pop(self);
- U::stack_push(self, func(v1, v2)?);
+ U::stack_push(self, func(v1, v2)?)?;
Ok(())
}
- #[inline]
- #[allow(dead_code)]
pub(crate) fn binary_diff<A: InternalValue, B: InternalValue, RES: InternalValue>(
&mut self,
func: impl FnOnce(A, B) -> Result<RES>,
) -> Result<()> {
let v2 = B::stack_pop(self);
let v1 = A::stack_pop(self);
- RES::stack_push(self, func(v1, v2)?);
+ RES::stack_push(self, func(v1, v2)?)?;
Ok(())
}
- #[inline]
pub(crate) fn unary<T: InternalValue, U: InternalValue>(
&mut self,
func: impl FnOnce(T) -> Result<U>,
) -> Result<()> {
let v1 = T::stack_pop(self);
- U::stack_push(self, func(v1)?);
+ U::stack_push(self, func(v1)?)?;
Ok(())
}
- #[inline]
pub(crate) fn unary_same<T: InternalValue>(&mut self, func: impl Fn(T) -> Result<T>) -> Result<()> {
T::replace_top(self, func)
}
- #[inline]
pub(crate) fn pop_types<'a>(
&'a mut self,
val_types: impl IntoIterator<Item = &'a ValType>,
@@ -130,63 +200,30 @@ impl ValueStack {
val_types.into_iter().map(|val_type| self.pop_wasmvalue(*val_type))
}
- #[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: self.stack_32.pop_to_locals(pc.c32 as usize, lc.c32 as usize),
+ locals_64: self.stack_64.pop_to_locals(pc.c64 as usize, lc.c64 as usize),
+ locals_128: self.stack_128.pop_to_locals(pc.c128 as usize, lc.c128 as usize),
+ locals_ref: self.stack_ref.pop_to_locals(pc.cref as usize, lc.cref as usize),
}
}
pub(crate) fn truncate_keep(&mut self, to: StackLocation, keep: StackHeight) {
- #[inline(always)]
- fn truncate_keep<T>(data: &mut Vec<T>, n: u32, end_keep: u32) {
- let len = data.len() as u32;
- if len <= n {
- return; // No need to truncate if the current size is already less than or equal to total_to_keep
- }
- data.drain((n as usize)..(len - end_keep) as usize);
- }
-
- truncate_keep(&mut self.stack_32, to.s32, u32::from(keep.s32));
- truncate_keep(&mut self.stack_64, to.s64, u32::from(keep.s64));
- truncate_keep(&mut self.stack_128, to.s128, u32::from(keep.s128));
- truncate_keep(&mut self.stack_ref, to.sref, u32::from(keep.sref));
+ self.stack_32.truncate_keep(to.s32 as usize, usize::from(keep.s32));
+ self.stack_64.truncate_keep(to.s64 as usize, usize::from(keep.s64));
+ self.stack_128.truncate_keep(to.s128 as usize, usize::from(keep.s128));
+ self.stack_ref.truncate_keep(to.sref as usize, usize::from(keep.sref));
}
- pub(crate) fn push_dyn(&mut self, value: TinyWasmValue) {
+ pub(crate) fn push_dyn(&mut self, value: TinyWasmValue) -> Result<()> {
match value {
- TinyWasmValue::Value32(v) => self.stack_32.push(v),
- TinyWasmValue::Value64(v) => self.stack_64.push(v),
- TinyWasmValue::Value128(v) => self.stack_128.push(v),
- TinyWasmValue::ValueRef(v) => self.stack_ref.push(v),
+ TinyWasmValue::Value32(v) => self.stack_32.push(v)?,
+ TinyWasmValue::Value64(v) => self.stack_64.push(v)?,
+ TinyWasmValue::Value128(v) => self.stack_128.push(v)?,
+ TinyWasmValue::ValueRef(v) => self.stack_ref.push(v)?,
}
+ Ok(())
}
pub(crate) fn pop_wasmvalue(&mut self, val_type: ValType) -> WasmValue {
@@ -201,17 +238,18 @@ impl ValueStack {
}
}
- pub(crate) fn extend_from_wasmvalues(&mut self, values: &[WasmValue]) {
+ pub(crate) fn extend_from_wasmvalues(&mut self, values: &[WasmValue]) -> Result<()> {
for value in values {
match value {
- WasmValue::I32(v) => self.stack_32.push(*v as u32),
- WasmValue::I64(v) => self.stack_64.push(*v as u64),
- WasmValue::F32(v) => self.stack_32.push(v.to_bits()),
- WasmValue::F64(v) => self.stack_64.push(v.to_bits()),
- WasmValue::RefExtern(v) => self.stack_ref.push(v.addr()),
- WasmValue::RefFunc(v) => self.stack_ref.push(v.addr()),
- WasmValue::V128(v) => self.stack_128.push((*v).into()),
+ WasmValue::I32(v) => self.stack_32.push(*v as u32)?,
+ WasmValue::I64(v) => self.stack_64.push(*v as u64)?,
+ WasmValue::F32(v) => self.stack_32.push(v.to_bits())?,
+ WasmValue::F64(v) => self.stack_64.push(v.to_bits())?,
+ WasmValue::RefExtern(v) => self.stack_ref.push(v.addr())?,
+ WasmValue::RefFunc(v) => self.stack_ref.push(v.addr())?,
+ WasmValue::V128(v) => self.stack_128.push((*v).into())?,
}
}
+ Ok(())
}
}
diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs
index 456fb93..ac05bd4 100644
--- a/crates/tinywasm/src/interpreter/values.rs
+++ b/crates/tinywasm/src/interpreter/values.rs
@@ -1,4 +1,4 @@
-use crate::{Result, interpreter::value128::Value128};
+use crate::{interpreter::value128::Value128, Result};
use super::stack::{Locals, ValueStack};
use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValType, WasmValue};
@@ -100,14 +100,19 @@ impl TinyWasmValue {
/// Attaches a type to the value (panics if the size of the value is not the same as the type)
pub fn attach_type(&self, ty: ValType) -> WasmValue {
- match ty {
- ValType::I32 => WasmValue::I32(self.unwrap_32() as i32),
- ValType::I64 => WasmValue::I64(self.unwrap_64() as i64),
- ValType::F32 => WasmValue::F32(f32::from_bits(self.unwrap_32())),
- ValType::F64 => WasmValue::F64(f64::from_bits(self.unwrap_64())),
- ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.unwrap_ref())),
- ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.unwrap_ref())),
- ValType::V128 => WasmValue::V128(self.unwrap_128().into()),
+ match (self, ty) {
+ (Self::Value32(v), ValType::I32) => WasmValue::I32(*v as i32),
+ (Self::Value64(v), ValType::I64) => WasmValue::I64(*v as i64),
+ (Self::Value32(v), ValType::F32) => WasmValue::F32(f32::from_bits(*v)),
+ (Self::Value64(v), ValType::F64) => WasmValue::F64(f64::from_bits(*v)),
+ (Self::ValueRef(v), ValType::RefExtern) => WasmValue::RefExtern(ExternRef::new(*v)),
+ (Self::ValueRef(v), ValType::RefFunc) => WasmValue::RefFunc(FuncRef::new(*v)),
+ (Self::Value128(v), ValType::V128) => WasmValue::V128((*v).into()),
+
+ (_, ValType::I32 | ValType::F32) => panic!("Expected Value32"),
+ (_, ValType::I64 | ValType::F64) => panic!("Expected Value64"),
+ (_, ValType::RefExtern | ValType::RefFunc) => panic!("Expected ValueRef"),
+ (_, ValType::V128) => panic!("Expected Value128"),
}
}
}
@@ -144,7 +149,7 @@ mod sealed {
}
pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> {
- fn stack_push(stack: &mut ValueStack, value: Self);
+ fn stack_push(stack: &mut ValueStack, value: Self) -> Result<()>;
fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()>
where
Self: Sized;
@@ -177,63 +182,42 @@ macro_rules! impl_internalvalue {
}
impl InternalValue for $outer {
- #[inline(always)]
- fn stack_push(stack: &mut ValueStack, value: Self) {
- stack.$stack.push($to_internal(value));
+ fn stack_push(stack: &mut ValueStack, value: Self) -> Result<()> {
+ stack.$stack.push($to_internal(value))
}
- #[inline(always)]
fn stack_pop(stack: &mut ValueStack) -> Self {
- match stack.$stack.pop() {
- Some(v) => $to_outer(v),
- None => unreachable!("ValueStack underflow, this is a bug"),
- }
+ $to_outer(stack.$stack.pop())
}
- #[inline(always)]
fn stack_peek(stack: &ValueStack) -> Self {
- match stack.$stack.last() {
- Some(v) => $to_outer(*v),
- None => unreachable!("ValueStack underflow, this is a bug"),
- }
+ $to_outer(*stack.$stack.last())
}
- #[inline(always)]
fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()> {
let v2 = stack.$stack.pop();
let v1 = stack.$stack.last_mut();
- let (Some(v1), Some(v2)) = (v1, v2) else {
- unreachable!("ValueStack underflow, this is a bug");
- };
*v1 = $to_internal(func($to_outer(*v1), $to_outer(v2))?);
- return Ok(())
+ Ok(())
}
- #[inline(always)]
fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()> {
let v3 = stack.$stack.pop();
let v2 = stack.$stack.pop();
let v1 = stack.$stack.last_mut();
- let (Some(v1), Some(v2), Some(v3)) = (v1, v2, v3) else {
- unreachable!("ValueStack underflow, this is a bug");
- };
*v1 = $to_internal(func($to_outer(*v1), $to_outer(v2), $to_outer(v3))?);
- return Ok(())
+ Ok(())
}
- #[inline(always)]
fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()> {
- let Some(v) = stack.$stack.last_mut() else {
- unreachable!("ValueStack underflow, this is a bug");
- };
+ let v = stack.$stack.last_mut();
*v = $to_internal(func($to_outer(*v))?);
Ok(())
}
- #[inline(always)]
fn local_get(locals: &Locals, index: LocalAddr) -> Self {
match locals.$locals.get(index as usize) {
Some(v) => $to_outer(*v),
@@ -241,7 +225,6 @@ macro_rules! impl_internalvalue {
}
}
- #[inline(always)]
fn local_set(locals: &mut Locals, index: LocalAddr, value: Self) {
match locals.$locals.get_mut(index as usize) {
Some(v) => *v = $to_internal(value),
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index 8898212..022db0d 100644
--- a/crates/tinywasm/src/store/memory.rs
+++ b/crates/tinywasm/src/store/memory.rs
@@ -33,7 +33,7 @@ impl MemoryInstance {
matches!(self.kind.arch(), MemoryArch::I64)
}
- #[inline(always)]
+ #[inline]
pub(crate) fn len(&self) -> usize {
self.data.len()
}
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 757cbb2..a0a025c 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -5,7 +5,7 @@ use tinywasm_types::*;
use crate::interpreter::TinyWasmValue;
use crate::interpreter::stack::Stack;
-use crate::{Engine, Error, Function, ModuleInstance, Result, Trap, cold};
+use crate::{Engine, Error, Function, ModuleInstance, Result, Trap};
mod data;
mod element;
@@ -94,25 +94,31 @@ pub(crate) struct State {
impl State {
/// Get the function at the actual index in the store
- #[inline]
pub(crate) fn get_func(&self, addr: FuncAddr) -> &FunctionInstance {
- &self.funcs[addr as usize]
+ match self.funcs.get(addr as usize) {
+ Some(func) => func,
+ None => unreachable!("function {addr} not found. This should be unreachable"),
+ }
}
/// Get the memory at the actual index in the store
- #[inline]
pub(crate) fn get_mem(&self, addr: MemAddr) -> &MemoryInstance {
- &self.memories[addr as usize]
+ match self.memories.get(addr as usize) {
+ Some(mem) => mem,
+ None => unreachable!("memory {addr} not found. This should be unreachable"),
+ }
}
/// Get the memory at the actual index in the store
#[inline(always)]
pub(crate) fn get_mem_mut(&mut self, addr: MemAddr) -> &mut MemoryInstance {
- &mut self.memories[addr as usize]
+ match self.memories.get_mut(addr as usize) {
+ Some(mem) => mem,
+ None => unreachable!("memory {addr} not found. This should be unreachable"),
+ }
}
/// Get the memory at the actual index in the store
- #[inline(always)]
pub(crate) fn get_mems_mut(
&mut self,
addr: MemAddr,
@@ -120,27 +126,27 @@ impl State {
) -> Result<(&mut MemoryInstance, &mut MemoryInstance)> {
match get_pair_mut(&mut self.memories, addr as usize, addr2 as usize) {
Some(mems) => Ok(mems),
- None => {
- cold();
- Err(Self::not_found_error("memory"))
- }
+ None => unreachable!("memory {addr} or {addr2} not found. This should be unreachable"),
}
}
/// Get the table at the actual index in the store
- #[inline]
pub(crate) fn get_table(&self, addr: TableAddr) -> &TableInstance {
- &self.tables[addr as usize]
+ match self.tables.get(addr as usize) {
+ Some(table) => table,
+ None => unreachable!("table {addr} not found. This should be unreachable"),
+ }
}
/// Get the table at the actual index in the store
- #[inline]
pub(crate) fn get_table_mut(&mut self, addr: TableAddr) -> &mut TableInstance {
- &mut self.tables[addr as usize]
+ match self.tables.get_mut(addr as usize) {
+ Some(table) => table,
+ None => unreachable!("table {addr} not found. This should be unreachable"),
+ }
}
/// Get two mutable tables at the actual index in the store
- #[inline]
pub(crate) fn get_tables_mut(
&mut self,
addr: TableAddr,
@@ -148,44 +154,48 @@ impl State {
) -> Result<(&mut TableInstance, &mut TableInstance)> {
match get_pair_mut(&mut self.tables, addr as usize, addr2 as usize) {
Some(tables) => Ok(tables),
- None => {
- cold();
- Err(Self::not_found_error("table"))
- }
+ None => unreachable!("table {addr} or {addr2} not found. This should be unreachable"),
}
}
/// Get the data at the actual index in the store
- #[inline]
pub(crate) fn get_data_mut(&mut self, addr: DataAddr) -> &mut DataInstance {
- &mut self.data[addr as usize]
+ match self.data.get_mut(addr as usize) {
+ Some(data) => data,
+ None => unreachable!("data {addr} not found. This should be unreachable"),
+ }
}
/// Get the element at the actual index in the store
- #[inline]
pub(crate) fn get_elem_mut(&mut self, addr: ElemAddr) -> &mut ElementInstance {
- &mut self.elements[addr as usize]
+ match self.elements.get_mut(addr as usize) {
+ Some(elem) => elem,
+ None => unreachable!("element {addr} not found. This should be unreachable"),
+ }
}
/// Get the global at the actual index in the store
- #[inline]
pub(crate) fn get_global(&self, addr: GlobalAddr) -> &GlobalInstance {
- &self.globals[addr as usize]
+ match self.globals.get(addr as usize) {
+ Some(global) => global,
+ None => unreachable!("global {addr} not found. This should be unreachable"),
+ }
}
/// Get the global at the actual index in the store
pub(crate) fn get_global_val(&self, addr: MemAddr) -> TinyWasmValue {
- self.globals[addr as usize].value.get()
+ match self.globals.get(addr as usize) {
+ Some(global) => global.value.get(),
+ None => unreachable!("global {addr} not found. This should be unreachable"),
+ }
}
/// Set the global at the actual index in the store
pub(crate) fn set_global_val(&mut self, addr: MemAddr, value: TinyWasmValue) {
- self.globals[addr as usize].value.set(value);
- }
-
- #[cold]
- fn not_found_error(name: &str) -> Error {
- Error::Other(format!("{name} not found"))
+ match self.globals.get_mut(addr as usize) {
+ Some(global) => global.value.set(value),
+ None => unreachable!("global {addr} not found. This should be unreachable"),
+ }
}
}
@@ -421,7 +431,7 @@ impl Store {
}
/// Evaluate a constant expression that's either a i32 or a i64 as a global or a const instruction
- pub(crate) fn eval_size_const(&self, const_instr: tinywasm_types::ConstInstruction) -> Result<i64> {
+ fn eval_size_const(&self, const_instr: tinywasm_types::ConstInstruction) -> Result<i64> {
Ok(match const_instr {
ConstInstruction::I32Const(i) => i64::from(i),
ConstInstruction::I64Const(i) => i,
@@ -435,7 +445,7 @@ impl Store {
}
/// Evaluate a constant expression
- pub(crate) fn eval_const(
+ fn eval_const(
&self,
const_instr: &tinywasm_types::ConstInstruction,
module_global_addrs: &[Addr],