mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 08:48:11 +00:00
LibJS: Generate unwind chains for break in Bytecode
This uses a newly added instruction `ScheduleJump` This instruction tells the finally proceeding it, that instead of jumping to it's next block it should jump to the designated block.
This commit is contained in:
parent
495ba53e46
commit
f5376cb282
9 changed files with 123 additions and 19 deletions
|
@ -262,23 +262,62 @@ CodeGenerationErrorOr<void> Generator::emit_delete_reference(JS::ASTNode const&
|
|||
return {};
|
||||
}
|
||||
|
||||
Label Generator::perform_needed_unwinds_for_labelled_break_and_return_target_block(DeprecatedFlyString const& break_label)
|
||||
void Generator::generate_break()
|
||||
{
|
||||
bool last_was_finally = false;
|
||||
// FIXME: Reduce code duplication
|
||||
for (size_t i = m_boundaries.size(); i > 0; --i) {
|
||||
auto boundary = m_boundaries[i - 1];
|
||||
using enum BlockBoundaryType;
|
||||
switch (boundary) {
|
||||
case Break:
|
||||
emit<Op::Jump>().set_targets(nearest_breakable_scope(), {});
|
||||
return;
|
||||
case Unwind:
|
||||
if (!last_was_finally)
|
||||
emit<Bytecode::Op::LeaveUnwindContext>();
|
||||
last_was_finally = false;
|
||||
break;
|
||||
case LeaveLexicalEnvironment:
|
||||
emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Lexical);
|
||||
break;
|
||||
case LeaveVariableEnvironment:
|
||||
emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Var);
|
||||
break;
|
||||
case Continue:
|
||||
break;
|
||||
case ReturnToFinally: {
|
||||
auto& block = make_block(DeprecatedString::formatted("{}.break", current_block().name()));
|
||||
emit<Op::ScheduleJump>(Label { block });
|
||||
switch_to_basic_block(block);
|
||||
last_was_finally = true;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Generator::generate_break(DeprecatedFlyString const& break_label)
|
||||
{
|
||||
size_t current_boundary = m_boundaries.size();
|
||||
for (auto& breakable_scope : m_breakable_scopes.in_reverse()) {
|
||||
bool last_was_finally = false;
|
||||
for (auto const& breakable_scope : m_breakable_scopes.in_reverse()) {
|
||||
for (; current_boundary > 0; --current_boundary) {
|
||||
auto boundary = m_boundaries[current_boundary - 1];
|
||||
// FIXME: Handle ReturnToFinally in a graceful manner
|
||||
// We need to execute the finally block, but tell it to resume
|
||||
// execution at the designated label
|
||||
if (boundary == BlockBoundaryType::Unwind) {
|
||||
emit<Bytecode::Op::LeaveUnwindContext>();
|
||||
if (!last_was_finally)
|
||||
emit<Bytecode::Op::LeaveUnwindContext>();
|
||||
last_was_finally = false;
|
||||
} else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment) {
|
||||
emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Lexical);
|
||||
} else if (boundary == BlockBoundaryType::LeaveVariableEnvironment) {
|
||||
emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Var);
|
||||
} else if (boundary == BlockBoundaryType::ReturnToFinally) {
|
||||
// FIXME: We need to enter the `finally`, while still scheduling the break to happen
|
||||
auto& block = make_block(DeprecatedString::formatted("{}.break", current_block().name()));
|
||||
emit<Op::ScheduleJump>(Label { block });
|
||||
switch_to_basic_block(block);
|
||||
last_was_finally = true;
|
||||
} else if (boundary == BlockBoundaryType::Break) {
|
||||
// Make sure we don't process this boundary twice if the current breakable scope doesn't contain the target label.
|
||||
--current_boundary;
|
||||
|
@ -286,8 +325,10 @@ Label Generator::perform_needed_unwinds_for_labelled_break_and_return_target_blo
|
|||
}
|
||||
}
|
||||
|
||||
if (breakable_scope.language_label_set.contains_slow(break_label))
|
||||
return breakable_scope.bytecode_target;
|
||||
if (breakable_scope.language_label_set.contains_slow(break_label)) {
|
||||
emit<Op::Jump>().set_targets(breakable_scope.bytecode_target, {});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We must have a breakable scope available that contains the label, as this should be enforced by the parser.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue