Skip to content

Commit c3b1f58

Browse files
chore: cleanup + add wasm intrinsics
Signed-off-by: Henry <mail@henrygressmann.de>
1 parent 0ed3e1d commit c3b1f58

File tree

17 files changed

+600
-266
lines changed

17 files changed

+600
-266
lines changed

.cargo/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ test-wasm-2="test --package tinywasm --test test-wasm-2 --release"
55
test-wasm-3="test --package tinywasm --test test-wasm-3 --release"
66
test-wast="test --package tinywasm --test test-wast"
77
test-wasm-custom="test --package tinywasm --test test-wasm-custom --release"
8+
9+
[target.x86_64-unknown-linux-gnu]
10+
rustflags=["-C", "target-cpu=x86-64-v3"]

crates/parser/src/visit.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
657657
}
658658

659659
fn visit_loop(&mut self, _ty: wasmparser::BlockType) -> Self::Output {
660+
if !matches!(self.instructions.last(), Some(Instruction::Nop)) {
661+
self.instructions.push(Instruction::Nop); // add nop to ensure that no superinstruction can be merged across block boundaries
662+
}
660663
let start_ip = self.instructions.len();
661664
self.ctx_stack.push(LoweringCtx { kind: BlockKind::Loop, has_else: false, start_ip, branch_jumps: Vec::new() });
662665
}
@@ -683,7 +686,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
683686
ctx.branch_jumps.push(jump_ip);
684687
self.patch_jump_if_zero(cond_jump_ip, self.instructions.len());
685688
if !matches!(self.instructions.last(), Some(Instruction::Nop)) {
686-
self.instructions.push(Instruction::Nop);
689+
self.instructions.push(Instruction::Nop); // add nop to ensure that no superinstruction can be merged across block boundaries
687690
}
688691
};
689692
};
@@ -693,7 +696,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
693696
if let Some(ctx) = self.ctx_stack.pop() {
694697
self.patch_end_jumps(ctx, self.instructions.len());
695698
if !matches!(self.instructions.last(), Some(Instruction::Nop)) {
696-
self.instructions.push(Instruction::Nop);
699+
self.instructions.push(Instruction::Nop); // add nop to ensure that no superinstruction can be merged across block boundaries
697700
}
698701
} else {
699702
self.instructions.push(Instruction::Return);

crates/tinywasm/benches/argon2id.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use eyre::Result;
33
use tinywasm::{ModuleInstance, Store, types};
44
use types::TinyWasmModule;
55

6-
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/argon2id.opt.wasm");
6+
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/argon2id.wasm");
77

88
fn argon2id_parse() -> Result<TinyWasmModule> {
99
let parser = tinywasm_parser::Parser::new();

crates/tinywasm/benches/fibonacci.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use eyre::Result;
33
use tinywasm::{ModuleInstance, Store, types};
44
use types::TinyWasmModule;
55

6-
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/fibonacci.opt.wasm");
6+
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/fibonacci.wasm");
77

88
fn fibonacci_parse() -> Result<TinyWasmModule> {
99
let parser = tinywasm_parser::Parser::new();

crates/tinywasm/benches/tinywasm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use eyre::Result;
33
use tinywasm::{Extern, FuncContext, Imports, ModuleInstance, Store, types};
44
use types::TinyWasmModule;
55

6-
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.opt.wasm");
6+
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.wasm");
77

88
fn tinywasm_parse() -> Result<TinyWasmModule> {
99
let parser = tinywasm_parser::Parser::new();

crates/tinywasm/src/func.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::interpreter::stack::CallFrame;
22
use crate::{Error, FuncContext, InterpreterRuntime, Result, Store};
3-
use crate::{Function, log, unlikely};
3+
use crate::{Function, unlikely};
44
use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};
55
use tinywasm_types::{ExternRef, FuncRef, FuncType, ModuleInstanceAddr, ValType, WasmValue};
66

@@ -34,23 +34,14 @@ impl FuncHandle {
3434
}
3535

3636
// 5. For each value type and the corresponding value, check if types match
37-
if !(func_ty.params.iter().zip(params).enumerate().all(|(_i, (ty, param))| {
38-
if ty == &param.val_type() {
39-
true
40-
} else {
41-
log::error!("param type mismatch at index {_i}: expected {ty:?}, got {param:?}");
42-
false
43-
}
44-
})) {
37+
if !(func_ty.params.iter().zip(params).all(|(ty, param)| ty == &param.val_type())) {
4538
return Err(Error::Other("Type mismatch".into()));
4639
}
4740

4841
let func_inst = store.state.get_func(self.addr);
4942
let wasm_func = match &func_inst.func {
5043
Function::Host(host_func) => {
51-
let host_func = host_func.clone();
52-
let ctx = FuncContext { store, module_addr: self.module_addr };
53-
return host_func.call(ctx, params);
44+
return host_func.clone().call(FuncContext { store, module_addr: self.module_addr }, params);
5445
}
5546
Function::Wasm(wasm_func) => wasm_func.clone(),
5647
};

crates/tinywasm/src/interpreter/executor.rs

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::no_std_floats::NoStdFloatExt;
44

55
use alloc::boxed::Box;
6-
use alloc::{format, rc::Rc, string::ToString};
6+
use alloc::{rc::Rc, string::ToString};
77
use core::ops::ControlFlow;
88

99
use interpreter::stack::CallFrame;
@@ -78,7 +78,7 @@ impl<'store> Executor<'store> {
7878
}};
7979
}
8080

81-
let next = match self.func.instructions.0.get(self.cf.instr_ptr) {
81+
let next = match self.func.instructions.0.get(self.cf.instr_ptr as usize) {
8282
Some(instr) => instr,
8383
None => unreachable!(
8484
"Instruction pointer out of bounds: {} ({} instructions)",
@@ -89,7 +89,7 @@ impl<'store> Executor<'store> {
8989

9090
#[rustfmt::skip]
9191
match next {
92-
Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
92+
Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 | BranchTableTarget {..} => {}
9393
Unreachable => return ControlFlow::Break(Some(Trap::Unreachable.into())),
9494
Drop32 => self.store.stack.values.drop::<Value32>(),
9595
Drop64 => self.store.stack.values.drop::<Value64>(),
@@ -107,66 +107,66 @@ impl<'store> Executor<'store> {
107107
ReturnCallSelf => return self.exec_call_self::<true>(),
108108
ReturnCallIndirect(ty, table) => return self.exec_call_indirect::<true>(*ty, *table),
109109
Jump(ip) => {
110-
self.cf.instr_ptr = *ip as usize;
110+
self.cf.instr_ptr = *ip;
111111
return ControlFlow::Continue(());
112112
}
113113
JumpIfZero(ip) => {
114114
let cond = self.store.stack.values.pop::<i32>();
115115

116116
if cond == 0 {
117-
self.cf.instr_ptr = *ip as usize;
117+
self.cf.instr_ptr = *ip;
118118
} else {
119119
self.cf.incr_instr_ptr();
120120
}
121121
return ControlFlow::Continue(());
122122
}
123123
DropKeepSmall { base32, keep32, base64, keep64, base128, keep128, base_ref, keep_ref } => {
124-
let b32 = self.cf.stack_base().s32 + *base32 as usize;
124+
let b32 = self.cf.stack_base().s32 + *base32 as u32;
125125
let k32 = *keep32 as usize;
126-
self.store.stack.values.stack_32.truncate_keep(b32, k32);
127-
let b64 = self.cf.stack_base().s64 + *base64 as usize;
126+
self.store.stack.values.stack_32.truncate_keep(b32 as usize, k32);
127+
let b64 = self.cf.stack_base().s64 + *base64 as u32;
128128
let k64 = *keep64 as usize;
129-
self.store.stack.values.stack_64.truncate_keep(b64, k64);
130-
let b128 = self.cf.stack_base().s128 + *base128 as usize;
129+
self.store.stack.values.stack_64.truncate_keep(b64 as usize, k64);
130+
let b128 = self.cf.stack_base().s128 + *base128 as u32;
131131
let k128 = *keep128 as usize;
132-
self.store.stack.values.stack_128.truncate_keep(b128, k128);
133-
let bref = self.cf.stack_base().sref + *base_ref as usize;
132+
self.store.stack.values.stack_128.truncate_keep(b128 as usize, k128);
133+
let bref = self.cf.stack_base().sref + *base_ref as u32;
134134
let kref = *keep_ref as usize;
135-
self.store.stack.values.stack_ref.truncate_keep(bref, kref);
135+
self.store.stack.values.stack_ref.truncate_keep(bref as usize, kref);
136136
}
137137
DropKeep32(base, keep) => {
138-
let b = self.cf.stack_base().s32 + *base as usize;
138+
let b = self.cf.stack_base().s32 + *base as u32;
139139
let k = *keep as usize;
140-
self.store.stack.values.stack_32.truncate_keep(b, k);
140+
self.store.stack.values.stack_32.truncate_keep(b as usize, k);
141141
}
142142
DropKeep64(base, keep) => {
143-
let b = self.cf.stack_base().s64 + *base as usize;
143+
let b = self.cf.stack_base().s64 + *base as u32;
144144
let k = *keep as usize;
145-
self.store.stack.values.stack_64.truncate_keep(b, k);
145+
self.store.stack.values.stack_64.truncate_keep(b as usize, k);
146146
}
147147
DropKeep128(base, keep) => {
148-
let b = self.cf.stack_base().s128 + *base as usize;
148+
let b = self.cf.stack_base().s128 + *base as u32;
149149
let k = *keep as usize;
150-
self.store.stack.values.stack_128.truncate_keep(b, k);
150+
self.store.stack.values.stack_128.truncate_keep(b as usize, k);
151151
}
152152
DropKeepRef(base, keep) => {
153-
let b = self.cf.stack_base().sref + *base as usize;
153+
let b = self.cf.stack_base().sref + *base as u32;
154154
let k = *keep as usize;
155-
self.store.stack.values.stack_ref.truncate_keep(b, k);
155+
self.store.stack.values.stack_ref.truncate_keep(b as usize, k);
156156
}
157157
BranchTable(default_ip, len) => {
158158
let idx = self.store.stack.values.pop::<i32>();
159159
let start = self.cf.instr_ptr + 1;
160160

161161
let target_ip = if idx >= 0 && (idx as u32) < *len {
162-
match self.func.instructions.0.get(start + idx as usize) {
162+
match self.func.instructions.0.get((start + idx as u32) as usize) {
163163
Some(Instruction::BranchTableTarget(ip)) => *ip,
164164
_ => *default_ip,
165165
}
166166
} else {
167167
*default_ip
168168
};
169-
self.cf.instr_ptr = target_ip as usize;
169+
self.cf.instr_ptr = target_ip;
170170
return ControlFlow::Continue(());
171171
}
172172
Return => return self.exec_return(),
@@ -434,10 +434,10 @@ impl<'store> Executor<'store> {
434434
V128Load16x4U(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load16x4_u(v.to_le_bytes()))?,
435435
V128Load32x2S(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load32x2_s(v.to_le_bytes()))?,
436436
V128Load32x2U(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load32x2_u(v.to_le_bytes()))?,
437-
V128Load8Splat(_arg) => self.exec_mem_load::<i8, 1, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i8)?,
438-
V128Load16Splat(_arg) => self.exec_mem_load::<i16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i16)?,
439-
V128Load32Splat(_arg) => self.exec_mem_load::<i32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i32)?,
440-
V128Load64Splat(_arg) => self.exec_mem_load::<i64, 8, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i64)?,
437+
V128Load8Splat(arg) => self.exec_mem_load::<i8, 1, Value128>(arg.mem_addr(), arg.offset(), Value128::splat_i8)?,
438+
V128Load16Splat(arg) => self.exec_mem_load::<i16, 2, Value128>(arg.mem_addr(), arg.offset(), Value128::splat_i16)?,
439+
V128Load32Splat(arg) => self.exec_mem_load::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), Value128::splat_i32)?,
440+
V128Load64Splat(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), Value128::splat_i64)?,
441441
V128Store(arg) => self.exec_mem_store::<Value128, Value128, 16>(arg.mem_addr(), arg.offset(), |v| v)?,
442442
V128Store8Lane(arg, lane) => self.exec_mem_store_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
443443
V128Store16Lane(arg, lane) => self.exec_mem_store_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
@@ -655,9 +655,6 @@ impl<'store> Executor<'store> {
655655
F64x2PromoteLowF32x4 => stack_op!(unary Value128, |v| v.f64x2_promote_low_f32x4()),
656656
I32x4TruncSatF64x2SZero => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f64x2_s_zero()),
657657
I32x4TruncSatF64x2UZero => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f64x2_u_zero()),
658-
659-
#[allow(unreachable_patterns)]
660-
i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))),
661658
};
662659

