mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:27:35 +00:00
LibJS: Deduplicate labelled continue & break bytecode generation
Similar to the scoped continue and break, the only two differences between these functions is the scope that is scanned for a matching label, and the specific handling of a continue/break boundary.
This commit is contained in:
parent
663e4507ea
commit
a0d1ef34e2
2 changed files with 24 additions and 44 deletions
|
@ -417,16 +417,14 @@ void Generator::generate_scoped_jump(JumpType type)
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Generator::generate_break()
|
void Generator::generate_labelled_jump(JumpType type, DeprecatedFlyString const& label)
|
||||||
{
|
|
||||||
generate_scoped_jump(JumpType::Break);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Generator::generate_break(DeprecatedFlyString const& break_label)
|
|
||||||
{
|
{
|
||||||
size_t current_boundary = m_boundaries.size();
|
size_t current_boundary = m_boundaries.size();
|
||||||
bool last_was_finally = false;
|
bool last_was_finally = false;
|
||||||
for (auto const& breakable_scope : m_breakable_scopes.in_reverse()) {
|
|
||||||
|
auto const& jumpable_scopes = type == JumpType::Continue ? m_continuable_scopes : m_breakable_scopes;
|
||||||
|
|
||||||
|
for (auto const& jumpable_scope : jumpable_scopes.in_reverse()) {
|
||||||
for (; current_boundary > 0; --current_boundary) {
|
for (; current_boundary > 0; --current_boundary) {
|
||||||
auto boundary = m_boundaries[current_boundary - 1];
|
auto boundary = m_boundaries[current_boundary - 1];
|
||||||
if (boundary == BlockBoundaryType::Unwind) {
|
if (boundary == BlockBoundaryType::Unwind) {
|
||||||
|
@ -436,27 +434,38 @@ void Generator::generate_break(DeprecatedFlyString const& break_label)
|
||||||
} else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment) {
|
} else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment) {
|
||||||
emit<Bytecode::Op::LeaveLexicalEnvironment>();
|
emit<Bytecode::Op::LeaveLexicalEnvironment>();
|
||||||
} else if (boundary == BlockBoundaryType::ReturnToFinally) {
|
} else if (boundary == BlockBoundaryType::ReturnToFinally) {
|
||||||
auto& block = make_block(DeprecatedString::formatted("{}.break", current_block().name()));
|
auto jump_type_name = type == JumpType::Break ? "break"sv : "continue"sv;
|
||||||
|
auto& block = make_block(DeprecatedString::formatted("{}.{}", current_block().name(), jump_type_name));
|
||||||
emit<Op::ScheduleJump>(Label { block });
|
emit<Op::ScheduleJump>(Label { block });
|
||||||
switch_to_basic_block(block);
|
switch_to_basic_block(block);
|
||||||
last_was_finally = true;
|
last_was_finally = true;
|
||||||
} else if (boundary == BlockBoundaryType::Break) {
|
} else if ((type == JumpType::Continue && boundary == BlockBoundaryType::Continue) || (type == JumpType::Break && boundary == BlockBoundaryType::Break)) {
|
||||||
// Make sure we don't process this boundary twice if the current breakable scope doesn't contain the target label.
|
// Make sure we don't process this boundary twice if the current jumpable scope doesn't contain the target label.
|
||||||
--current_boundary;
|
--current_boundary;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (breakable_scope.language_label_set.contains_slow(break_label)) {
|
if (jumpable_scope.language_label_set.contains_slow(label)) {
|
||||||
emit<Op::Jump>().set_targets(breakable_scope.bytecode_target, {});
|
emit<Op::Jump>().set_targets(jumpable_scope.bytecode_target, {});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We must have a breakable scope available that contains the label, as this should be enforced by the parser.
|
// We must have a jumpable scope available that contains the label, as this should be enforced by the parser.
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Generator::generate_break()
|
||||||
|
{
|
||||||
|
generate_scoped_jump(JumpType::Break);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Generator::generate_break(DeprecatedFlyString const& break_label)
|
||||||
|
{
|
||||||
|
generate_labelled_jump(JumpType::Break, break_label);
|
||||||
|
}
|
||||||
|
|
||||||
void Generator::generate_continue()
|
void Generator::generate_continue()
|
||||||
{
|
{
|
||||||
generate_scoped_jump(JumpType::Continue);
|
generate_scoped_jump(JumpType::Continue);
|
||||||
|
@ -464,37 +473,7 @@ void Generator::generate_continue()
|
||||||
|
|
||||||
void Generator::generate_continue(DeprecatedFlyString const& continue_label)
|
void Generator::generate_continue(DeprecatedFlyString const& continue_label)
|
||||||
{
|
{
|
||||||
size_t current_boundary = m_boundaries.size();
|
generate_labelled_jump(JumpType::Continue, continue_label);
|
||||||
bool last_was_finally = false;
|
|
||||||
for (auto const& continuable_scope : m_continuable_scopes.in_reverse()) {
|
|
||||||
for (; current_boundary > 0; --current_boundary) {
|
|
||||||
auto boundary = m_boundaries[current_boundary - 1];
|
|
||||||
if (boundary == BlockBoundaryType::Unwind) {
|
|
||||||
if (!last_was_finally)
|
|
||||||
emit<Bytecode::Op::LeaveUnwindContext>();
|
|
||||||
last_was_finally = false;
|
|
||||||
} else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment) {
|
|
||||||
emit<Bytecode::Op::LeaveLexicalEnvironment>();
|
|
||||||
} else if (boundary == BlockBoundaryType::ReturnToFinally) {
|
|
||||||
auto& block = make_block(DeprecatedString::formatted("{}.continue", current_block().name()));
|
|
||||||
emit<Op::ScheduleJump>(Label { block });
|
|
||||||
switch_to_basic_block(block);
|
|
||||||
last_was_finally = true;
|
|
||||||
} else if (boundary == BlockBoundaryType::Continue) {
|
|
||||||
// Make sure we don't process this boundary twice if the current continuable scope doesn't contain the target label.
|
|
||||||
--current_boundary;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (continuable_scope.language_label_set.contains_slow(continue_label)) {
|
|
||||||
emit<Op::Jump>().set_targets(continuable_scope.bytecode_target, {});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We must have a continuable scope available that contains the label, as this should be enforced by the parser.
|
|
||||||
VERIFY_NOT_REACHED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Generator::push_home_object(Register register_)
|
void Generator::push_home_object(Register register_)
|
||||||
|
|
|
@ -217,6 +217,7 @@ private:
|
||||||
Break,
|
Break,
|
||||||
};
|
};
|
||||||
void generate_scoped_jump(JumpType);
|
void generate_scoped_jump(JumpType);
|
||||||
|
void generate_labelled_jump(JumpType, DeprecatedFlyString const& label);
|
||||||
|
|
||||||
Generator();
|
Generator();
|
||||||
~Generator() = default;
|
~Generator() = default;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue