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

Commit 4f405d1

Browse files
pref: more callstack/callframe improvements
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent 9d30a1b commit 4f405d1

File tree

11 files changed

+128
-124
lines changed

11 files changed

+128
-124
lines changed

crates/tinywasm/src/func.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::log;
1+
use crate::{log, runtime::RawWasmValue};
22
use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec};
33
use tinywasm_types::{FuncAddr, FuncType, ValType, WasmValue};
44

@@ -63,7 +63,7 @@ impl FuncHandle {
6363

6464
// 6. Let f be the dummy frame
6565
log::debug!("locals: {:?}", locals);
66-
let call_frame = CallFrame::new(func_inst, params, locals);
66+
let call_frame = CallFrame::new(func_inst, params.iter().map(|v| RawWasmValue::from(*v)), locals);
6767

6868
// 7. Push the frame f to the call stack
6969
// & 8. Push the values to the stack (Not needed since the call frame owns the values)

crates/tinywasm/src/imports.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ impl Extern {
154154
let inner_func = move |ctx: FuncContext<'_>, args: &[WasmValue]| -> Result<Vec<WasmValue>> {
155155
let args = P::from_wasm_value_tuple(args)?;
156156
let result = func(ctx, args)?;
157-
Ok(result.into_wasm_value_tuple())
157+
Ok(result.into_wasm_value_tuple().to_vec())
158158
};
159159

160160
let ty = tinywasm_types::FuncType { params: P::val_types(), results: R::val_types() };
@@ -383,7 +383,7 @@ impl Imports {
383383
.ok_or_else(|| LinkingError::incompatible_import_type(import))?;
384384

385385
Self::compare_types(import, extern_func.ty(), import_func_type)?;
386-
imports.funcs.push(store.add_func(extern_func, *ty, idx)?);
386+
imports.funcs.push(store.add_func(extern_func, idx)?);
387387
}
388388
_ => return Err(LinkingError::incompatible_import_type(import).into()),
389389
},