663660
self.cf.incr_instr_ptr();
@@ -670,10 +667,6 @@ impl<'store> Executor<'store> {
670667
func_addr: FuncAddr,
671668
owner: ModuleInstanceAddr,
672669
) -> ControlFlow<Option<Error>> {
673-
if !IS_RETURN_CALL && self.store.stack.call_stack.is_full() {
674-
return ControlFlow::Break(Some(Trap::CallStackOverflow.into()));
675-
}
676-
677670
if !Rc::ptr_eq(&self.func, &wasm_func) {
678671
self.func = wasm_func.clone();
679672
}
@@ -726,10 +719,6 @@ impl<'store> Executor<'store> {
726719
}
727720

728721
fn exec_call_self<const IS_RETURN_CALL: bool>(&mut self) -> ControlFlow<Option<Error>> {
729-
if !IS_RETURN_CALL && self.store.stack.call_stack.is_full() {
730-
return ControlFlow::Break(Some(Trap::CallStackOverflow.into()));
731-
}
732-
733722
let params = self.func.params;
734723
let locals = self.func.locals;
735724

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

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,35 @@ use tinywasm_types::{FuncAddr, ModuleInstanceAddr, ValueCountsSmall};
66
#[derive(Debug)]
77
pub(crate) struct CallStack {
88
stack: Vec<CallFrame>,
9-
len: usize,
109
}
1110

1211
impl CallStack {
1312
pub(crate) fn new(config: &crate::engine::Config) -> Self {
14-
let mut stack = Vec::with_capacity(config.call_stack_size);
15-
stack.resize_with(config.call_stack_size, CallFrame::default);
16-
Self { stack, len: 0 }
13+
Self { stack: Vec::with_capacity(config.call_stack_size) }
1714
}
1815

1916
pub(crate) fn clear(&mut self) {
20-
self.len = 0;
17+
self.stack.clear();
2118
}
2219

20+
#[inline(always)]
2321
pub(crate) fn pop(&mut self) -> Option<CallFrame> {
24-
if self.len == 0 {
25-
return None;
26-
}
27-
28-
self.len -= 1;
29-
Some(self.stack[self.len])
30-
}
31-
32-
pub(crate) fn is_full(&self) -> bool {
33-
self.len >= self.stack.len()
22+
self.stack.pop()
3423
}
3524

25+
#[inline(always)]
3626
pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> {
37-
if unlikely(self.is_full()) {
27+
if unlikely(self.stack.len() == self.stack.capacity()) {
3828
return Err(Trap::CallStackOverflow.into());
3929
}
40-
41-
self.stack[self.len] = call_frame;
42-
self.len += 1;
30+
self.stack.push(call_frame);
4331
Ok(())
4432
}
4533
}
4634

4735
#[derive(Debug, Clone, Copy, Default)]
4836
pub(crate) struct CallFrame {
49-
pub(crate) instr_ptr: usize,
37+
pub(crate) instr_ptr: u32,
5038
pub(crate) module_addr: ModuleInstanceAddr,
5139
pub(crate) func_addr: FuncAddr,
5240
pub(crate) locals_base: StackBase,
@@ -55,10 +43,10 @@ pub(crate) struct CallFrame {
5543

5644
#[derive(Debug, Clone, Copy, Default)]
5745
pub(crate) struct StackBase {
58-
pub(crate) s32: usize,
59-
pub(crate) s64: usize,
60-
pub(crate) s128: usize,
61-
pub(crate) sref: usize,
46+
pub(crate) s32: u32,
47+
pub(crate) s64: u32,
48+
pub(crate) s128: u32,
49+
pub(crate) sref: u32,
6250
}
6351

6452
impl CallFrame {
@@ -74,10 +62,10 @@ impl CallFrame {
7462
#[inline]
7563
pub(crate) fn stack_base(&self) -> StackBase {
7664
StackBase {
77-
s32: self.locals_base.s32 + self.stack_offset.c32 as usize,
78-
s64: self.locals_base.s64 + self.stack_offset.c64 as usize,
79-
s128: self.locals_base.s128 + self.stack_offset.c128 as usize,
80-
sref: self.locals_base.sref + self.stack_offset.cref as usize,
65+
s32: self.locals_base.s32 + self.stack_offset.c32 as u32,
66+
s64: self.locals_base.s64 + self.stack_offset.c64 as u32,
67+
s128: self.locals_base.s128 + self.stack_offset.c128 as u32,
68+
sref: self.locals_base.sref + self.stack_offset.cref as u32,
8169
}
8270
}
8371

0 commit comments

Comments
 (0)