diff options
author | Hendiadyoin1 <leon.a@serenityos.org> | 2022-11-25 16:35:39 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-02-26 19:40:09 +0100 |
commit | d65488b80c19123cd34e169a1d27093221a504f0 (patch) | |
tree | f3385feb8491192a230e3f3da7145806bd3d6dd6 | |
parent | f5376cb282df2ba2e005a204b6d9353f1c304f5d (diff) | |
download | serenity-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.cpp | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.cpp | 59 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Interpreter.cpp | 2 |
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()); |