Skip to content

Commit ee869ab

Browse files
chore: improve label handling
Signed-off-by: Henry Gressmann <[email protected]>
1 parent fc97f2c commit ee869ab

File tree

12 files changed

+163
-51
lines changed

12 files changed

+163
-51
lines changed

crates/parser/src/conversion.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,7 @@ pub(crate) fn convert_blocktype(blocktype: wasmparser::BlockType) -> BlockArgs {
8181
// TODO: maybe solve this differently so we can support 128-bit values
8282
// without having to increase the size of the WasmValue enum
8383
Type(ty) => BlockArgs::Type(convert_valtype(&ty)),
84-
85-
// Wasm 2.0
86-
FuncType(_ty) => unimplemented!(),
87-
// FuncType(ty) => BlockArgs::FuncType(*ty),
84+
FuncType(ty) => BlockArgs::FuncType(ty),
8885
}
8986
}
9087

crates/tinywasm/src/func.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloc::{format, string::String, string::ToString, vec, vec::Vec};
2-
use log::debug;
2+
use log::{debug, info};
33
use tinywasm_types::{FuncAddr, FuncType, WasmValue};
44

55
use crate::{
@@ -34,6 +34,7 @@ impl FuncHandle {
3434

3535
// 4. If the length of the provided argument values is different from the number of expected arguments, then fail
3636
if func_ty.params.len() != params.len() {
37+
info!("func_ty.params: {:?}", func_ty.params);
3738
return Err(Error::Other(format!(
3839
"param count mismatch: expected {}, got {}",
3940
func_ty.params.len(),

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

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
};
77
use alloc::vec::Vec;
88
use log::info;
9-
use tinywasm_types::{BlockArgs, Instruction};
9+
use tinywasm_types::{BlockArgs, FuncType, Instruction, ValType};
1010

1111
mod macros;
1212
use macros::*;
@@ -137,37 +137,37 @@ fn exec_one(
137137
info!("end: {:?} (@{})", instrs[end_instr_ptr], end_instr_ptr);
138138

139139
if stack.values.pop_t::<i32>()? != 0 {
140+
// let params = stack.values.pop_block_params(*args, &module)?;
140141
cf.labels.push(LabelFrame {
141142
instr_ptr: cf.instr_ptr,
142143
end_instr_ptr: cf.instr_ptr + *end_offset,
143-
stack_ptr: stack.values.len(),
144+
stack_ptr: stack.values.len(), // - params,
144145
args: *args,
145146
ty: BlockType::If,
146147
});
147-
stack.values.push_block_args(*args)?;
148148
}
149149
}
150150

151151
Loop(args, end_offset) => {
152+
// let params = stack.values.pop_block_params(*args, &module)?;
152153
cf.labels.push(LabelFrame {
153154
instr_ptr: cf.instr_ptr,
154155
end_instr_ptr: cf.instr_ptr + *end_offset,
155-
stack_ptr: stack.values.len(),
156+
stack_ptr: stack.values.len(), // - params,
156157
args: *args,
157158
ty: BlockType::Loop,
158159
});
159-
stack.values.push_block_args(*args)?;
160160
}
161161

162162
Block(args, end_offset) => {
163+
// let params = stack.values.pop_block_params(*args, &module)?;
163164
cf.labels.push(LabelFrame {
164165
instr_ptr: cf.instr_ptr,
165166
end_instr_ptr: cf.instr_ptr + *end_offset,
166-
stack_ptr: stack.values.len(),
167+
stack_ptr: stack.values.len(), //- params,
167168
args: *args,
168169
ty: BlockType::Block,
169170
});
170-
stack.values.push_block_args(*args)?;
171171
}
172172

173173
BrTable(_default, len) => {
@@ -215,17 +215,18 @@ fn exec_one(
215215
panic!("end: no label to end, this should have been validated by the parser");
216216
};
217217

218-
let res: &[RawWasmValue] = match block.args {
219-
BlockArgs::Empty => &[],
220-
BlockArgs::Type(_t) => todo!(),
221-
BlockArgs::FuncType(_t) => todo!(),
218+
let res_count = match block.args {
219+
BlockArgs::Empty => 0,
220+
BlockArgs::Type(_) => 1,
221+
BlockArgs::FuncType(t) => module.func_ty(t).results.len(),
222222
};
223223

224-
// trim the lable's stack from the stack
225-
stack.values.trim(block.stack_ptr);
224+
info!("we want to keep {} values on the stack", res_count);
225+
info!("current block stack ptr: {}", block.stack_ptr);
226+
info!("stack: {:?}", stack.values);
226227

227-
// push the block result values to the stack
228-
stack.values.extend(res.iter().copied());
228+
// trim the lable's stack from the stack
229+
stack.values.truncate_keep(block.stack_ptr, res_count)
229230
}
230231

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use alloc::vec::Vec;
22
use log::info;
3-
use tinywasm_types::BlockArgs;
3+
use tinywasm_types::{BlockArgs, FuncType};
44

55
#[derive(Debug, Default, Clone)]
66
pub(crate) struct Labels(Vec<LabelFrame>);

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl CallFrame {
9797
BlockType::Loop => {
9898
// this is a loop, so we want to jump back to the start of the loop
9999
self.instr_ptr = break_to.instr_ptr;
100-
value_stack.trim(break_to.stack_ptr);
100+
value_stack.truncate(break_to.stack_ptr);
101101

102102
// we also want to trim the label stack to the loop (but not including the loop)
103103
self.labels.trim(self.labels.len() - break_to_relative as usize);
@@ -107,11 +107,10 @@ impl CallFrame {
107107

108108
// this is a block, so we want to jump to the next instruction after the block ends
109109
self.instr_ptr = break_to.end_instr_ptr + 1;
110-
value_stack.trim(break_to.stack_ptr);
110+
value_stack.truncate(break_to.stack_ptr);
111111

112112
// we also want to trim the label stack, including the block
113113
self.labels.trim(self.labels.len() - break_to_relative as usize + 1);
114-
panic!()
115114
}
116115
_ => unimplemented!("break to block type: {:?}", current_label.ty),
117116
}

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

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
use crate::{runtime::RawWasmValue, Error, Result};
1+
use core::ops::Range;
2+
3+
use crate::{runtime::RawWasmValue, Error, ModuleInstance, Result};
24
use alloc::vec::Vec;
5+
use log::info;
36
use tinywasm_types::BlockArgs;
47

58
// minimum stack size
@@ -23,26 +26,36 @@ impl Default for ValueStack {
2326
}
2427

2528
impl ValueStack {
29+
#[cfg(test)]
30+
pub(crate) fn data(&self) -> &[RawWasmValue] {
31+
&self.stack
32+
}
33+
2634
#[inline]
2735
pub(crate) fn len(&self) -> usize {
2836
assert!(self.top <= self.stack.len());
2937
self.top
3038
}
3139

3240
#[inline]
33-
pub(crate) fn trim(&mut self, n: usize) {
41+
pub(crate) fn truncate(&mut self, n: usize) {
3442
assert!(self.top <= self.stack.len());
3543
self.top -= n;
3644
self.stack.truncate(self.top);
3745
}
3846

3947
#[inline]
40-
pub(crate) fn push_block_args(&self, args: BlockArgs) -> Result<()> {
41-
match args {
42-
BlockArgs::Empty => Ok(()),
43-
BlockArgs::Type(_t) => todo!("support block args (type)"),
44-
BlockArgs::FuncType(_t) => todo!("support block args (func type)"),
48+
// example: [1, 2, 3] n=1, end_keep=1 => [1, 3]
49+
// example: [1] n=1, end_keep=1 => [1]
50+
pub(crate) fn truncate_keep(&mut self, n: usize, end_keep: usize) {
51+
if n == end_keep || n == 0 {
52+
return;
4553
}
54+
55+
assert!(self.top <= self.stack.len());
56+
info!("removing from {} to {}", self.top - n, self.top - end_keep);
57+
self.stack.drain(self.top - n..self.top - end_keep);
58+
self.top -= n - end_keep;
4659
}
4760

4861
#[inline]
@@ -98,3 +111,56 @@ impl ValueStack {
98111
Ok(res)
99112
}
100113
}
114+
115+
#[cfg(test)]
116+
mod tests {
117+
use super::*;
118+
use crate::std::panic;
119+
120+
fn crate_stack<T: Into<RawWasmValue> + Copy>(data: &[T]) -> ValueStack {
121+
let mut stack = ValueStack::default();
122+
stack.extend(data.iter().map(|v| (*v).into()));
123+
stack
124+
}
125+
126+
fn assert_truncate_keep<T: Into<RawWasmValue> + Copy>(data: &[T], n: usize, end_keep: usize, expected: &[T]) {
127+
let mut stack = crate_stack(data);
128+
stack.truncate_keep(n, end_keep);
129+
assert_eq!(
130+
stack.data(),
131+
expected.iter().map(|v| (*v).into()).collect::<Vec<_>>().as_slice()
132+
);
133+
}
134+
135+
fn catch_unwind_silent<F: FnOnce() -> R + panic::UnwindSafe, R>(f: F) -> crate::std::thread::Result<R> {
136+
let prev_hook = panic::take_hook();
137+
panic::set_hook(alloc::boxed::Box::new(|_| {}));
138+
let result = panic::catch_unwind(f);
139+
panic::set_hook(prev_hook);
140+
result
141+
}
142+
143+
#[test]
144+
fn test_truncate_keep() {
145+
assert_truncate_keep(&[1, 2, 3], 1, 1, &[1, 2, 3]);
146+
assert_truncate_keep(&[1], 1, 1, &[1]);
147+
assert_truncate_keep(&[1, 2, 3], 2, 1, &[1, 3]);
148+
assert_truncate_keep::<i32>(&[], 0, 0, &[]);
149+
catch_unwind_silent(|| assert_truncate_keep(&[1, 2, 3], 4, 1, &[1, 3])).expect_err("should panic");
150+
}
151+
152+
#[test]
153+
fn test_value_stack() {
154+
let mut stack = ValueStack::default();
155+
stack.push(1.into());
156+
stack.push(2.into());
157+
stack.push(3.into());
158+
assert_eq!(stack.len(), 3);
159+
assert_eq!(stack.pop_t::<i32>().unwrap(), 3);
160+
assert_eq!(stack.len(), 2);
161+
assert_eq!(stack.pop_t::<i32>().unwrap(), 2);
162+
assert_eq!(stack.len(), 1);
163+
assert_eq!(stack.pop_t::<i32>().unwrap(), 1);
164+
assert_eq!(stack.len(), 0);
165+
}
166+
}

0 commit comments

Comments
 (0)