mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:27:45 +00:00
LibJS/JIT: Compile the EnterUnwindContext and LeaveUnwindContext ops
These push a "valid" unwind context on the stack and check_exception() now knows how to jump to the (catch) handler if present. (finally) finalizers will require some more work, but with this change, we now have basic support for try...catch. :^)
This commit is contained in:
parent
9d35016284
commit
9dd5be0186
2 changed files with 63 additions and 2 deletions
|
@ -214,6 +214,47 @@ void Compiler::check_exception()
|
|||
// handle_exception:
|
||||
handle_exception.link(m_assembler);
|
||||
|
||||
// if (unwind_context.handler) {
|
||||
// accumulator = exception;
|
||||
// exception = Value();
|
||||
// goto handler;
|
||||
// }
|
||||
auto no_handler = m_assembler.make_label();
|
||||
m_assembler.mov(
|
||||
Assembler::Operand::Register(GPR0),
|
||||
Assembler::Operand::Mem64BaseAndOffset(UNWIND_CONTEXT_BASE, 8));
|
||||
m_assembler.jump_if_equal(
|
||||
Assembler::Operand::Register(GPR0),
|
||||
Assembler::Operand::Imm32(0),
|
||||
no_handler);
|
||||
load_vm_register(GPR1, Bytecode::Register::exception());
|
||||
store_vm_register(Bytecode::Register::accumulator(), GPR1);
|
||||
m_assembler.mov(
|
||||
Assembler::Operand::Register(GPR1),
|
||||
Assembler::Operand::Imm64(Value().encoded()));
|
||||
store_vm_register(Bytecode::Register::exception(), GPR1);
|
||||
m_assembler.jump(Assembler::Operand::Register(GPR0));
|
||||
|
||||
// no_handler:
|
||||
no_handler.link(m_assembler);
|
||||
|
||||
// if (unwind_context.finalizer) goto finalizer;
|
||||
auto no_finalizer = m_assembler.make_label();
|
||||
m_assembler.mov(
|
||||
Assembler::Operand::Register(GPR0),
|
||||
Assembler::Operand::Mem64BaseAndOffset(UNWIND_CONTEXT_BASE, 16));
|
||||
m_assembler.jump_if_equal(
|
||||
Assembler::Operand::Register(GPR0),
|
||||
Assembler::Operand::Imm32(0),
|
||||
no_finalizer);
|
||||
|
||||
m_assembler.jump(Assembler::Operand::Register(GPR0));
|
||||
|
||||
// no_finalizer:
|
||||
// NOTE: No catch and no finally!? Crash.
|
||||
no_finalizer.link(m_assembler);
|
||||
m_assembler.verify_not_reached();
|
||||
|
||||
// no_exception:
|
||||
no_exception.link(m_assembler);
|
||||
}
|
||||
|
@ -230,7 +271,7 @@ void Compiler::push_unwind_context(bool valid, Optional<Bytecode::Label> const&
|
|||
// push finalizer (patched later)
|
||||
m_assembler.mov(
|
||||
Assembler::Operand::Register(GPR0),
|
||||
Assembler::Operand::Imm64(0xdeadbeef));
|
||||
Assembler::Operand::Imm64(0));
|
||||
if (finalizer.has_value())
|
||||
const_cast<Bytecode::BasicBlock&>(finalizer.value().block()).absolute_references_to_here.append(m_assembler.m_output.size() - 8);
|
||||
m_assembler.push(Assembler::Operand::Register(GPR0));
|
||||
|
@ -238,7 +279,7 @@ void Compiler::push_unwind_context(bool valid, Optional<Bytecode::Label> const&
|
|||
// push handler (patched later)
|
||||
m_assembler.mov(
|
||||
Assembler::Operand::Register(GPR0),
|
||||
Assembler::Operand::Imm64(0xdeadbeef));
|
||||
Assembler::Operand::Imm64(0));
|
||||
if (handler.has_value())
|
||||
const_cast<Bytecode::BasicBlock&>(handler.value().block()).absolute_references_to_here.append(m_assembler.m_output.size() - 8);
|
||||
m_assembler.push(Assembler::Operand::Register(GPR0));
|
||||
|
@ -261,6 +302,18 @@ void Compiler::pop_unwind_context()
|
|||
m_assembler.add(Assembler::Operand::Register(UNWIND_CONTEXT_BASE), Assembler::Operand::Imm8(32));
|
||||
}
|
||||
|
||||
void Compiler::compile_enter_unwind_context(Bytecode::Op::EnterUnwindContext const& op)
|
||||
{
|
||||
push_unwind_context(true, op.handler_target(), op.finalizer_target());
|
||||
|
||||
m_assembler.jump(const_cast<Bytecode::BasicBlock&>(op.entry_point().block()));
|
||||
}
|
||||
|
||||
void Compiler::compile_leave_unwind_context(Bytecode::Op::LeaveUnwindContext const&)
|
||||
{
|
||||
pop_unwind_context();
|
||||
}
|
||||
|
||||
OwnPtr<NativeExecutable> Compiler::compile(Bytecode::Executable const& bytecode_executable)
|
||||
{
|
||||
if (getenv("LIBJS_NO_JIT"))
|
||||
|
@ -313,6 +366,12 @@ OwnPtr<NativeExecutable> Compiler::compile(Bytecode::Executable const& bytecode_
|
|||
case Bytecode::Instruction::Type::Increment:
|
||||
compiler.compile_increment(static_cast<Bytecode::Op::Increment const&>(op));
|
||||
break;
|
||||
case Bytecode::Instruction::Type::EnterUnwindContext:
|
||||
compiler.compile_enter_unwind_context(static_cast<Bytecode::Op::EnterUnwindContext const&>(op));
|
||||
break;
|
||||
case Bytecode::Instruction::Type::LeaveUnwindContext:
|
||||
compiler.compile_leave_unwind_context(static_cast<Bytecode::Op::LeaveUnwindContext const&>(op));
|
||||
break;
|
||||
default:
|
||||
dbgln("JIT compilation failed: {}", bytecode_executable.name);
|
||||
dbgln("Unsupported bytecode op: {}", op.to_deprecated_string(bytecode_executable));
|
||||
|
|
|
@ -38,6 +38,8 @@ private:
|
|||
void compile_jump_conditional(Bytecode::Op::JumpConditional const&);
|
||||
void compile_less_than(Bytecode::Op::LessThan const&);
|
||||
void compile_increment(Bytecode::Op::Increment const&);
|
||||
void compile_enter_unwind_context(Bytecode::Op::EnterUnwindContext const&);
|
||||
void compile_leave_unwind_context(Bytecode::Op::LeaveUnwindContext const&);
|
||||
|
||||
void store_vm_register(Bytecode::Register, Assembler::Reg);
|
||||
void load_vm_register(Assembler::Reg, Bytecode::Register);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue