Skip to content

Commit 1b08814

Browse files
chore: remove block stack
Signed-off-by: Henry <mail@henrygressmann.de>
1 parent 1ff5945 commit 1b08814

File tree

21 files changed

+559
-452
lines changed

21 files changed

+559
-452
lines changed

.cargo/config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ test-wasm-1="test --package tinywasm --test test-wasm-1 --release"
44
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"
7+
test-wasm-custom="test --package tinywasm --test test-wasm-custom --release"

.vscode/settings.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

crates/parser/src/visit.rs

Lines changed: 339 additions & 86 deletions
Large diffs are not rendered by default.

crates/tinywasm/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ harness=false
7272
name="test-wasm-custom-page-sizes"
7373
harness=false
7474

75+
[[test]]
76+
name="test-wasm-custom"
77+
harness=false
78+
7579
[[test]]
7680
name="test-wasm-tail-call"
7781
harness=false

crates/tinywasm/benches/argon2id.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ use types::TinyWasmModule;
55

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

8+
fn init_log() {
9+
let _ = pretty_env_logger::formatted_timed_builder().filter_level(log::LevelFilter::Off).try_init();
10+
}
11+
812
fn argon2id_parse() -> Result<TinyWasmModule> {
913
let parser = tinywasm_parser::Parser::new();
1014
let data = parser.parse_module_bytes(WASM)?;
@@ -30,6 +34,7 @@ fn argon2id_run(module: TinyWasmModule) -> Result<()> {
3034
}
3135

3236
fn criterion_benchmark(c: &mut Criterion) {
37+
init_log();
3338
let module = argon2id_parse().expect("argon2id_parse");
3439
let twasm = argon2id_to_twasm(&module).expect("argon2id_to_twasm");
3540

crates/tinywasm/benches/tinywasm.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ fn criterion_benchmark(c: &mut Criterion) {
3535
let module = tinywasm_parse().expect("tinywasm_parse");
3636
let twasm = tinywasm_to_twasm(&module).expect("tinywasm_to_twasm");
3737

38-
c.bench_function("tinywasm_parse", |b| b.iter(tinywasm_parse));
39-
c.bench_function("tinywasm_to_twasm", |b| b.iter(|| tinywasm_to_twasm(&module)));
40-
c.bench_function("tinywasm_from_twasm", |b| b.iter(|| tinywasm_from_twasm(&twasm)));
38+
// c.bench_function("tinywasm_parse", |b| b.iter(tinywasm_parse));
39+
// c.bench_function("tinywasm_to_twasm", |b| b.iter(|| tinywasm_to_twasm(&module)));
40+
// c.bench_function("tinywasm_from_twasm", |b| b.iter(|| tinywasm_from_twasm(&twasm)));
4141
c.bench_function("tinywasm", |b| b.iter(|| tinywasm_run(module.clone())));
4242
}
4343

crates/tinywasm/src/engine.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ pub const DEFAULT_VALUE_STACK_128_SIZE: usize = 4 * 1024; // 4k slots
5151
/// Default initial size for the reference value stack (funcref, externref values).
5252
pub const DEFAULT_VALUE_STACK_REF_SIZE: usize = 4 * 1024; // 4k slots
5353

54-
/// Default initial size for the block stack (control frames).
55-
pub const DEFAULT_BLOCK_STACK_SIZE: usize = 2048; // 1024 frames
56-
5754
/// Default initial size for the call stack (function frames).
5855
pub const DEFAULT_CALL_STACK_SIZE: usize = 2048; // 1024 frames
5956

@@ -71,9 +68,6 @@ pub struct Config {
7168
pub stack_ref_size: usize,
7269
/// Initial size of the call stack.
7370
pub call_stack_size: usize,
74-
75-
/// Initial size of the block stack.
76-
pub block_stack_initial_size: usize,
7771
}
7872

7973
impl Config {
@@ -91,7 +85,6 @@ impl Default for Config {
9185
stack_128_size: DEFAULT_VALUE_STACK_128_SIZE,
9286
stack_ref_size: DEFAULT_VALUE_STACK_REF_SIZE,
9387
call_stack_size: DEFAULT_CALL_STACK_SIZE,
94-
block_stack_initial_size: DEFAULT_BLOCK_STACK_SIZE,
9588
}
9689
}
9790
}

crates/tinywasm/src/error.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@ pub enum Trap {
121121
/// Call stack overflow
122122
CallStackOverflow,
123123

124-
/// Block stack overflow
125-
BlockStackOverflow,
126-
127124
/// Value stack overflow
128125
ValueStackOverflow,
129126

@@ -159,7 +156,6 @@ impl Trap {
159156
Self::InvalidConversionToInt => "invalid conversion to integer",
160157
Self::IntegerOverflow => "integer overflow",
161158
Self::CallStackOverflow => "call stack exhausted",
162-
Self::BlockStackOverflow => "block stack exhausted",
163159
Self::ValueStackOverflow => "value stack exhausted",
164160
Self::UndefinedElement { .. } => "undefined element",
165161
Self::UninitializedElement { .. } => "uninitialized element",
@@ -243,7 +239,6 @@ impl Display for Trap {
243239
Self::InvalidConversionToInt => write!(f, "invalid conversion to integer"),
244240
Self::IntegerOverflow => write!(f, "integer overflow"),
245241
Self::CallStackOverflow => write!(f, "call stack exhausted"),
246-
Self::BlockStackOverflow => write!(f, "block stack exhausted"),
247242
Self::ValueStackOverflow => write!(f, "value stack exhausted"),
248243
Self::UndefinedElement { index } => write!(f, "undefined element: index={index}"),
249244
Self::UninitializedElement { index } => {

crates/tinywasm/src/func.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl FuncHandle {
5656
};
5757

5858
// 6. Let f be the dummy frame
59-
let callframe = CallFrame::new_with_params(wasm_func.locals, self.addr, func_inst.owner, params, 0);
59+
let callframe = CallFrame::new_with_params(wasm_func.locals, self.addr, func_inst.owner, params);
6060

6161
// 7. Push the frame f to the call stack
6262
// & 8. Push the values to the stack

crates/tinywasm/src/interpreter/executor.rs

Lines changed: 68 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use interpreter::stack::CallFrame;
1010
use tinywasm_types::*;
1111

1212
use super::num_helpers::*;
13-
use super::stack::{BlockFrame, BlockType};
1413
use super::values::*;
1514
use crate::instance::ModuleInstanceInner;
1615
use crate::interpreter::Value128;
@@ -88,7 +87,7 @@ impl<'store> Executor<'store> {
8887

8988
#[rustfmt::skip]
9089
match next {
91-
Nop | BrLabel(_) | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
90+
Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
9291
Unreachable => return ControlFlow::Break(Some(Trap::Unreachable.into())),
9392
Drop32 => self.store.stack.values.drop::<Value32>(),
9493
Drop64 => self.store.stack.values.drop::<Value64>(),
@@ -102,21 +101,70 @@ impl<'store> Executor<'store> {
102101
CallIndirect(ty, table) => return self.exec_call_indirect::<false>(*ty, *table),
103102
ReturnCall(v) => return self.exec_call_direct::<true>(*v),
104103
ReturnCallIndirect(ty, table) => return self.exec_call_indirect::<true>(*ty, *table),
105-
If(end, el) => self.exec_if(*end, *el, (StackHeight::default(), StackHeight::default())),
106-
IfWithType(ty, end, el) => self.exec_if(*end, *el, (StackHeight::default(), (*ty).into())),
107-
IfWithFuncType(ty, end, el) => self.exec_if(*end, *el, self.resolve_functype(*ty)),
108-
Else(end_offset) => self.exec_else(*end_offset),
109-
Loop(end) => self.enter_block(*end, BlockType::Loop, (StackHeight::default(), StackHeight::default())),
110-
LoopWithType(ty, end) => self.enter_block(*end, BlockType::Loop, (StackHeight::default(), (*ty).into())),
111-
LoopWithFuncType(ty, end) => self.enter_block(*end, BlockType::Loop, self.resolve_functype(*ty)),
112-
Block(end) => self.enter_block(*end, BlockType::Block, (StackHeight::default(), StackHeight::default())),
113-
BlockWithType(ty, end) => self.enter_block(*end, BlockType::Block, (StackHeight::default(), (*ty).into())),
114-
BlockWithFuncType(ty, end) => self.enter_block(*end, BlockType::Block, self.resolve_functype(*ty)),
115-
Br(v) => return self.exec_br(*v),
116-
BrIf(v) => return self.exec_br_if(*v),
117-
BrTable(default, len) => return self.exec_brtable(*default, *len),
104+
Jump(ip) => {
105+
self.cf.instr_ptr = *ip as usize;
106+
return ControlFlow::Continue(());
107+
}
108+
JumpIfZero(ip) => {
109+
let cond = self.store.stack.values.pop::<i32>();
110+
111+
if cond == 0 {
112+
self.cf.instr_ptr = *ip as usize;
113+
} else {
114+
self.cf.incr_instr_ptr();
115+
}
116+
return ControlFlow::Continue(());
117+
}
118+
DropKeepSmall { base32, keep32, base64, keep64, base128, keep128, base_ref, keep_ref } => {
119+
let b32 = self.cf.stack_base.s32 as usize + *base32 as usize;
120+
let k32 = *keep32 as usize;
121+
self.store.stack.values.stack_32.truncate_keep(b32, k32);
122+
let b64 = self.cf.stack_base.s64 as usize + *base64 as usize;
123+
let k64 = *keep64 as usize;
124+
self.store.stack.values.stack_64.truncate_keep(b64, k64);
125+
let b128 = self.cf.stack_base.s128 as usize + *base128 as usize;
126+
let k128 = *keep128 as usize;
127+
self.store.stack.values.stack_128.truncate_keep(b128, k128);
128+
let bref = self.cf.stack_base.sref as usize + *base_ref as usize;
129+
let kref = *keep_ref as usize;
130+
self.store.stack.values.stack_ref.truncate_keep(bref, kref);
131+
}
132+
DropKeep32(base, keep) => {
133+
let b = self.cf.stack_base.s32 as usize + *base as usize;
134+
let k = *keep as usize;
135+
self.store.stack.values.stack_32.truncate_keep(b, k);
136+
}
137+
DropKeep64(base, keep) => {
138+
let b = self.cf.stack_base.s64 as usize + *base as usize;
139+
let k = *keep as usize;
140+
self.store.stack.values.stack_64.truncate_keep(b, k);
141+
}
142+
DropKeep128(base, keep) => {
143+
let b = self.cf.stack_base.s128 as usize + *base as usize;
144+
let k = *keep as usize;
145+
self.store.stack.values.stack_128.truncate_keep(b, k);
146+
}
147+
DropKeepRef(base, keep) => {
148+
let b = self.cf.stack_base.sref as usize + *base as usize;
149+
let k = *keep as usize;
150+
self.store.stack.values.stack_ref.truncate_keep(b, k);
151+
}
152+
BranchTable(default_ip, len) => {
153+
let idx = self.store.stack.values.pop::<i32>();
154+
let start = self.cf.instr_ptr + 1;
155+
156+
let target_ip = if idx >= 0 && (idx as u32) < *len {
157+
match self.instructions.0.get(start + idx as usize) {
158+
Some(Instruction::BranchTableTarget(ip)) => *ip,
159+
_ => *default_ip,
160+
}
161+
} else {
162+
*default_ip
163+
};
164+
self.cf.instr_ptr = target_ip as usize;
165+
return ControlFlow::Continue(());
166+
}
118167
Return => return self.exec_return(),
119-
EndBlockFrame => self.exec_end_block(),
120168
LocalGet32(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value32>(*local_index)).to_cf()?,
121169
LocalGet64(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value64>(*local_index)).to_cf()?,
122170
LocalGet128(local_index) => self.store.stack.values.push(self.cf.locals.get::<Value128>(*local_index)).to_cf()?,
@@ -588,10 +636,12 @@ impl<'store> Executor<'store> {
588636

589637
if IS_RETURN_CALL {
590638
let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals);
591-
self.cf.reuse_for(func_addr, locals, self.store.stack.blocks.len() as u32, owner);
639+
let stack_base = self.store.stack.values.height();
640+
self.cf.reuse_for(func_addr, locals, owner, stack_base);
592641
} else {
593642
let locals = self.store.stack.values.pop_locals(wasm_func.params, wasm_func.locals);
594-
let new_call_frame = CallFrame::new(func_addr, owner, locals, self.store.stack.blocks.len() as u32);
643+
let stack_base = self.store.stack.values.height();
644+
let new_call_frame = CallFrame::new(func_addr, owner, locals, stack_base);
595645
self.cf.incr_instr_ptr(); // skip the call instruction
596646
self.store.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame)).to_cf()?;
597647
}
@@ -661,84 +711,7 @@ impl<'store> Executor<'store> {
661711
}
662712
}
663713

664-
fn exec_if(&mut self, else_offset: u32, end_offset: u32, (params, results): (StackHeight, StackHeight)) {
665-
// truthy value is on the top of the stack, so enter the then block
666-
if self.store.stack.values.pop::<i32>() != 0 {
667-
self.enter_block(end_offset, BlockType::If, (params, results));
668-
return;
669-
}
670-
671-
// falsy value is on the top of the stack
672-
if else_offset == 0 {
673-
self.cf.jump(end_offset);
674-
return;
675-
}
676-
677-
self.cf.jump(else_offset);
678-
self.enter_block(end_offset - else_offset, BlockType::Else, (params, results));
679-
}
680-
fn exec_else(&mut self, end_offset: u32) {
681-
self.exec_end_block();
682-
self.cf.jump(end_offset);
683-
}
684-
fn resolve_functype(&self, idx: u32) -> (StackHeight, StackHeight) {
685-
let ty = self.module.func_ty(idx);
686-
((&*ty.params).into(), (&*ty.results).into())
687-
}
688-
fn enter_block(&mut self, end_instr_offset: u32, ty: BlockType, (params, results): (StackHeight, StackHeight)) {
689-
self.store.stack.blocks.push(BlockFrame {
690-
instr_ptr: self.cf.instr_ptr as u32,
691-
end_instr_offset,
692-
stack_ptr: self.store.stack.values.height(),
693-
results,
694-
params,
695-
ty,
696-
})
697-
}
698-
fn exec_br(&mut self, to: u32) -> ControlFlow<Option<Error>> {
699-
if self.cf.break_to(to, &mut self.store.stack.values, &mut self.store.stack.blocks).is_none() {
700-
return self.exec_return();
701-
}
702-
703-
self.cf.incr_instr_ptr();
704-
ControlFlow::Continue(())
705-
}
706-
fn exec_br_if(&mut self, to: u32) -> ControlFlow<Option<Error>> {
707-
if self.store.stack.values.pop::<i32>() != 0
708-
&& self.cf.break_to(to, &mut self.store.stack.values, &mut self.store.stack.blocks).is_none()
709-
{
710-
return self.exec_return();
711-
}
712-
self.cf.incr_instr_ptr();
713-
ControlFlow::Continue(())
714-
}
715-
fn exec_brtable(&mut self, default: u32, len: u32) -> ControlFlow<Option<Error>> {
716-
let start = self.cf.instr_ptr + 1;
717-
let end = start + len as usize;
718-
if end > self.func.instructions.len() {
719-
return ControlFlow::Break(Some(Error::Other(format!(
720-
"br_table out of bounds: {} >= {}",
721-
end,
722-
self.func.instructions.len()
723-
))));
724-
}
725-
726-
let idx = self.store.stack.values.pop::<i32>();
727-
let to = match self.func.instructions[start..end].get(idx as usize) {
728-
None => default,
729-
Some(Instruction::BrLabel(to)) => *to,
730-
_ => return ControlFlow::Break(Some(Error::Other("br_table out of bounds".to_string()))),
731-
};
732-
733-
if self.cf.break_to(to, &mut self.store.stack.values, &mut self.store.stack.blocks).is_none() {
734-
return self.exec_return();
735-
}
736-
737-
self.cf.incr_instr_ptr();
738-
ControlFlow::Continue(())
739-
}
740714
fn exec_return(&mut self) -> ControlFlow<Option<Error>> {
741-
let old = self.cf.block_ptr;
742715
let Some(cf) = self.store.stack.call_stack.pop() else { return ControlFlow::Break(None) };
743716

744717
if cf.func_addr != self.cf.func_addr {
@@ -750,18 +723,9 @@ impl<'store> Executor<'store> {
750723
}
751724
}
752725

753-
if old > cf.block_ptr {
754-
self.store.stack.blocks.truncate(old);
755-
}
756-
757726
self.cf = cf;
758727
ControlFlow::Continue(())
759728
}
760-
fn exec_end_block(&mut self) {
761-
let block = self.store.stack.blocks.pop();
762-
self.store.stack.values.truncate_keep(block.stack_ptr, block.results);
763-
}
764-
765729
fn exec_global_get(&mut self, global_index: u32) -> Result<()> {
766730
self.store.stack.values.push_dyn(self.store.state.get_global_val(self.module.resolve_global_addr(global_index)))
767731
}

0 commit comments

Comments
 (0)