Skip to content

Commit

Permalink
Return the correct value during a labelled break
Browse files Browse the repository at this point in the history
  • Loading branch information
raskad committed Jun 6, 2023
1 parent 9a903fb commit 711534d
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 23 deletions.
22 changes: 12 additions & 10 deletions boa_engine/src/bytecompiler/statement/break.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ use boa_interner::Sym;
impl ByteCompiler<'_, '_> {
/// Compile a [`Break`] `boa_ast` node
pub(crate) fn compile_break(&mut self, node: Break) {
let opcode = if node.label().is_some() {
Opcode::BreakLabel
} else {
Opcode::Break
};

if let Some(info) = self.jump_info.last().filter(|info| info.is_try_block()) {
let in_finally = info.in_finally();
let in_catch_no_finally = info.in_catch() && !info.has_finally();
Expand All @@ -20,8 +26,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::CatchEnd2);
}

let (break_label, target_jump_label) =
self.emit_opcode_with_two_operands(Opcode::Break);
let (break_label, target_jump_label) = self.emit_opcode_with_two_operands(opcode);

if let Some(node_label) = node.label() {
self.search_jump_info_label(target_jump_label, node_label);
Expand All @@ -48,15 +53,12 @@ impl ByteCompiler<'_, '_> {
}

// Emit the break opcode -> (Label, Label)
let (break_label, target_label) = self.emit_opcode_with_two_operands(Opcode::Break);
if node.label().is_some() {
self.search_jump_info_label(
break_label,
node.label().expect("must exist in this block"),
);
self.search_jump_info_label(target_label, node.label().expect("must exist"));
let (break_label, target_label) = self.emit_opcode_with_two_operands(opcode);
if let Some(label) = node.label() {
self.search_jump_info_label(break_label, label);
self.search_jump_info_label(target_label, label);
return;
};
}

let info = self
.jump_info
Expand Down
4 changes: 2 additions & 2 deletions boa_engine/src/vm/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ impl CodeBlock {
}
Opcode::CopyDataProperties
| Opcode::Break
| Opcode::BreakLabel
| Opcode::Continue
| Opcode::LoopStart
| Opcode::IteratorLoopStart
Expand Down Expand Up @@ -616,8 +617,7 @@ impl CodeBlock {
| Opcode::Reserved49
| Opcode::Reserved50
| Opcode::Reserved51
| Opcode::Reserved52
| Opcode::Reserved53 => unreachable!("Reserved opcodes are unrechable"),
| Opcode::Reserved52 => unreachable!("Reserved opcodes are unrechable"),
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions boa_engine/src/vm/flowgraph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl CodeBlock {
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::Red);
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line);
}
Opcode::Break => {
Opcode::Break | Opcode::BreakLabel => {
let jump_operand = self.read::<u32>(pc);
pc += size_of::<u32>();
let target_operand = self.read::<u32>(pc);
Expand Down Expand Up @@ -709,8 +709,7 @@ impl CodeBlock {
| Opcode::Reserved49
| Opcode::Reserved50
| Opcode::Reserved51
| Opcode::Reserved52
| Opcode::Reserved53 => unreachable!("Reserved opcodes are unrechable"),
| Opcode::Reserved52 => unreachable!("Reserved opcodes are unrechable"),
}
}

Expand Down
53 changes: 47 additions & 6 deletions boa_engine/src/vm/opcode/control_flow/break.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,61 @@ impl Operation for Break {
continue;
}

if (jump_address == env_entry.exit_address())
if jump_address == env_entry.exit_address()
|| (env_entry.is_finally_env() && jump_address == env_entry.start_address())
{
found_target = true;
set_loop_result = env_entry.set_loop_return_value(value.clone());
continue;
}

// Checks for the break if we have jumped from inside of a finally block
if jump_address == env_entry.exit_address() {
found_target = true;
set_loop_result = env_entry.set_loop_return_value(value.clone());
continue;
envs_to_pop += env_entry.env_num();
context.vm.frame_mut().env_stack.pop();
}

let env_truncation_len = context.vm.environments.len().saturating_sub(envs_to_pop);
context.vm.environments.truncate(env_truncation_len);

// 2. Register target address in AbruptCompletionRecord.
let new_record = AbruptCompletionRecord::new_break().with_initial_target(target_address);
context.vm.frame_mut().abrupt_completion = Some(new_record);

// 3. Set program counter and finally return fields.
context.vm.frame_mut().pc = jump_address;
Ok(CompletionType::Normal)
}
}

/// `BreakLabel` implements the Opcode Operation for `Opcode::BreakLabel`
///
/// Operation:
/// - Pop required environments and jump to address.
pub(crate) struct BreakLabel;

impl Operation for BreakLabel {
const NAME: &'static str = "BreakLabel";
const INSTRUCTION: &'static str = "INST - BreakLabel";

fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let jump_address = context.vm.read::<u32>();
let target_address = context.vm.read::<u32>();

let value = context.vm.stack.pop().unwrap_or(JsValue::undefined());
context.vm.push(value);

// 1. Iterate through Env stack looking for exit address.
let mut envs_to_pop = 0;
for i in (0..context.vm.frame().env_stack.len()).rev() {
let Some(env_entry) = context.vm.frame_mut().env_stack.get_mut(i) else {
break;
};

if jump_address == env_entry.exit_address()
|| (env_entry.is_finally_env() && jump_address == env_entry.start_address())
{
break;
}

envs_to_pop += env_entry.env_num();
context.vm.frame_mut().env_stack.pop();
}
Expand Down
9 changes: 7 additions & 2 deletions boa_engine/src/vm/opcode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,13 @@ generate_impl! {
/// Stack: loop_return_value **=>**
Break,

/// Jumps to a label target location and pops the environments involved.
///
/// Operands: Jump Address: u32, Target address: u32
///
/// Stack: **=>**
BreakLabel,

/// Sets the `AbruptCompletionRecord` for a delayed continue
///
/// Operands: Jump Address: u32, Target address: u32,
Expand Down Expand Up @@ -1809,8 +1816,6 @@ generate_impl! {
Reserved51 => Reserved,
/// Reserved [`Opcode`].
Reserved52 => Reserved,
/// Reserved [`Opcode`].
Reserved53 => Reserved,
}
}

Expand Down

0 comments on commit 711534d

Please sign in to comment.