Skip to content

Commit 55a7ac0

Browse files
chore: add CallSelf/ReturnCallSelf
Signed-off-by: Henry <mail@henrygressmann.de>
1 parent 2e40140 commit 55a7ac0

File tree

4 files changed

+65
-9
lines changed

4 files changed

+65
-9
lines changed

crates/parser/src/module.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::log::debug;
2-
use crate::{ParseError, Result, conversion};
2+
use crate::{conversion, ParseError, Result};
33
use alloc::string::ToString;
44
use alloc::sync::Arc;
55
use alloc::{format, vec::Vec};
66
use tinywasm_types::{
7-
ArcSlice, Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, TinyWasmModule,
8-
ValueCounts, ValueCountsSmall, WasmFunction, WasmFunctionData,
7+
ArcSlice, Data, Element, Export, FuncType, Global, Import, ImportKind, Instruction, MemoryType, TableType,
8+
TinyWasmModule, ValueCounts, ValueCountsSmall, WasmFunction, WasmFunctionData,
99
};
1010
use wasmparser::{FuncValidatorAllocations, Payload, Validator};
1111

@@ -31,6 +31,16 @@ pub(crate) struct ModuleReader {
3131
}
3232

3333
impl ModuleReader {
34+
fn apply_instruction_rewrites(instructions: &mut [Instruction], self_func_addr: u32) {
35+
for instr in instructions.iter_mut() {
36+
if matches!(instr, Instruction::Call(addr) if *addr == self_func_addr) {
37+
*instr = Instruction::CallSelf;
38+
} else if matches!(instr, Instruction::ReturnCall(addr) if *addr == self_func_addr) {
39+
*instr = Instruction::ReturnCallSelf;
40+
}
41+
}
42+
}
43+
3444
pub(crate) fn new() -> Self {
3545
Self::default()
3646
}
@@ -189,14 +199,22 @@ impl ModuleReader {
189199
return Err(ParseError::Other("Code and code type address count mismatch".to_string()));
190200
}
191201

202+
let imported_func_count =
203+
self.imports.iter().filter(|i| matches!(&i.kind, ImportKind::Function(_))).count() as u32;
204+
192205
let funcs = self
193206
.code
194207
.into_iter()
195208
.zip(self.code_type_addrs)
196-
.map(|((instructions, data, locals), ty_idx)| {
209+
.enumerate()
210+
.map(|(func_idx, ((instructions, data, locals), ty_idx))| {
197211
let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone();
198212
let params = ValueCountsSmall::from(&ty.params);
199-
WasmFunction { instructions: ArcSlice(instructions), data, locals, params, ty }
213+
let self_func_addr = imported_func_count + func_idx as u32;
214+
let mut instructions = instructions.to_vec();
215+
Self::apply_instruction_rewrites(&mut instructions, self_func_addr);
216+
217+
WasmFunction { instructions: ArcSlice::from(instructions), data, locals, params, ty }
200218
})
201219
.collect::<Vec<_>>();
202220

crates/tinywasm/benches/fibonacci.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ fn fibonacci_run(module: TinyWasmModule, recursive: bool, n: i32) -> Result<()>
3636

3737
fn criterion_benchmark(c: &mut Criterion) {
3838
let module = fibonacci_parse().expect("fibonacci_parse");
39-
let twasm = fibonacci_to_twasm(&module).expect("fibonacci_to_twasm");
39+
let _twasm = fibonacci_to_twasm(&module).expect("fibonacci_to_twasm");
4040

41-
c.bench_function("fibonacci_parse", |b| b.iter(fibonacci_parse));
42-
c.bench_function("fibonacci_to_twasm", |b| b.iter(|| fibonacci_to_twasm(&module)));
43-
c.bench_function("fibonacci_from_twasm", |b| b.iter(|| fibonacci_from_twasm(&twasm)));
41+
// c.bench_function("fibonacci_parse", |b| b.iter(fibonacci_parse));
42+
// c.bench_function("fibonacci_to_twasm", |b| b.iter(|| fibonacci_to_twasm(&module)));
43+
// c.bench_function("fibonacci_from_twasm", |b| b.iter(|| fibonacci_from_twasm(&twasm)));
4444
c.bench_function("fibonacci_iterative_60", |b| b.iter(|| fibonacci_run(module.clone(), false, 60)));
4545
c.bench_function("fibonacci_recursive_26", |b| b.iter(|| fibonacci_run(module.clone(), true, 26)));
4646
}

crates/tinywasm/src/interpreter/executor.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,10 @@ impl<'store> Executor<'store> {
9696
Select128 => self.store.stack.values.select::<Value128>().to_cf()?,
9797
SelectRef => self.store.stack.values.select::<ValueRef>().to_cf()?,
9898
Call(v) => return self.exec_call_direct::<false>(*v),
99+
CallSelf => return self.exec_call_self::<false>(),
99100
CallIndirect(ty, table) => return self.exec_call_indirect::<false>(*ty, *table),
100101
ReturnCall(v) => return self.exec_call_direct::<true>(*v),
102+
ReturnCallSelf => return self.exec_call_self::<true>(),
101103
ReturnCallIndirect(ty, table) => return self.exec_call_indirect::<true>(*ty, *table),
102104
Jump(ip) => {
103105
self.cf.instr_ptr = *ip as usize;
@@ -717,6 +719,40 @@ impl<'store> Executor<'store> {
717719
crate::Function::Host(host_func) => self.exec_call_host(host_func.clone()),
718720
}
719721
}
722+
723+
fn exec_call_self<const IS_RETURN_CALL: bool>(&mut self) -> ControlFlow<Option<Error>> {
724+
if !IS_RETURN_CALL && self.store.stack.call_stack.is_full() {
725+
return ControlFlow::Break(Some(Trap::CallStackOverflow.into()));
726+
}
727+
728+
let params = self.func.params;
729+
let locals = self.func.locals;
730+
731+
if IS_RETURN_CALL {
732+
self.store.stack.values.truncate_keep_counts(self.cf.locals_base, params);
733+
}
734+
735+
let (locals_base, _stack_base, stack_offset) = match self.store.stack.values.enter_locals(params, locals) {
736+
Ok(v) => v,
737+
Err(Error::Trap(Trap::ValueStackOverflow)) if !IS_RETURN_CALL => {
738+
return ControlFlow::Break(Some(Trap::CallStackOverflow.into()));
739+
}
740+
Err(err) => return ControlFlow::Break(Some(err)),
741+
};
742+
743+
let new_call_frame = CallFrame::new(self.cf.func_addr, self.cf.module_addr, locals_base, stack_offset);
744+
745+
if IS_RETURN_CALL {
746+
self.cf = new_call_frame;
747+
} else {
748+
self.cf.incr_instr_ptr();
749+
self.store.stack.call_stack.push(self.cf).to_cf()?;
750+
self.cf = new_call_frame;
751+
}
752+
753+
ControlFlow::Continue(())
754+
}
755+
720756
fn exec_call_indirect<const IS_RETURN_CALL: bool>(
721757
&mut self,
722758
type_addr: u32,

crates/types/src/instructions.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ pub enum Instruction {
6767
BranchTableTarget(u32), // (landing_pad_ip)
6868
Return,
6969
Call(FuncAddr),
70+
CallSelf,
7071
CallIndirect(TypeAddr, TableAddr),
7172
ReturnCall(FuncAddr),
73+
ReturnCallSelf,
7274
ReturnCallIndirect(TypeAddr, TableAddr),
7375

7476
// > Parametric Instructions

0 commit comments

Comments
 (0)