Skip to content

Commit bfeefda

Browse files
chore: clean up interpreter
Signed-off-by: Henry <mail@henrygressmann.de>
1 parent c3b1f58 commit bfeefda

File tree

10 files changed

+859
-2564
lines changed

10 files changed

+859
-2564
lines changed

crates/tinywasm/src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ pub(crate) trait Controlify<T> {
268268
}
269269

270270
impl<T> Controlify<T> for Result<T, Error> {
271+
#[inline(always)]
271272
fn to_cf(self) -> ControlFlow<Option<Error>, T> {
272273
match self {
273274
Ok(value) => ControlFlow::Continue(value),

crates/tinywasm/src/interpreter/executor.rs

Lines changed: 83 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use super::values::*;
1414
use crate::instance::ModuleInstanceInner;
1515
use crate::interpreter::Value128;
1616
use crate::*;
17-
1817
pub(crate) struct Executor<'store> {
1918
cf: CallFrame,
2019
func: Rc<WasmFunction>,
@@ -45,37 +44,24 @@ impl<'store> Executor<'store> {
4544
use tinywasm_types::Instruction::*;
4645

4746
macro_rules! stack_op {
48-
(simd_unary $method:ident) => {
49-
self.store.stack.values.unary_same::<Value128>(|v| Ok(v.$method())).to_cf()?
50-
};
51-
(simd_binary $method:ident) => {
52-
self.store.stack.values.binary_same::<Value128>(|a, b| Ok(a.$method(b))).to_cf()?
53-
};
54-
(unary $ty:ty, |$v:ident| $expr:expr) => {
55-
self.store.stack.values.unary_same::<$ty>(|$v| Ok($expr)).to_cf()?
56-
};
57-
(binary $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
58-
self.store.stack.values.binary_same::<$ty>(|$a, $b| Ok($expr)).to_cf()?
59-
};
60-
(binary_try $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
61-
self.store.stack.values.binary_same::<$ty>(|$a, $b| $expr).to_cf()?
62-
};
63-
(unary $from:ty => $to:ty, |$v:ident| $expr:expr) => {
64-
self.store.stack.values.unary::<$from, $to>(|$v| Ok($expr)).to_cf()?
65-
};
66-
(binary $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => {
67-
self.store.stack.values.binary::<$from, $to>(|$a, $b| Ok($expr)).to_cf()?
68-
};
69-
(binary $a:ty, $b:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
70-
self.store.stack.values.binary_diff::<$a, $b, $b>(|$lhs, $rhs| Ok($expr)).to_cf()?
71-
};
72-
(binary $a:ty, $b:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
73-
self.store.stack.values.binary_diff::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()?
74-
};
47+
(simd_unary $method:ident) => { stack_op!(unary Value128, |v| v.$method()) };
48+
(simd_binary $method:ident) => { stack_op!(binary Value128, |a, b| a.$method(b)) };
49+
(unary $ty:ty, |$v:ident| $expr:expr) => { self.store.stack.values.unary::<$ty>(|$v| Ok($expr)).to_cf()? };
50+
(binary $ty:ty, |$a:ident, $b:ident| $expr:expr) => { self.store.stack.values.binary::<$ty>(|$a, $b| Ok($expr)).to_cf()? };
51+
(binary try $ty:ty, |$a:ident, $b:ident| $expr:expr) => { self.store.stack.values.binary::<$ty>(|$a, $b| $expr).to_cf()? };
52+
(unary $from:ty => $to:ty, |$v:ident| $expr:expr) => { self.store.stack.values.unary_into::<$from, $to>(|$v| Ok($expr)).to_cf()? };
53+
(binary $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => { self.store.stack.values.binary_into::<$from, $to>(|$a, $b| Ok($expr)).to_cf()? };
54+
(binary $a:ty, $b:ty, |$lhs:ident, $rhs:ident| $expr:expr) => { stack_op!(binary $a, $b => $b, |$lhs, $rhs| $expr) };
55+
(binary $a:ty, $b:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => { self.store.stack.values.binary_mixed::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()? };
56+
(ternary $ty:ty, |$a:ident, $b:ident, $c:ident| $expr:expr) => { self.store.stack.values.ternary::<$ty>(|$a, $b, $c| Ok($expr)).to_cf()? };
7557
(local_set_pop $ty:ty, $local_index:expr) => {{
7658
let val = self.store.stack.values.pop::<$ty>();
7759
self.store.stack.values.local_set(&self.cf, *$local_index, val);
7860
}};
61+
(local_tee $ty:ty, $local_index:expr) => {{
62+
let val = self.store.stack.values.peek::<$ty>();
63+
self.store.stack.values.local_set(&self.cf, *$local_index, val);
64+
}};
7965
}
8066

8167
let next = match self.func.instructions.0.get(self.cf.instr_ptr as usize) {
@@ -89,7 +75,7 @@ impl<'store> Executor<'store> {
8975

9076
#[rustfmt::skip]
9177
match next {
92-
Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 | BranchTableTarget {..} => {}
78+
Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
9379
Unreachable => return ControlFlow::Break(Some(Trap::Unreachable.into())),
9480
Drop32 => self.store.stack.values.drop::<Value32>(),
9581
Drop64 => self.store.stack.values.drop::<Value64>(),
@@ -106,20 +92,8 @@ impl<'store> Executor<'store> {
10692
ReturnCall(v) => return self.exec_call_direct::<true>(*v),
10793
ReturnCallSelf => return self.exec_call_self::<true>(),
10894
ReturnCallIndirect(ty, table) => return self.exec_call_indirect::<true>(*ty, *table),
109-
Jump(ip) => {
110-
self.cf.instr_ptr = *ip;
111-
return ControlFlow::Continue(());
112-
}
113-
JumpIfZero(ip) => {
114-
let cond = self.store.stack.values.pop::<i32>();
115-
116-
if cond == 0 {
117-
self.cf.instr_ptr = *ip;
118-
} else {
119-
self.cf.incr_instr_ptr();
120-
}
121-
return ControlFlow::Continue(());
122-
}
95+
Jump(ip) => return self.exec_jump(*ip),
96+
JumpIfZero(ip) => if self.exec_jump_if_zero(*ip) { return ControlFlow::Continue(()); },
12397
DropKeepSmall { base32, keep32, base64, keep64, base128, keep128, base_ref, keep_ref } => {
12498
let b32 = self.cf.stack_base().s32 + *base32 as u32;
12599
let k32 = *keep32 as usize;
@@ -154,21 +128,8 @@ impl<'store> Executor<'store> {
154128
let k = *keep as usize;
155129
self.store.stack.values.stack_ref.truncate_keep(b as usize, k);
156130
}
157-
BranchTable(default_ip, len) => {
158-
let idx = self.store.stack.values.pop::<i32>();
159-
let start = self.cf.instr_ptr + 1;
160-
161-
let target_ip = if idx >= 0 && (idx as u32) < *len {
162-
match self.func.instructions.0.get((start + idx as u32) as usize) {
163-
Some(Instruction::BranchTableTarget(ip)) => *ip,
164-
_ => *default_ip,
165-
}
166-
} else {
167-
*default_ip
168-
};
169-
self.cf.instr_ptr = target_ip;
170-
return ControlFlow::Continue(());
171-
}
131+
BranchTable(default_ip, len) => return self.exec_branch_table(*default_ip, *len),
132+
BranchTableTarget {..} => {},
172133
Return => return self.exec_return(),
173134
LocalGet32(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value32>(&self.cf, *local_index)).to_cf()?,
174135
LocalGet64(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value64>(&self.cf, *local_index)).to_cf()?,
@@ -214,14 +175,13 @@ impl<'store> Executor<'store> {
214175
}
215176
I64XorRotlConst(c) => stack_op!(binary i64, |lhs, rhs| (lhs ^ rhs).rotate_left(*c as u32)),
216177
I64XorRotlConstTee(c, local_index) => {
217-
self.store.stack.values.binary_same::<i64>(|lhs, rhs| Ok((lhs ^ rhs).rotate_left(*c as u32))).to_cf()?;
218-
let val = self.store.stack.values.peek::<i64>();
219-
self.store.stack.values.local_set(&self.cf, *local_index, val);
178+
stack_op!(binary i64, |lhs, rhs| (lhs ^ rhs).rotate_left(*c as u32));
179+
stack_op!(local_tee i64, local_index);
220180
}
221-
LocalTee32(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value32>()),
222-
LocalTee64(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value64>()),
223-
LocalTee128(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value128>()),
224-
LocalTeeRef(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<ValueRef>()),
181+
LocalTee32(local_index) => stack_op!(local_tee Value32, local_index),
182+
LocalTee64(local_index) => stack_op!(local_tee Value64, local_index),
183+
LocalTee128(local_index) => stack_op!(local_tee Value128, local_index),
184+
LocalTeeRef(local_index) => stack_op!(local_tee ValueRef, local_index),
225185
GlobalGet(global_index) => self.exec_global_get(*global_index).to_cf()?,
226186
GlobalSet32(global_index) => self.exec_global_set::<Value32>(*global_index),
227187
GlobalSet64(global_index) => self.exec_global_set::<Value64>(*global_index),
@@ -279,14 +239,14 @@ impl<'store> Executor<'store> {
279239
I64Mul => stack_op!(binary i64, |a, b| a.wrapping_mul(b)),
280240
F32Mul => stack_op!(binary f32, |a, b| a * b),
281241
F64Mul => stack_op!(binary f64, |a, b| a * b),
282-
I32DivS => stack_op!(binary_try i32, |a, b| a.wasm_checked_div(b)),
283-
I64DivS => stack_op!(binary_try i64, |a, b| a.wasm_checked_div(b)),
284-
I32DivU => stack_op!(binary_try u32, |a, b| a.checked_div(b).ok_or_else(trap_0)),
285-
I64DivU => stack_op!(binary_try u64, |a, b| a.checked_div(b).ok_or_else(trap_0)),
286-
I32RemS => stack_op!(binary_try i32, |a, b| a.checked_wrapping_rem(b)),
287-
I64RemS => stack_op!(binary_try i64, |a, b| a.checked_wrapping_rem(b)),
288-
I32RemU => stack_op!(binary_try u32, |a, b| a.checked_wrapping_rem(b)),
289-
I64RemU => stack_op!(binary_try u64, |a, b| a.checked_wrapping_rem(b)),
242+
I32DivS => stack_op!(binary try i32, |a, b| a.wasm_checked_div(b)),
243+
I64DivS => stack_op!(binary try i64, |a, b| a.wasm_checked_div(b)),
244+
I32DivU => stack_op!(binary try u32, |a, b| a.checked_div(b).ok_or_else(trap_0)),
245+
I64DivU => stack_op!(binary try u64, |a, b| a.checked_div(b).ok_or_else(trap_0)),
246+
I32RemS => stack_op!(binary try i32, |a, b| a.checked_wrapping_rem(b)),
247+
I64RemS => stack_op!(binary try i64, |a, b| a.checked_wrapping_rem(b)),
248+
I32RemU => stack_op!(binary try u32, |a, b| a.checked_wrapping_rem(b)),
249+
I64RemU => stack_op!(binary try u64, |a, b| a.checked_wrapping_rem(b)),
290250
I32And => stack_op!(binary i32, |a, b| a & b),
291251
I64And => stack_op!(binary i64, |a, b| a & b),
292252
I32Or => stack_op!(binary i32, |a, b| a | b),
@@ -424,7 +384,7 @@ impl<'store> Executor<'store> {
424384
V128AndNot => stack_op!(binary Value128, |a, b| a.v128_andnot(b)),
425385
V128Or => stack_op!(binary Value128, |a, b| a.v128_or(b)),
426386
V128Xor => stack_op!(binary Value128, |a, b| a.v128_xor(b)),
427-
V128Bitselect => self.store.stack.values.ternary_same::<Value128>(|v1, v2, c| Ok(Value128::v128_bitselect(v1, v2, c))).to_cf()?,
387+
V128Bitselect => stack_op!(ternary Value128, |v1, v2, c| Value128::v128_bitselect(v1, v2, c)),
428388
V128AnyTrue => stack_op!(unary Value128 => i32, |v| v.v128_any_true() as i32),
429389
I8x16Swizzle => stack_op!(binary Value128, |a, s| a.i8x16_swizzle(s)),
430390
V128Load(arg) => self.exec_mem_load::<Value128, 16, _>(arg.mem_addr(), arg.offset(), |v| v)?,
@@ -661,6 +621,39 @@ impl<'store> Executor<'store> {
661621
ControlFlow::Continue(())
662622
}
663623

624+
#[inline(always)]
625+
fn exec_jump(&mut self, ip: u32) -> ControlFlow<Option<Error>> {
626+
self.cf.instr_ptr = ip;
627+
ControlFlow::Continue(())
628+
}
629+
630+
#[inline(always)]
631+
fn exec_jump_if_zero(&mut self, ip: u32) -> bool {
632+
if self.store.stack.values.pop::<i32>() == 0 {
633+
self.cf.instr_ptr = ip;
634+
return true;
635+
}
636+
false
637+
}
638+
639+
#[inline(always)]
640+
fn exec_branch_table(&mut self, default_ip: u32, len: u32) -> ControlFlow<Option<Error>> {
641+
let idx = self.store.stack.values.pop::<i32>();
642+
let start = self.cf.instr_ptr + 1;
643+
644+
let target_ip = if idx >= 0 && (idx as u32) < len {
645+
match self.func.instructions.0.get((start + idx as u32) as usize) {
646+
Some(Instruction::BranchTableTarget(ip)) => *ip,
647+
_ => default_ip,
648+
}
649+
} else {
650+
default_ip
651+
};
652+
653+
self.cf.instr_ptr = target_ip;
654+
ControlFlow::Continue(())
655+
}
656+
664657
fn exec_call<const IS_RETURN_CALL: bool>(
665658
&mut self,
666659
wasm_func: Rc<WasmFunction>,
@@ -943,6 +936,7 @@ impl<'store> Executor<'store> {
943936
ControlFlow::Continue(())
944937
}
945938

939+
#[inline(always)]
946940
fn exec_mem_load<LOAD: MemValue<LOAD_SIZE>, const LOAD_SIZE: usize, TARGET: InternalValue>(
947941
&mut self,
948942
mem_addr: tinywasm_types::MemAddr,
@@ -951,18 +945,28 @@ impl<'store> Executor<'store> {
951945
) -> ControlFlow<Option<Error>> {
952946
let mem = self.store.state.get_mem(self.module.resolve_mem_addr(mem_addr));
953947

954-
let addr = match mem.is_64bit() {
955-
true => self.store.stack.values.pop::<i64>() as u64,
956-
false => u64::from(self.store.stack.values.pop::<i32>() as u32),
948+
let base: u64 = if mem.is_64bit() {
949+
self.store.stack.values.pop::<i64>() as u64
950+
} else {
951+
self.store.stack.values.pop::<i32>() as u32 as u64
957952
};
958953

959-
let Some(Ok(addr)) = offset.checked_add(addr).map(|a| a.try_into()) else {
954+
let Some(addr) = base.checked_add(offset) else {
960955
return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
961-
offset: addr as usize,
956+
offset: base as usize,
962957
len: LOAD_SIZE,
963958
max: 0,
964959
})));
965960
};
961+
962+
let Ok(addr) = usize::try_from(addr) else {
963+
return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
964+
offset: base as usize,
965+
len: LOAD_SIZE,
966+
max: 0,
967+
})));
968+
};
969+
966970
let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?;
967971
self.store.stack.values.push(cast(val)).to_cf()?;
968972
ControlFlow::Continue(())

crates/tinywasm/src/interpreter/num_helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ macro_rules! checked_conv_float {
3535
.store
3636
.stack
3737
.values
38-
.unary::<$from, $to>(|v| {
38+
.unary_into::<$from, $to>(|v| {
3939
let (min, max) = float_min_max!($from, $intermediate);
4040
if unlikely(v.is_nan()) {
4141
return Err(Error::Trap(crate::Trap::InvalidConversionToInt));

crates/tinywasm/src/interpreter/stack/call_stack.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl CallFrame {
6969
}
7070
}
7171

72+
#[inline(always)]
7273
pub(crate) fn incr_instr_ptr(&mut self) {
7374
self.instr_ptr += 1;
7475
}

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

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ impl ValueStack {
172172
T::stack_pop(self);
173173
}
174174

175-
#[inline]
175+
#[inline(always)]
176176
pub(crate) fn select<T: InternalValue>(&mut self) -> Result<()> {
177177
let cond: i32 = self.pop();
178178
let val2: T = self.pop();
@@ -192,51 +192,51 @@ impl ValueStack {
192192
self.stack_ref.select_many(counts.cref as usize, condition);
193193
}
194194

195-
#[inline]
196-
pub(crate) fn binary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
197-
T::stack_calculate(self, func)
198-
}
199-
200-
#[inline]
201-
pub(crate) fn ternary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
202-
T::stack_calculate3(self, func)
195+
#[inline(always)]
196+
pub(crate) fn unary<T: InternalValue>(&mut self, func: impl FnOnce(T) -> Result<T>) -> Result<()> {
197+
T::stack_apply1(self, func)
203198
}
204199

205-
#[inline]
206-
pub(crate) fn binary<T: InternalValue, U: InternalValue>(
200+
#[inline(always)]
201+
pub(crate) fn unary_into<IN: InternalValue, OUT: InternalValue>(
207202
&mut self,
208-
func: impl FnOnce(T, T) -> Result<U>,
203+
func: impl FnOnce(IN) -> Result<OUT>,
209204
) -> Result<()> {
210-
let v2 = T::stack_pop(self);
211-
let v1 = T::stack_pop(self);
212-
U::stack_push(self, func(v1, v2)?)?;
205+
let v = IN::stack_pop(self);
206+
OUT::stack_push(self, func(v)?)?;
213207
Ok(())
214208
}
215209

216-
#[inline]
217-
pub(crate) fn binary_diff<A: InternalValue, B: InternalValue, RES: InternalValue>(
210+
#[inline(always)]
211+
pub(crate) fn binary<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
212+
T::stack_apply2(self, func)
213+
}
214+
215+
#[inline(always)]
216+
pub(crate) fn binary_into<IN: InternalValue, OUT: InternalValue>(
218217
&mut self,
219-
func: impl FnOnce(A, B) -> Result<RES>,
218+
func: impl FnOnce(IN, IN) -> Result<OUT>,
220219
) -> Result<()> {
221-
let v2 = B::stack_pop(self);
222-
let v1 = A::stack_pop(self);
223-
RES::stack_push(self, func(v1, v2)?)?;
220+
let rhs = IN::stack_pop(self);
221+
let lhs = IN::stack_pop(self);
222+
OUT::stack_push(self, func(lhs, rhs)?)?;
224223
Ok(())
225224
}
226225

227-
#[inline]
228-
pub(crate) fn unary<T: InternalValue, U: InternalValue>(
226+
#[inline(always)]
227+
pub(crate) fn binary_mixed<A: InternalValue, B: InternalValue, OUT: InternalValue>(
229228
&mut self,
230-
func: impl FnOnce(T) -> Result<U>,
229+
func: impl FnOnce(A, B) -> Result<OUT>,
231230
) -> Result<()> {
232-
let v1 = T::stack_pop(self);
233-
U::stack_push(self, func(v1)?)?;
231+
let rhs = B::stack_pop(self);
232+
let lhs = A::stack_pop(self);
233+
OUT::stack_push(self, func(lhs, rhs)?)?;
234234
Ok(())
235235
}
236236

237-
#[inline]
238-
pub(crate) fn unary_same<T: InternalValue>(&mut self, func: impl Fn(T) -> Result<T>) -> Result<()> {
239-
T::replace_top(self, func)
237+
#[inline(always)]
238+
pub(crate) fn ternary<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
239+
T::stack_apply3(self, func)
240240
}
241241

242242
pub(crate) fn pop_types<'a>(

0 commit comments

Comments
 (0)