diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 44cd8e7874..e493bfbb7b 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -171,12 +171,67 @@ void Interpreter::run_bytecode() bool will_return = false; bool will_yield = false; + ThrowCompletionOr result; + while (!pc.at_end()) { auto& instruction = *pc; - auto ran_or_error = instruction.execute(*this); - if (ran_or_error.is_error()) [[unlikely]] { - reg(Register::exception()) = *ran_or_error.throw_completion().value(); + switch (instruction.type()) { + case Instruction::Type::Jump: + m_current_block = &static_cast(instruction).true_target()->block(); + goto start; + case Instruction::Type::JumpConditional: + if (accumulator().to_boolean()) + m_current_block = &static_cast(instruction).true_target()->block(); + else + m_current_block = &static_cast(instruction).false_target()->block(); + goto start; + case Instruction::Type::JumpNullish: + if (accumulator().is_nullish()) + m_current_block = &static_cast(instruction).true_target()->block(); + else + m_current_block = &static_cast(instruction).false_target()->block(); + goto start; + case Instruction::Type::JumpUndefined: + if (accumulator().is_undefined()) + m_current_block = &static_cast(instruction).true_target()->block(); + else + m_current_block = &static_cast(instruction).false_target()->block(); + goto start; + case Instruction::Type::EnterUnwindContext: + enter_unwind_context( + static_cast(instruction).handler_target(), + static_cast(instruction).finalizer_target()); + m_current_block = &static_cast(instruction).entry_point().block(); + goto start; + case Instruction::Type::ContinuePendingUnwind: + if (auto exception = reg(Register::exception()); !exception.is_empty()) { + result = throw_completion(exception); + break; + } + if (!saved_return_value().is_empty()) { + do_return(saved_return_value()); + break; + } + if (m_scheduled_jump) { + // FIXME: If we `break` or `continue` in the finally, we need to clear + // this field + m_current_block = exchange(m_scheduled_jump, nullptr); + } else { + m_current_block = &static_cast(instruction).resume_target().block(); + } + goto start; + case Instruction::Type::ScheduleJump: + m_scheduled_jump = &static_cast(instruction).target().block(); + m_current_block = unwind_contexts().last().finalizer; + goto start; + default: + result = instruction.execute(*this); + break; + } + + if (result.is_error()) [[unlikely]] { + reg(Register::exception()) = *result.throw_completion().value(); if (unwind_contexts().is_empty()) return; auto& unwind_context = unwind_contexts().last(); @@ -204,10 +259,7 @@ void Interpreter::run_bytecode() // If you run into this, you probably forgot to remove the current unwind_context somewhere. VERIFY_NOT_REACHED(); } - if (m_pending_jump.has_value()) { - m_current_block = m_pending_jump.release_value(); - goto start; - } + if (!reg(Register::return_value()).is_empty()) { will_return = true; // Note: A `yield` statement will not go through a finally statement, @@ -315,27 +367,6 @@ void Interpreter::leave_unwind_context() unwind_contexts().take_last(); } -ThrowCompletionOr Interpreter::continue_pending_unwind(Label const& resume_label) -{ - if (auto exception = reg(Register::exception()); !exception.is_empty()) - return throw_completion(exception); - - if (!saved_return_value().is_empty()) { - do_return(saved_return_value()); - return {}; - } - - if (m_scheduled_jump) { - // FIXME: If we `break` or `continue` in the finally, we need to clear - // this field - jump(Label { *m_scheduled_jump }); - m_scheduled_jump = nullptr; - } else { - jump(resume_label); - } - return {}; -} - ThrowCompletionOr> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name) { auto executable_result = Bytecode::Generator::generate(node, kind); diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index eae8bf7748..448939857a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -64,16 +64,6 @@ public: auto& saved_lexical_environment_stack() { return call_frame().saved_lexical_environments; } auto& unwind_contexts() { return call_frame().unwind_contexts; } - void jump(Label const& label) - { - m_pending_jump = &label.block(); - } - void schedule_jump(Label const& label) - { - m_scheduled_jump = &label.block(); - VERIFY(unwind_contexts().last().finalizer); - jump(Label { *unwind_contexts().last().finalizer }); - } void do_return(Value value) { reg(Register::return_value()) = value; @@ -82,7 +72,6 @@ public: void enter_unwind_context(Optional