crates/tinywasm/src/reference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ impl MemoryRef {
8383
/// Load a UTF-8 string from memory
8484
pub fn load_string(&self, offset: usize, len: usize) -> Result<String> {
8585
let bytes = self.load_vec(offset, len)?;
86-
Ok(String::from_utf8(bytes).map_err(|_| crate::Error::Other("Invalid UTF-8 string".to_string()))?)
86+
String::from_utf8(bytes).map_err(|_| crate::Error::Other("Invalid UTF-8 string".to_string()))
8787
}
8888

8989
/// Load a C-style string from memory

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

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::{InterpreterRuntime, Stack};
22
use crate::{cold, log, unlikely};
33
use crate::{
4-
runtime::{BlockType, CallFrame, LabelArgs, LabelFrame},
4+
runtime::{BlockType, CallFrame, LabelFrame},
55
Error, FuncContext, ModuleInstance, Result, Store, Trap,
66
};
77
use alloc::format;
@@ -29,13 +29,12 @@ impl InterpreterRuntime {
2929
let mut cf = stack.call_stack.pop()?;
3030

3131
let mut func_inst = cf.func_instance.clone();
32-
let mut wasm_func = func_inst.assert_wasm().expect("exec expected wasm function");
32+
let mut wasm_func = func_inst.assert_wasm()?;
3333

3434
// The function to execute, gets updated from ExecResult::Call
3535
let mut instrs = &wasm_func.instructions;
3636
let mut instr_count = instrs.len();
37-
38-
let mut current_module = store.get_module_instance(func_inst.owner).unwrap().clone();
37+
let mut current_module = store.get_module_instance_raw(func_inst.owner);
3938

4039
loop {
4140
if unlikely(cf.instr_ptr >= instr_count) {
@@ -164,8 +163,8 @@ fn exec_one(
164163
}
165164
};
166165

167-
let params = stack.values.pop_n_rev(ty.params.len())?.collect::<Vec<_>>();
168-
let call_frame = CallFrame::new_raw(func_inst, &params, locals);
166+
let params = stack.values.pop_n_rev(ty.params.len())?;
167+
let call_frame = CallFrame::new(func_inst, params, locals);
169168

170169
// push the call frame
171170
cf.instr_ptr += 1; // skip the call instruction
@@ -213,8 +212,8 @@ fn exec_one(
213212
}
214213
};
215214

216-
let params = stack.values.pop_n_rev(func_ty.params.len())?.collect::<Vec<_>>();
217-
let call_frame = CallFrame::new_raw(func_inst, &params, locals);
215+
let params = stack.values.pop_n_rev(func_ty.params.len())?;
216+
let call_frame = CallFrame::new(func_inst, params, locals);
218217

219218
// push the call frame
220219
cf.instr_ptr += 1; // skip the call instruction
@@ -229,13 +228,14 @@ fn exec_one(
229228
// truthy value is on the top of the stack, so enter the then block
230229
if stack.values.pop_t::<i32>()? != 0 {
231230
cf.enter_label(
232-
LabelFrame {
233-
instr_ptr: cf.instr_ptr,
234-
end_instr_ptr: cf.instr_ptr + *end_offset,
235-
stack_ptr: stack.values.len(), // - params,
236-
args: LabelArgs::new(*args, module)?,
237-
ty: BlockType::If,
238-
},
231+
LabelFrame::new(
232+
cf.instr_ptr,
233+
cf.instr_ptr + *end_offset,
234+
stack.values.len(), // - params,
235+
BlockType::If,
236+
args,
237+
module,
238+
),
239239
&mut stack.values,
240240
);
241241
return Ok(ExecResult::Ok);
@@ -244,13 +244,14 @@ fn exec_one(
244244
// falsy value is on the top of the stack
245245
if let Some(else_offset) = else_offset {
246246
cf.enter_label(
247-
LabelFrame {
248-
instr_ptr: cf.instr_ptr + *else_offset,
249-
end_instr_ptr: cf.instr_ptr + *end_offset,
250-
stack_ptr: stack.values.len(), // - params,
251-
args: LabelArgs::new(*args, module)?,
252-
ty: BlockType::Else,
253-
},
247+
LabelFrame::new(
248+
cf.instr_ptr + *else_offset,
249+
cf.instr_ptr + *end_offset,
250+
stack.values.len(), // - params,
251+
BlockType::Else,
252+
args,
253+
module,
254+
),
254255
&mut stack.values,
255256
);
256257
cf.instr_ptr += *else_offset;
@@ -261,26 +262,28 @@ fn exec_one(
261262

262263
Loop(args, end_offset) => {
263264
cf.enter_label(
264-
LabelFrame {
265-
instr_ptr: cf.instr_ptr,
266-
end_instr_ptr: cf.instr_ptr + *end_offset,
267-
stack_ptr: stack.values.len(), // - params,
268-
args: LabelArgs::new(*args, module)?,
269-
ty: BlockType::Loop,
270-
},
265+
LabelFrame::new(
266+
cf.instr_ptr,
267+
cf.instr_ptr + *end_offset,
268+
stack.values.len(), // - params,
269+
BlockType::Loop,
270+
args,
271+
module,
272+
),
271273
&mut stack.values,
272274
);
273275
}
274276

275277
Block(args, end_offset) => {
276278
cf.enter_label(
277-
LabelFrame {
278-
instr_ptr: cf.instr_ptr,
279-
end_instr_ptr: cf.instr_ptr + *end_offset,
280-
stack_ptr: stack.values.len(), //- params,
281-
args: LabelArgs::new(*args, module)?,
282-
ty: BlockType::Block,
283-
},
279+
LabelFrame::new(
280+
cf.instr_ptr,
281+
cf.instr_ptr + *end_offset,
282+
stack.values.len(), // - params,
283+
BlockType::Block,
284+
args,
285+
module,
286+
),
284287
&mut stack.values,
285288
);
286289
}
@@ -341,7 +344,7 @@ fn exec_one(
341344
panic!("else: no label to end, this should have been validated by the parser");
342345
};
343346

344-
let res_count = block.args.results;
347+
let res_count = block.results;
345348
stack.values.truncate_keep(block.stack_ptr, res_count);
346349
cf.instr_ptr += *end_offset;
347350
}
@@ -352,7 +355,7 @@ fn exec_one(
352355
cold();
353356
panic!("end: no label to end, this should have been validated by the parser");
354357
};
355-
stack.values.truncate_keep(block.stack_ptr, block.args.results)
358+
stack.values.truncate_keep(block.stack_ptr, block.results)
356359
}
357360

358361
LocalGet(local_index) => stack.values.push(cf.get_local(*local_index as usize)),

crates/tinywasm/src/runtime/stack.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mod call_stack;
33
mod value_stack;
44

55
use self::{call_stack::CallStack, value_stack::ValueStack};
6-
pub(crate) use blocks::{BlockType, LabelArgs, LabelFrame};
6+
pub(crate) use blocks::{BlockType, LabelFrame};
77
pub(crate) use call_stack::CallFrame;
88

99
/// A WebAssembly Stack

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

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
use alloc::vec::Vec;
22
use tinywasm_types::BlockArgs;
33

4-
use crate::{ModuleInstance, Result};
4+
use crate::{unlikely, ModuleInstance};
55

6-
#[derive(Debug, Clone, Default)]
6+
#[derive(Debug, Clone)]
77
pub(crate) struct Labels(Vec<LabelFrame>);
88

99
impl Labels {
10+
pub(crate) fn new() -> Self {
11+
// this is somehow a lot faster than Vec::with_capacity(128) or even using Default::default() in the benchmarks
12+
Self(Vec::new())
13+
}
14+
1015
pub(crate) fn len(&self) -> usize {
1116
self.0.len()
1217
}
@@ -19,7 +24,12 @@ impl Labels {
1924
#[inline]
2025
/// get the label at the given index, where 0 is the top of the stack
2126
pub(crate) fn get_relative_to_top(&self, index: usize) -> Option<&LabelFrame> {
22-
self.0.get(self.0.len() - index - 1)
27+
// the vast majority of wasm functions don't use break to return
28+
if unlikely(index >= self.0.len()) {
29+
return None;
30+
}
31+
32+
Some(&self.0[self.0.len() - index - 1])
2333
}
2434

2535
#[inline]
@@ -43,10 +53,34 @@ pub(crate) struct LabelFrame {
4353

4454
// position of the stack pointer when the block was entered
4555
pub(crate) stack_ptr: usize,
46-
pub(crate) args: LabelArgs,
56+
pub(crate) results: usize,
57+
pub(crate) params: usize,
4758
pub(crate) ty: BlockType,
4859
}
4960

61+
impl LabelFrame {
62+
#[inline]
63+
pub(crate) fn new(
64+
instr_ptr: usize,
65+
end_instr_ptr: usize,
66+
stack_ptr: usize,
67+
ty: BlockType,
68+
args: &BlockArgs,
69+
module: &ModuleInstance,
70+
) -> Self {
71+
let (params, results) = match args {
72+
BlockArgs::Empty => (0, 0),
73+
BlockArgs::Type(_) => (0, 1),
74+
BlockArgs::FuncType(t) => {
75+
let ty = module.func_ty(*t);
76+
(ty.params.len(), ty.results.len())
77+
}
78+
};
79+
80+
Self { instr_ptr, end_instr_ptr, stack_ptr, results, params, ty }
81+
}
82+
}
83+
5084
#[derive(Debug, Copy, Clone)]
5185
#[allow(dead_code)]
5286
pub(crate) enum BlockType {
@@ -55,21 +89,3 @@ pub(crate) enum BlockType {
5589
Else,
5690
Block,
5791
}
58-
59-
#[derive(Debug, Clone, Default)]
60-
pub(crate) struct LabelArgs {
61-
pub(crate) params: usize,
62-
pub(crate) results: usize,
63-
}
64-
65-
impl LabelArgs {
66-
pub(crate) fn new(args: BlockArgs, module: &ModuleInstance) -> Result<Self> {
67-
Ok(match args {
68-
BlockArgs::Empty => LabelArgs { params: 0, results: 0 },
69-
BlockArgs::Type(_) => LabelArgs { params: 0, results: 1 },
70-
BlockArgs::FuncType(t) => {
71-
LabelArgs { params: module.func_ty(t).params.len(), results: module.func_ty(t).results.len() }
72-
}
73-
})
74-
}
75-
}

0 commit comments

Comments
 (0)