summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHendiadyoin1 <leon.a@serenityos.org>2022-11-25 16:35:39 +0100
committerLinus Groh <mail@linusgroh.de>2023-02-26 19:40:09 +0100
commitd65488b80c19123cd34e169a1d27093221a504f0 (patch)
treef3385feb8491192a230e3f3da7145806bd3d6dd6
parentf5376cb282df2ba2e005a204b6d9353f1c304f5d (diff)
downloadserenity-d65488b80c19123cd34e169a1d27093221a504f0.zip
LibJS: Generate unwind chains for continue in Bytecode
This works similar to `break` The `try-finally-continue` still do not pass with this, likely because of binding issues.
-rw-r--r--Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp10
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Generator.cpp59
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Generator.h3
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Interpreter.cpp2
4 files changed, 55 insertions, 19 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
index ca8e7e227b..49aa9e640f 100644
--- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
+++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
@@ -1972,17 +1972,11 @@ Bytecode::CodeGenerationErrorOr<void> ContinueStatement::generate_bytecode(Bytec
// We need to execute the finally block, but tell it to resume
// execution at the designated block
if (m_target_label.is_null()) {
- generator.perform_needed_unwinds<Bytecode::Op::Jump>();
- generator.emit<Bytecode::Op::Jump>().set_targets(
- generator.nearest_continuable_scope(),
- {});
+ generator.generate_continue();
return {};
}
- auto target_to_jump_to = generator.perform_needed_unwinds_for_labelled_continue_and_return_target_block(m_target_label);
- generator.emit<Bytecode::Op::Jump>().set_targets(
- target_to_jump_to,
- {});
+ generator.generate_continue(m_target_label);
return {};
}
diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp
index 771454a056..c08f233319 100644
--- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp
+++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp
@@ -335,23 +335,62 @@ void Generator::generate_break(DeprecatedFlyString const& break_label)
VERIFY_NOT_REACHED();
}
-Label Generator::perform_needed_unwinds_for_labelled_continue_and_return_target_block(DeprecatedFlyString const& continue_label)
+void Generator::generate_continue()
+{
+ 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 Continue:
+ emit<Op::Jump>().set_targets(nearest_continuable_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 Break:
+ break;
+ case 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;
+ break;
+ };
+ }
+ }
+ VERIFY_NOT_REACHED();
+}
+
+void Generator::generate_continue(DeprecatedFlyString const& continue_label)
{
size_t current_boundary = m_boundaries.size();
- for (auto& continuable_scope : m_continuable_scopes.in_reverse()) {
+ 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];
- // 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 continue to happen
+ 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;
@@ -359,8 +398,10 @@ Label Generator::perform_needed_unwinds_for_labelled_continue_and_return_target_
}
}
- if (continuable_scope.language_label_set.contains_slow(continue_label))
- return continuable_scope.bytecode_target;
+ 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.
diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h
index 459db7da96..12bb4c9e6c 100644
--- a/Userland/Libraries/LibJS/Bytecode/Generator.h
+++ b/Userland/Libraries/LibJS/Bytecode/Generator.h
@@ -216,7 +216,8 @@ public:
void generate_break();
void generate_break(DeprecatedFlyString const& break_label);
- Label perform_needed_unwinds_for_labelled_continue_and_return_target_block(DeprecatedFlyString const& continue_label);
+ void generate_continue();
+ void generate_continue(DeprecatedFlyString const& continue_label);
void start_boundary(BlockBoundaryType type) { m_boundaries.append(type); }
void end_boundary(BlockBoundaryType type)
diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp
index 33f43ac8ca..d7ec282ec4 100644
--- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp
+++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp
@@ -45,7 +45,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e
TemporaryChange restore_executable { m_current_executable, &executable };
TemporaryChange restore_saved_jump { m_scheduled_jump, static_cast<BasicBlock const*>(nullptr) };
- VERIFY(m_saved_exception.is_null());
+ TemporaryChange restore_saved_exception { m_saved_exception, {} };
bool pushed_execution_context = false;
ExecutionContext execution_context(vm().heap());