diff --git a/crates/interpreter/src/exec.rs b/crates/interpreter/src/exec.rs index eaac31b3..ddf41b50 100644 --- a/crates/interpreter/src/exec.rs +++ b/crates/interpreter/src/exec.rs @@ -762,19 +762,24 @@ impl<'m> Thread<'m> { use Instr::*; let inst_id = self.frame().inst_id; let inst = &mut store.insts[inst_id]; + let side_table = self.frame().side_table; + let val_cnt = + if !side_table.is_empty() { Some(side_table[0].view().val_cnt) } else { None }; + let pop_cnt = + if !side_table.is_empty() { Some(side_table[0].view().pop_cnt) } else { None }; match self.parser.parse_instr().into_ok() { Unreachable => return Err(trap()), Nop => (), - Block(b) => self.push_label(self.blocktype(inst, &b), LabelKind::Block), - Loop(b) => self.push_label(self.blocktype(inst, &b), LabelKind::Loop), + Block(b) => self.push_label(self.blocktype(inst, &b), LabelKind::Block, val_cnt), + Loop(b) => self.push_label(self.blocktype(inst, &b), LabelKind::Loop, val_cnt), If(b) => match self.pop_value().unwrap_i32() { 0 => { self.take_jump(0); - self.push_label(self.blocktype(inst, &b), LabelKind::Block); + self.push_label(self.blocktype(inst, &b), LabelKind::Block, val_cnt); } _ => { self.frame().skip_jump(); - self.push_label(self.blocktype(inst, &b), LabelKind::If); + self.push_label(self.blocktype(inst, &b), LabelKind::If, val_cnt); } }, Else => { @@ -782,10 +787,10 @@ impl<'m> Thread<'m> { return Ok(self.exit_label()); } End => return Ok(self.exit_label()), - Br(l) => return Ok(self.pop_label(l, 0)), + Br(l) => return Ok(self.pop_label(l, 0, pop_cnt)), BrIf(l) => { if self.pop_value().unwrap_i32() != 0 { - return Ok(self.pop_label(l, 0)); + return Ok(self.pop_label(l, 0, pop_cnt)); } self.frame().skip_jump(); } @@ -793,8 +798,11 @@ impl<'m> Thread<'m> { // In validation for BrTable, the side table entry for the last label index is // created at first. let i = self.pop_value().unwrap_i32() as usize; - return Ok(self - .pop_label(ls.get(i).cloned().unwrap_or(ln), ls.get(i).map_or(0, |_| i + 1))); + return Ok(self.pop_label( + ls.get(i).cloned().unwrap_or(ln), + ls.get(i).map_or(0, |_| i + 1), + pop_cnt, + )); } Return => return Ok(self.exit_frame()), Call(x) => return self.invoke(store, store.func_ptr(inst_id, x)), @@ -1036,24 +1044,47 @@ impl<'m> Thread<'m> { self.values().split_off(len) } - fn push_label(&mut self, type_: FuncType<'m>, kind: LabelKind) { + fn push_label(&mut self, type_: FuncType<'m>, kind: LabelKind, val_cnt: Option) { let arity = match kind { LabelKind::Block | LabelKind::If => type_.results.len(), LabelKind::Loop => type_.params.len(), }; - let label = Label { arity, values_cnt: type_.params.len() }; + match kind { + LabelKind::If => { + if val_cnt.is_some() { + debug_assert_eq!(arity as u32, val_cnt.unwrap()) + } + } + LabelKind::Loop => { + // There is no side table entry for a loop that is only executed once. + if val_cnt.is_some() && !type_.params.is_empty() { + debug_assert_eq!(arity as u32, val_cnt.unwrap()) + } + } + _ => {} + } + let label = Label { arity, values_cnt: type_.params.len(), kind }; self.label().values_cnt -= label.values_cnt; self.labels().push(label); } - fn pop_label(mut self, l: LabelIdx, offset: usize) -> ThreadResult<'m> { + fn pop_label(mut self, l: LabelIdx, offset: usize, pop_cnt: Option) -> ThreadResult<'m> { let i = self.labels().len() - l as usize - 1; if i == 0 { return self.exit_frame(); } let frame = self.frame(); let values_cnt: usize = frame.labels[i ..].iter().map(|label| label.values_cnt).sum(); - let Label { arity, .. } = frame.labels.drain(i ..).next().unwrap(); + + let Label { arity, kind, .. } = frame.labels.drain(i ..).next().unwrap(); + match kind { + LabelKind::Block => {} + _ => { + if pop_cnt.is_some() { + debug_assert_eq!(values_cnt as u32 - arity as u32, pop_cnt.unwrap()); + } + } + } let values_len = self.values().len(); self.values().drain(values_len - values_cnt .. values_len - arity); self.label().values_cnt += arity; @@ -1419,7 +1450,7 @@ impl<'m> Frame<'m> { inst_id: usize, arity: usize, ret: &'m [u8], locals: Vec, side_table: &'m [SideTableEntry], ) -> Self { - let label = Label { arity, values_cnt: 0 }; + let label = Label { arity, values_cnt: 0, kind: LabelKind::Block }; Frame { inst_id, arity, ret, locals, labels: vec![label], side_table } } @@ -1439,6 +1470,7 @@ impl<'m> Frame<'m> { struct Label { arity: usize, values_cnt: usize, + kind: LabelKind, } #[derive(Debug)]