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

Commit aac8cab

Browse files
feat: finish if/else
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 40e5dcf commit aac8cab

File tree

6 files changed

+59
-58
lines changed

6 files changed

+59
-58
lines changed

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

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ use core::ops::{BitAnd, BitOr, BitXor, Neg};
22

33
use super::{DefaultRuntime, Stack};
44
use crate::{
5-
get_label_args,
65
log::debug,
76
runtime::{BlockType, LabelFrame},
8-
CallFrame, Error, ModuleInstance, Result, Store,
7+
CallFrame, Error, LabelArgs, ModuleInstance, Result, Store,
98
};
109
use alloc::vec::Vec;
1110
use log::info;
@@ -132,45 +131,51 @@ fn exec_one(
132131
}
133132

134133
If(args, else_offset, end_offset) => {
135-
let end_instr_ptr = cf.instr_ptr + *end_offset;
136-
137-
info!(
138-
"if it's true, we'll jump to the next instruction (@{})",
139-
cf.instr_ptr + 1
140-
);
141-
142-
if let Some(else_offset) = else_offset {
143-
info!(
144-
"else: {:?} (@{})",
145-
instrs[cf.instr_ptr + else_offset],
146-
cf.instr_ptr + else_offset
147-
);
148-
};
149-
150-
info!("end: {:?} (@{})", instrs[end_instr_ptr], end_instr_ptr);
151-
152-
if stack.values.pop_t::<i32>()? != 0 {
134+
if stack.values.pop_t::<i32>()? == 0 {
135+
if let Some(else_offset) = else_offset {
136+
log::info!("entering else at {}", cf.instr_ptr + *else_offset);
137+
cf.enter_label(
138+
LabelFrame {
139+
instr_ptr: cf.instr_ptr + *else_offset,
140+
end_instr_ptr: cf.instr_ptr + *end_offset,
141+
stack_ptr: stack.values.len(), // - params,
142+
args: crate::LabelArgs::new(*args, module)?,
143+
ty: BlockType::Else,
144+
},
145+
&mut stack.values,
146+
);
147+
cf.instr_ptr += *else_offset;
148+
} else {
149+
log::info!("skipping if");
150+
cf.instr_ptr += *end_offset
151+
}
152+
} else {
153+
log::info!("entering then");
153154
cf.enter_label(
154155
LabelFrame {
155156
instr_ptr: cf.instr_ptr,
156157
end_instr_ptr: cf.instr_ptr + *end_offset,
157158
stack_ptr: stack.values.len(), // - params,
158-
args: get_label_args(*args, module)?,
159+
args: LabelArgs::new(*args, module)?,
159160
ty: BlockType::If,
160161
},
161162
&mut stack.values,
162163
)
163164
}
164165
}
165166

167+
// Else(_end_offset) => {
168+
// // end the if block
169+
// cf.break_to(0, &mut stack.values)?;
170+
// }
166171
Loop(args, end_offset) => {
167172
// let params = stack.values.pop_block_params(*args, &module)?;
168173
cf.enter_label(
169174
LabelFrame {
170175
instr_ptr: cf.instr_ptr,
171176
end_instr_ptr: cf.instr_ptr + *end_offset,
172177
stack_ptr: stack.values.len(), // - params,
173-
args: get_label_args(*args, module)?,
178+
args: LabelArgs::new(*args, module)?,
174179
ty: BlockType::Loop,
175180
},
176181
&mut stack.values,
@@ -183,7 +188,7 @@ fn exec_one(
183188
instr_ptr: cf.instr_ptr,
184189
end_instr_ptr: cf.instr_ptr + *end_offset,
185190
stack_ptr: stack.values.len(), //- params,
186-
args: get_label_args(*args, module)?,
191+
args: LabelArgs::new(*args, module)?,
187192
ty: BlockType::Block,
188193
},
189194
&mut stack.values,
@@ -210,7 +215,7 @@ fn exec_one(
210215
BrIf(v) => {
211216
if stack.values.pop_t::<i32>()? > 0 {
212217
cf.break_to(*v, &mut stack.values)?
213-
};
218+
}
214219
}
215220

216221
Return => match stack.call_stack.is_empty() {
@@ -235,21 +240,22 @@ fn exec_one(
235240
}
236241
}
237242

238-
EndBlockFrame => {
239-
let blocks = &mut cf.labels;
240-
241-
// remove the label from the label stack
242-
let Some(block) = blocks.pop() else {
243-
panic!("end: no label to end, this should have been validated by the parser");
243+
Else(end_offset) => {
244+
let Some(block) = cf.labels.pop() else {
245+
panic!("else: no label to end, this should have been validated by the parser");
244246
};
245247

246248
let res_count = block.args.results;
247-
info!("we want to keep {} values on the stack", res_count);
248-
info!("current block stack ptr: {}", block.stack_ptr);
249-
info!("stack: {:?}", stack.values);
249+
stack.values.truncate_keep(block.stack_ptr, res_count);
250+
cf.instr_ptr += *end_offset;
251+
}
250252

251-
// trim the lable's stack from the stack
252-
stack.values.truncate_keep(block.stack_ptr, res_count)
253+
EndBlockFrame => {
254+
// remove the label from the label stack
255+
let Some(block) = cf.labels.pop() else {
256+
panic!("end: no label to end, this should have been validated by the parser");
257+
};
258+
stack.values.truncate_keep(block.stack_ptr, block.args.results)
253259
}
254260

255261
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::{get_label_args, BlockType, LabelFrame};
6+
pub(crate) use blocks::{BlockType, LabelArgs, LabelFrame};
77
pub(crate) use call_stack::CallFrame;
88

99
/// A WebAssembly Stack

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ impl Labels {
1717
self.0.push(block);
1818
}
1919

20-
#[inline]
21-
pub(crate) fn top(&self) -> Option<&LabelFrame> {
22-
self.0.last()
23-
}
24-
2520
#[inline]
2621
/// get the block at the given index, where 0 is the top of the stack
2722
pub(crate) fn get_relative_to_top(&self, index: usize) -> Option<&LabelFrame> {
@@ -64,19 +59,21 @@ pub(crate) enum BlockType {
6459
Block,
6560
}
6661

67-
#[derive(Debug, Clone)]
62+
#[derive(Debug, Clone, Default)]
6863
pub(crate) struct LabelArgs {
6964
pub(crate) params: usize,
7065
pub(crate) results: usize,
7166
}
7267

73-
pub(crate) fn get_label_args(args: BlockArgs, module: &ModuleInstance) -> Result<LabelArgs> {
74-
Ok(match args {
75-
BlockArgs::Empty => LabelArgs { params: 0, results: 0 },
76-
BlockArgs::Type(_) => LabelArgs { params: 0, results: 1 },
77-
BlockArgs::FuncType(t) => LabelArgs {
78-
params: module.func_ty(t).params.len(),
79-
results: module.func_ty(t).results.len(),
80-
},
81-
})
68+
impl LabelArgs {
69+
pub(crate) fn new(args: BlockArgs, module: &ModuleInstance) -> Result<Self> {
70+
Ok(match args {
71+
BlockArgs::Empty => LabelArgs { params: 0, results: 0 },
72+
BlockArgs::Type(_) => LabelArgs { params: 0, results: 1 },
73+
BlockArgs::FuncType(t) => LabelArgs {
74+
params: module.func_ty(t).params.len(),
75+
results: module.func_ty(t).results.len(),
76+
},
77+
})
78+
}
8279
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ impl CallFrame {
9191
/// Break to a block at the given index (relative to the current frame)
9292
#[inline]
9393
pub(crate) fn break_to(&mut self, break_to_relative: u32, value_stack: &mut super::ValueStack) -> Result<()> {
94-
let current_label = self.labels.top().ok_or(Error::LabelStackUnderflow)?;
9594
let break_to = self
9695
.labels
9796
.get_relative_to_top(break_to_relative as usize)
@@ -109,15 +108,14 @@ impl CallFrame {
109108
// we also want to trim the label stack to the loop (but not including the loop)
110109
self.labels.truncate(self.labels.len() - break_to_relative as usize);
111110
}
112-
BlockType::Block => {
111+
BlockType::Block | BlockType::If | BlockType::Else => {
113112
// this is a block, so we want to jump to the next instruction after the block ends (the inst_ptr will be incremented by 1 before the next instruction is executed)
114113
self.instr_ptr = break_to.end_instr_ptr;
115114

116115
// we also want to trim the label stack, including the block
117116
self.labels
118117
.truncate(self.labels.len() - (break_to_relative as usize + 1));
119118
}
120-
_ => unimplemented!("break to block type: {:?}", current_label.ty),
121119
}
122120

123121
// self.instr_ptr = block_frame.instr_ptr;

0 commit comments

Comments
 (0)