From 0768bf26230e3637ac045f3cf6b929cbfa3deed1 Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Sat, 28 Oct 2023 17:37:59 +0300 Subject: [PATCH] LibJS: Execute the finalizer when returning from a try block in the JIT This fixes 1 of the 2 remaining failing test-js tests. --- Userland/Libraries/LibJS/JIT/Compiler.cpp | 44 +++++++++++++++++++++++ Userland/Libraries/LibJS/JIT/Compiler.h | 1 + 2 files changed, 45 insertions(+) diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index a844e98e9f..3dcfcabbe6 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -566,6 +566,32 @@ JS_ENUMERATE_COMMON_UNARY_OPS(DO_COMPILE_COMMON_UNARY_OP) void Compiler::compile_return(Bytecode::Op::Return const&) { load_vm_register(GPR0, Bytecode::Register::accumulator()); + + // check for finalizer + // if (!unwind_context.valid) goto normal_return; + auto normal_return = m_assembler.make_label(); + m_assembler.mov( + Assembler::Operand::Register(GPR1), + Assembler::Operand::Mem64BaseAndOffset(UNWIND_CONTEXT_BASE, 0)); + m_assembler.jump_if_equal( + Assembler::Operand::Register(GPR1), + Assembler::Operand::Imm(0), + normal_return); + + // if (!unwind_context.finalizer) goto normal_return; + m_assembler.mov( + Assembler::Operand::Register(GPR1), + Assembler::Operand::Mem64BaseAndOffset(UNWIND_CONTEXT_BASE, 16)); + m_assembler.jump_if_equal( + Assembler::Operand::Register(GPR1), + Assembler::Operand::Imm(0), + normal_return); + + store_vm_register(Bytecode::Register::saved_return_value(), GPR0); + m_assembler.jump(Assembler::Operand::Register(GPR1)); + + // normal_return: + normal_return.link(m_assembler); store_vm_register(Bytecode::Register::return_value(), GPR0); m_assembler.exit(); } @@ -933,6 +959,21 @@ void Compiler::compile_set_variable(Bytecode::Op::SetVariable const& op) check_exception(); } +void Compiler::compile_continue_pending_unwind(Bytecode::Op::ContinuePendingUnwind const& op) +{ + // re-throw the exception if we reached the end of the finally block and there was no catch block to handle it + check_exception(); + + // if (!saved_return_value.is_empty()) goto resume_block; + load_vm_register(GPR0, Bytecode::Register::saved_return_value()); + m_assembler.mov(Assembler::Operand::Register(GPR1), Assembler::Operand::Imm(Value().encoded())); + m_assembler.jump_if_not_equal(Assembler::Operand::Register(GPR0), Assembler::Operand::Register(GPR1), label_for(op.resume_target().block())); + + // finish the pending return from the try block + store_vm_register(Bytecode::Register::return_value(), GPR0); + m_assembler.exit(); +} + static void cxx_create_lexical_environment(VM& vm) { auto make_and_swap_envs = [&](auto& old_environment) { @@ -1088,6 +1129,9 @@ OwnPtr Compiler::compile(Bytecode::Executable& bytecode_execut case Bytecode::Instruction::Type::LessThan: compiler.compile_less_than(static_cast(op)); break; + case Bytecode::Instruction::Type::ContinuePendingUnwind: + compiler.compile_continue_pending_unwind(static_cast(op)); + break; # define DO_COMPILE_COMMON_BINARY_OP(TitleCaseName, snake_case_name) \ case Bytecode::Instruction::Type::TitleCaseName: \ diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index 64935812d8..168282ae0e 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -112,6 +112,7 @@ private: void compile_call(Bytecode::Op::Call const&); void compile_typeof_variable(Bytecode::Op::TypeofVariable const&); void compile_set_variable(Bytecode::Op::SetVariable const&); + void compile_continue_pending_unwind(Bytecode::Op::ContinuePendingUnwind const&); void store_vm_register(Bytecode::Register, Assembler::Reg); void load_vm_register(Assembler::Reg, Bytecode::Register);