Skip to content

Commit 8c4701f

Browse files
committed
properly reset last_instr when crossing control frame boundaries
1 parent 73aecbf commit 8c4701f

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

crates/wasmi/src/engine/translator/func2/instrs.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,20 @@ impl InstrEncoder {
254254
&mut self.instrs[instr.into_usize()]
255255
}
256256

257+
/// Resets the [`Instr`] last created via [`InstrEncoder::push_instr`].
258+
///
259+
/// # Note
260+
///
261+
/// The `last_instr` info is used for op-code fusion of `local.set`
262+
/// `local.tee`, compare, conditional branch and `select` instructions.
263+
///
264+
/// Whenever ending a control frame during Wasm translation `last_instr`
265+
/// needs to be reset to `None` to signal that no such optimization is
266+
/// valid across control flow boundaries.
267+
pub fn reset_last_instr(&mut self) {
268+
self.last_instr = None;
269+
}
270+
257271
/// Updates the branch offset of `instr` to `offset`.
258272
///
259273
/// # Errors

crates/wasmi/src/engine/translator/func2/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,13 +949,19 @@ impl FuncTranslator {
949949
if self.reachable && self.stack.is_control_empty() {
950950
self.encode_return(consume_fuel_instr)?;
951951
}
952+
if frame.is_branched_to() {
953+
// No need to reset `last_instr` if there was no branch to the end of a Wasm `block`.
954+
self.instrs.reset_last_instr();
955+
}
952956
Ok(())
953957
}
954958

955959
/// Translates the end of a Wasm `loop` control frame.
956960
fn translate_end_loop(&mut self, _frame: LoopControlFrame) -> Result<(), Error> {
957961
debug_assert!(!self.stack.is_control_empty());
958962
// Nothing needs to be done since Wasm `loop` control frames always only have a single exit.
963+
//
964+
// Note: no need to reset `last_instr` since end of `loop` is not a control flow boundary.
959965
Ok(())
960966
}
961967

@@ -1003,6 +1009,8 @@ impl FuncTranslator {
10031009
.pin_label(frame.label(), self.instrs.next_instr())
10041010
.unwrap();
10051011
self.reachable = true;
1012+
// Need to reset `last_instr` since end of `if` is a control flow boundary.
1013+
self.instrs.reset_last_instr();
10061014
Ok(())
10071015
}
10081016

@@ -1035,6 +1043,8 @@ impl FuncTranslator {
10351043
.pin_label(frame.label(), self.instrs.next_instr())
10361044
.unwrap();
10371045
self.reachable = reachable;
1046+
// Need to reset `last_instr` since end of `else` is a control flow boundary.
1047+
self.instrs.reset_last_instr();
10381048
Ok(())
10391049
}
10401050

@@ -1055,12 +1065,19 @@ impl FuncTranslator {
10551065
.pin_label(frame.label(), self.instrs.next_instr())
10561066
.unwrap();
10571067
self.reachable = end_is_reachable || frame.is_branched_to();
1068+
if frame.is_branched_to() {
1069+
// No need to reset `last_instr` if there was no branch to the
1070+
// end of a Wasm `if` where only `then` or `else` is reachable.
1071+
self.instrs.reset_last_instr();
1072+
}
10581073
Ok(())
10591074
}
10601075

10611076
/// Translates the end of an unreachable Wasm control frame.
10621077
fn translate_end_unreachable(&mut self, _frame: ControlFrameKind) -> Result<(), Error> {
10631078
debug_assert!(!self.stack.is_control_empty());
1079+
// We reset `last_instr` out of caution in case there is a control flow boundary.
1080+
self.instrs.reset_last_instr();
10641081
Ok(())
10651082
}
10661083

crates/wasmi/src/engine/translator/func2/visit.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator {
117117
let consume_fuel = self.instrs.push_consume_fuel_instr()?;
118118
self.stack
119119
.push_loop(block_ty, continue_label, consume_fuel)?;
120+
// Need to reset `last_instr` because a loop header is a control flow boundary.
121+
self.instrs.reset_last_instr();
120122
Ok(())
121123
}
122124

0 commit comments

Comments
 (0)