diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index abe7272fd3..03d06e9bfb 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -2337,6 +2337,8 @@ Bytecode::CodeGenerationErrorOr TryStatement::generate_bytecode(Bytecode:: auto& handler_block = generator.make_block(); generator.switch_to_basic_block(handler_block); + generator.emit(); + if (!m_finalizer) generator.emit(); diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index fdf4c115e3..1d08b1cff7 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -24,6 +24,7 @@ O(BlockDeclarationInstantiation) \ O(Call) \ O(CallWithArgumentArray) \ + O(Catch) \ O(ConcatString) \ O(ContinuePendingUnwind) \ O(CopyObjectExcludingProperties) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 5e8f1924df..9a3c433a3a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -294,13 +294,7 @@ void Interpreter::run_bytecode() VERIFY(unwind_context.executable == m_current_executable); if (handler) { - VERIFY(!unwind_context.handler_called); - vm().running_execution_context().lexical_environment = unwind_context.lexical_environment; m_current_block = handler; - unwind_context.handler_called = true; - - accumulator = reg(Register::exception()); - reg(Register::exception()) = {}; goto start; } if (finalizer) { @@ -439,6 +433,17 @@ void Interpreter::leave_unwind_context() unwind_contexts().take_last(); } +void Interpreter::catch_exception() +{ + accumulator() = reg(Register::exception()); + reg(Register::exception()) = {}; + auto& context = unwind_contexts().last(); + VERIFY(!context.handler_called); + VERIFY(context.executable == ¤t_executable()); + context.handler_called = true; + vm().running_execution_context().lexical_environment = context.lexical_environment; +} + ThrowCompletionOr> compile(VM& vm, ASTNode const& node, FunctionKind kind, DeprecatedFlyString const& name) { auto executable_result = Bytecode::Generator::generate(node, kind); @@ -746,6 +751,12 @@ ThrowCompletionOr EnterObjectEnvironment::execute_impl(Bytecode::Interpret return {}; } +ThrowCompletionOr Catch::execute_impl(Bytecode::Interpreter& interpreter) const +{ + interpreter.catch_exception(); + return {}; +} + ThrowCompletionOr CreateVariable::execute_impl(Bytecode::Interpreter& interpreter) const { auto const& name = interpreter.current_executable().get_identifier(m_identifier); @@ -1733,4 +1744,9 @@ DeprecatedString ImportCall::to_deprecated_string_impl(Bytecode::Executable cons return DeprecatedString::formatted("ImportCall specifier:{} options:{}"sv, m_specifier, m_options); } +DeprecatedString Catch::to_deprecated_string_impl(Bytecode::Executable const&) const +{ + return "Catch"sv; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index 05772b1e4f..ab5890f252 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -74,6 +74,7 @@ public: void enter_unwind_context(); void leave_unwind_context(); + void catch_exception(); Executable& current_executable() { return *m_current_executable; } Executable const& current_executable() const { return *m_current_executable; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 26cac4d460..1f3525c1e6 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -407,6 +407,17 @@ public: DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; }; +class Catch final : public Instruction { +public: + explicit Catch() + : Instruction(Type::Catch, sizeof(*this)) + { + } + + ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; + DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; +}; + class CreateVariable final : public Instruction { public: explicit CreateVariable(IdentifierTableIndex identifier, EnvironmentMode mode, bool is_immutable, bool is_global = false, bool is_strict = false) diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index 12605a8371..6bca178411 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -560,14 +560,25 @@ void Compiler::check_exception() } } +static void cxx_enter_unwind_context(VM& vm) +{ + vm.bytecode_interpreter().enter_unwind_context(); +} + void Compiler::compile_enter_unwind_context(Bytecode::Op::EnterUnwindContext const& op) { + native_call((void*)cxx_enter_unwind_context); m_assembler.jump(label_for(op.entry_point().block())); } +static void cxx_leave_unwind_context(VM& vm) +{ + vm.bytecode_interpreter().leave_unwind_context(); +} + void Compiler::compile_leave_unwind_context(Bytecode::Op::LeaveUnwindContext const&) { - /* Nothing */ + native_call((void*)cxx_leave_unwind_context); } void Compiler::compile_throw(Bytecode::Op::Throw const&) @@ -577,6 +588,16 @@ void Compiler::compile_throw(Bytecode::Op::Throw const&) check_exception(); } +static void cxx_catch(VM& vm) +{ + vm.bytecode_interpreter().catch_exception(); +} + +void Compiler::compile_catch(Bytecode::Op::Catch const&) +{ + native_call((void*)cxx_catch); +} + static ThrowCompletionOr loosely_inequals(VM& vm, Value src1, Value src2) { return Value(!TRY(is_loosely_equal(vm, src1, src2))); diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index 7672d2e78c..eabd40612b 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -83,6 +83,7 @@ private: O(EnterUnwindContext, enter_unwind_context) \ O(LeaveUnwindContext, leave_unwind_context) \ O(Throw, throw) \ + O(Catch, catch) \ O(CreateLexicalEnvironment, create_lexical_environment) \ O(LeaveLexicalEnvironment, leave_lexical_environment) \ O(ToNumeric, to_numeric) \