From 1f6a0ef6e0dd26447275e9f19e84f0d5c0216c8e Mon Sep 17 00:00:00 2001 From: Hendiadyoin1 Date: Tue, 6 Dec 2022 20:45:38 +0100 Subject: [PATCH] LibJS: Don't enter finally blocks upon `yield` in bytecode mode --- Userland/Libraries/LibJS/Bytecode/Interpreter.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index d7ec282ec4..2f91b8bf3a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -75,8 +75,10 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e Bytecode::InstructionStreamIterator pc(m_current_block->instruction_stream()); TemporaryChange temp_change { m_pc, &pc }; + // FIXME: This is getting kinda spaghetti-y bool will_jump = false; bool will_return = false; + bool will_yield = false; while (!pc.at_end()) { auto& instruction = *pc; auto ran_or_error = instruction.execute(*this); @@ -113,6 +115,12 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e } if (!m_return_value.is_empty()) { will_return = true; + // Note: A `yield` statement will not go through a finally statement, + // hence we need to set a flag to not do so, + // but we generate a Yield Operation in the case of returns in + // generators as well, so we need to check if it will actually + // continue or is a `return` in disguise + will_yield = instruction.type() == Instruction::Type::Yield && static_cast(instruction).continuation().has_value(); break; } ++pc; @@ -121,7 +129,7 @@ Interpreter::ValueAndFrame Interpreter::run_and_return_frame(Executable const& e if (will_jump) continue; - if (!unwind_contexts().is_empty()) { + if (!unwind_contexts().is_empty() && !will_yield) { auto& unwind_context = unwind_contexts().last(); if (unwind_context.executable == m_current_executable && unwind_context.finalizer) { m_saved_return_value = make_handle(m_return_value);