Skip to content
This repository was archived by the owner on Oct 3, 2025. It is now read-only.

Commit e2ae76c

Browse files
chore: simplify interpreter::exec
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent c414c17 commit e2ae76c

File tree

5 files changed

+62
-79
lines changed

5 files changed

+62
-79
lines changed

crates/tinywasm/src/instance.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ impl ModuleInstance {
4343

4444
#[inline]
4545
pub(crate) fn swap_with(&mut self, other_addr: ModuleInstanceAddr, store: &mut Store) {
46-
self.swap(store.get_module_instance_raw(other_addr))
46+
if other_addr != self.id() {
47+
self.swap(store.get_module_instance_raw(other_addr))
48+
}
4749
}
4850

4951
/// Get the module instance's address

crates/tinywasm/src/runtime/interpreter/macros.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,12 @@ macro_rules! mem_load {
3333
offset: u64,
3434
) -> Result<()> {
3535
let mem = store.get_mem(module.resolve_mem_addr(mem_addr))?;
36-
let addr: usize = match offset.checked_add(stack.values.pop()?.into()).map(|a| a.try_into()) {
37-
Some(Ok(a)) => a,
38-
_ => {
39-
cold();
40-
return Err(Error::Trap(crate::Trap::MemoryOutOfBounds {
41-
offset: offset as usize,
42-
len: core::mem::size_of::<$load_type>(),
43-
max: mem.borrow().max_pages(),
44-
}));
45-
}
36+
let Some(Ok(addr)) = offset.checked_add(stack.values.pop()?.into()).map(|a| a.try_into()) else {
37+
return Err(Error::Trap(crate::Trap::MemoryOutOfBounds {
38+
offset: offset as usize,
39+
len: core::mem::size_of::<$load_type>(),
40+
max: mem.borrow().max_pages(),
41+
}));
4642
};
4743

4844
const LEN: usize = core::mem::size_of::<$load_type>();

crates/tinywasm/src/runtime/interpreter/mod.rs

Lines changed: 46 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use alloc::format;
2+
use alloc::rc::Rc;
23
use alloc::string::ToString;
3-
use core::ops::{BitAnd, BitOr, BitXor, Neg};
4-
use tinywasm_types::{BlockArgs, ElementKind, Instruction, ValType};
4+
use core::ops::{BitAnd, BitOr, BitXor, ControlFlow, Neg};
5+
use tinywasm_types::{BlockArgs, ElementKind, Instruction, ModuleInstanceAddr, ValType, WasmFunction};
56

67
use super::stack::{BlockFrame, BlockType};
78
use super::{InterpreterRuntime, RawWasmValue, Stack};
@@ -35,11 +36,6 @@ struct Executor<'store, 'stack> {
3536
module: ModuleInstance,
3637
}
3738

38-
enum ExecResult {
39-
Continue,
40-
Return,
41-
}
42-
4339
impl<'store, 'stack> Executor<'store, 'stack> {
4440
pub(crate) fn new(store: &'store mut Store, stack: &'stack mut Stack) -> Result<Self> {
4541
let current_frame = stack.call_stack.pop()?;
@@ -49,19 +45,15 @@ impl<'store, 'stack> Executor<'store, 'stack> {
4945

5046
pub(crate) fn run_to_completion(&mut self) -> Result<()> {
5147
loop {
52-
match self.next() {
53-
Ok(ExecResult::Return) => return Ok(()),
54-
Ok(ExecResult::Continue) => continue,
55-
Err(e) => {
56-
cold();
57-
return Err(e);
58-
}
48+
match self.next()? {
49+
ControlFlow::Break(..) => return Ok(()),
50+
ControlFlow::Continue(..) => continue,
5951
};
6052
}
6153
}
6254

6355
#[inline(always)]
64-
pub(crate) fn next(&mut self) -> Result<ExecResult> {
56+
pub(crate) fn next(&mut self) -> Result<ControlFlow<()>> {
6557
use tinywasm_types::Instruction::*;
6658
match self.cf.fetch_instr() {
6759
Nop => cold(),
@@ -70,7 +62,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
7062
Drop => self.stack.values.pop().map(|_| ())?,
7163
Select(_valtype) => self.exec_select()?,
7264

73-
Call(v) => return self.exec_call(*v),
65+
Call(v) => return self.exec_call_direct(*v),
7466
CallIndirect(ty, table) => return self.exec_call_indirect(*ty, *table),
7567

7668
If(args, el, end) => return self.exec_if((*args).into(), *el, *end),
@@ -310,7 +302,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
310302
};
311303

312304
self.cf.instr_ptr += 1;
313-
Ok(ExecResult::Continue)
305+
Ok(ControlFlow::Continue(()))
314306
}
315307

316308
#[inline(always)]
@@ -337,18 +329,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
337329
}
338330

339331
#[inline(always)]
340-
fn exec_br_if(&mut self, to: u32) -> Result<ExecResult> {
332+
fn exec_br_if(&mut self, to: u32) -> Result<ControlFlow<()>> {
341333
let val: i32 = self.stack.values.pop()?.into();
342334
if val != 0 {
343335
break_to!(to, self);
344336
}
345-
346337
self.cf.instr_ptr += 1;
347-
Ok(ExecResult::Continue)
338+
Ok(ControlFlow::Continue(()))
348339
}
349340

350341
#[inline(always)]
351-
fn exec_brtable(&mut self, default: u32, len: u32) -> Result<ExecResult> {
342+
fn exec_brtable(&mut self, default: u32, len: u32) -> Result<ControlFlow<()>> {
352343
let start = self.cf.instr_ptr + 1;
353344
let end = start + len as usize;
354345
if end > self.cf.instructions().len() {
@@ -364,13 +355,14 @@ impl<'store, 'stack> Executor<'store, 'stack> {
364355
}
365356

366357
self.cf.instr_ptr += 1;
367-
Ok(ExecResult::Continue)
358+
Ok(ControlFlow::Continue(()))
368359
}
369360

370361
#[inline(always)]
371-
fn exec_return(&mut self) -> Result<ExecResult> {
362+
fn exec_return(&mut self) -> Result<ControlFlow<()>> {
363+
// returning from the main function is a break
372364
if self.stack.call_stack.is_empty() {
373-
return Ok(ExecResult::Return);
365+
return Ok(ControlFlow::Break(()));
374366
}
375367

376368
let old = self.cf.block_ptr;
@@ -384,7 +376,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
384376
self.module.swap_with(self.cf.module_addr, self.store);
385377
}
386378

387-
Ok(ExecResult::Continue)
379+
Ok(ControlFlow::Continue(()))
388380
}
389381

390382
#[inline(always)]
@@ -645,7 +637,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
645637
}
646638

647639
#[inline(always)]
648-
fn exec_call(&mut self, v: u32) -> Result<ExecResult> {
640+
fn exec_call(&mut self, wasm_func: Rc<WasmFunction>, owner: ModuleInstanceAddr) -> Result<ControlFlow<()>> {
641+
let params = self.stack.values.pop_n_rev(wasm_func.ty.params.len())?;
642+
let new_call_frame = CallFrame::new(wasm_func, owner, params, self.stack.blocks.len() as u32);
643+
self.cf.instr_ptr += 1; // skip the call instruction
644+
self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
645+
self.module.swap_with(self.cf.module_addr, self.store);
646+
Ok(ControlFlow::Continue(()))
647+
}
648+
649+
#[inline(always)]
650+
fn exec_call_direct(&mut self, v: u32) -> Result<ControlFlow<()>> {
649651
let func_inst = self.store.get_func(self.module.resolve_func_addr(v))?;
650652
let wasm_func = match &func_inst.func {
651653
crate::Function::Wasm(wasm_func) => wasm_func,
@@ -655,38 +657,27 @@ impl<'store, 'stack> Executor<'store, 'stack> {
655657
let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params)?;
656658
self.stack.values.extend_from_typed(&res);
657659
self.cf.instr_ptr += 1;
658-
return Ok(ExecResult::Continue);
660+
return Ok(ControlFlow::Continue(()));
659661
}
660662
};
661-
662-
let params = self.stack.values.pop_n_rev(wasm_func.ty.params.len())?;
663-
let new_call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, self.stack.blocks.len() as u32);
664-
665-
self.cf.instr_ptr += 1; // skip the call instruction
666-
self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
667-
if self.cf.module_addr != self.module.id() {
668-
self.module.swap_with(self.cf.module_addr, self.store);
669-
}
670-
Ok(ExecResult::Continue)
663+
return self.exec_call(wasm_func.clone(), func_inst.owner);
671664
}
672665

673666
#[inline(always)]
674-
fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<ExecResult> {
675-
let table = self.store.get_table(self.module.resolve_table_addr(table_addr))?;
676-
let table_idx: u32 = self.stack.values.pop()?.into();
677-
667+
fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<ControlFlow<()>> {
678668
// verify that the table is of the right type, this should be validated by the parser already
679669
let func_ref = {
670+
let table = self.store.get_table(self.module.resolve_table_addr(table_addr))?;
671+
let table_idx: u32 = self.stack.values.pop()?.into();
680672
let table = table.borrow();
681673
assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref");
682674
table.get(table_idx)?.addr().ok_or(Trap::UninitializedElement { index: table_idx as usize })?
683675
};
684676

685-
let func_inst = self.store.get_func(func_ref)?.clone();
677+
let func_inst = self.store.get_func(func_ref)?;
686678
let call_ty = self.module.func_ty(type_addr);
687-
688-
let wasm_func = match func_inst.func {
689-
crate::Function::Wasm(ref f) => f,
679+
let wasm_func = match &func_inst.func {
680+
crate::Function::Wasm(f) => f,
690681
crate::Function::Host(host_func) => {
691682
if unlikely(host_func.ty != *call_ty) {
692683
return Err(Trap::IndirectCallTypeMismatch {
@@ -701,48 +692,38 @@ impl<'store, 'stack> Executor<'store, 'stack> {
701692
let res = (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params)?;
702693
self.stack.values.extend_from_typed(&res);
703694
self.cf.instr_ptr += 1;
704-
return Ok(ExecResult::Continue);
695+
return Ok(ControlFlow::Continue(()));
705696
}
706697
};
707698

708-
if unlikely(wasm_func.ty != *call_ty) {
709-
return Err(
710-
Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into()
711-
);
712-
}
713-
714-
let params = self.stack.values.pop_n_rev(wasm_func.ty.params.len())?;
715-
let new_call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, self.stack.blocks.len() as u32);
716-
717-
self.cf.instr_ptr += 1; // skip the call instruction
718-
self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
719-
if self.cf.module_addr != self.module.id() {
720-
self.module.swap_with(self.cf.module_addr, self.store);
699+
if wasm_func.ty == *call_ty {
700+
return self.exec_call(wasm_func.clone(), func_inst.owner);
721701
}
722702

723-
Ok(ExecResult::Continue)
703+
cold();
704+
return Err(Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into());
724705
}
725706

726707
#[inline(always)]
727-
fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<ExecResult> {
708+
fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<ControlFlow<()>> {
728709
// truthy value is on the top of the stack, so enter the then block
729710
if i32::from(self.stack.values.pop()?) != 0 {
730711
self.enter_block(self.cf.instr_ptr, end_offset, BlockType::If, args);
731712
self.cf.instr_ptr += 1;
732-
return Ok(ExecResult::Continue);
713+
return Ok(ControlFlow::Continue(()));
733714
}
734715

735716
// falsy value is on the top of the stack
736717
if else_offset == 0 {
737718
self.cf.instr_ptr += end_offset as usize + 1;
738-
return Ok(ExecResult::Continue);
719+
return Ok(ControlFlow::Continue(()));
739720
}
740721

741722
let old = self.cf.instr_ptr;
742723
self.cf.instr_ptr += else_offset as usize;
743724
self.enter_block(old + else_offset as usize, end_offset - else_offset, BlockType::Else, args);
744725
self.cf.instr_ptr += 1;
745-
Ok(ExecResult::Continue)
726+
Ok(ControlFlow::Continue(()))
746727
}
747728

748729
#[inline(always)]
@@ -790,7 +771,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
790771
instr_ptr,
791772
end_instr_offset,
792773
stack_ptr: self.stack.values.len() as u32 - params as u32,
793-
simd_stack_ptr: self.stack.values.simd_len() as u32 - simd_params as u32,
774+
simd_stack_ptr: self.stack.values.simd_len() as u16 - simd_params as u16,
794775
results,
795776
simd_params,
796777
simd_results,

crates/tinywasm/src/runtime/stack/block_stack.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub(crate) struct BlockFrame {
6060
pub(crate) params: u8,
6161

6262
#[cfg(feature = "simd")]
63-
pub(crate) simd_stack_ptr: u32, // position of the large stack pointer when the block was entered
63+
pub(crate) simd_stack_ptr: u16, // position of the large stack pointer when the block was entered
6464
#[cfg(feature = "simd")]
6565
pub(crate) simd_results: u8,
6666
#[cfg(feature = "simd")]

crates/tinywasm/src/runtime/stack/value_stack.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ use tinywasm_types::{ValType, WasmValue};
55
use super::BlockFrame;
66

77
pub(crate) const MIN_VALUE_STACK_SIZE: usize = 1024 * 128;
8+
// pub(crate) const MAX_VALUE_STACK_SIZE: usize = u32::MAX / 32 as usize;
89

910
#[cfg(feature = "simd")]
1011
pub(crate) const MIN_SIMD_VALUE_STACK_SIZE: usize = 1024 * 32;
1112

13+
// #[cfg(feature = "simd")]
14+
// pub(crate) const MAX_SIMD_VALUE_STACK_SIZE: usize = u16::MAX as usize;
15+
1216
#[cfg(feature = "simd")]
1317
use crate::runtime::raw_simd::RawSimdWasmValue;
1418

@@ -90,8 +94,8 @@ impl ValueStack {
9094

9195
#[cfg(feature = "simd")]
9296
#[inline]
93-
pub(crate) fn truncate_keep_simd(&mut self, n: u32, end_keep: u32) {
94-
truncate_keep(&mut self.simd_stack, n, end_keep);
97+
pub(crate) fn truncate_keep_simd(&mut self, n: u16, end_keep: u32) {
98+
truncate_keep(&mut self.simd_stack, n as u32, end_keep);
9599
}
96100

97101
#[inline(always)]

0 commit comments

Comments
 (0)