mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:17:34 +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:
|
||||||
handle_exception.link(m_assembler);
|
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:
|
||||||
no_exception.link(m_assembler);
|
no_exception.link(m_assembler);
|
||||||
}
|
}
|
||||||
|
@ -230,7 +271,7 @@ void Compiler::push_unwind_context(bool valid, Optional<Bytecode::Label> const&
|
||||||
// push finalizer (patched later)
|
// push finalizer (patched later)
|
||||||
m_assembler.mov(
|
m_assembler.mov(
|
||||||
Assembler::Operand::Register(GPR0),
|
Assembler::Operand::Register(GPR0),
|
||||||
Assembler::Operand::Imm64(0xdeadbeef));
|
Assembler::Operand::Imm64(0));
|
||||||
if (finalizer.has_value())
|
if (finalizer.has_value())
|
||||||
const_cast<Bytecode::BasicBlock&>(finalizer.value().block()).absolute_references_to_here.append(m_assembler.m_output.size() - 8);
|
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));
|
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)
|
// push handler (patched later)
|
||||||
m_assembler.mov(
|
m_assembler.mov(
|
||||||
Assembler::Operand::Register(GPR0),
|
Assembler::Operand::Register(GPR0),
|
||||||
Assembler::Operand::Imm64(0xdeadbeef));
|
Assembler::Operand::Imm64(0));
|
||||||
if (handler.has_value())
|
if (handler.has_value())
|
||||||
const_cast<Bytecode::BasicBlock&>(handler.value().block()).absolute_references_to_here.append(m_assembler.m_output.size() - 8);
|
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));
|
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));
|
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)
|
OwnPtr<NativeExecutable> Compiler::compile(Bytecode::Executable const& bytecode_executable)
|
||||||
{
|
{
|
||||||
if (getenv("LIBJS_NO_JIT"))
|
if (getenv("LIBJS_NO_JIT"))
|
||||||
|
@ -313,6 +366,12 @@ OwnPtr<NativeExecutable> Compiler::compile(Bytecode::Executable const& bytecode_
|
||||||
case Bytecode::Instruction::Type::Increment:
|
case Bytecode::Instruction::Type::Increment:
|
||||||
compiler.compile_increment(static_cast<Bytecode::Op::Increment const&>(op));
|
compiler.compile_increment(static_cast<Bytecode::Op::Increment const&>(op));
|
||||||
break;
|
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:
|
default:
|
||||||
dbgln("JIT compilation failed: {}", bytecode_executable.name);
|
dbgln("JIT compilation failed: {}", bytecode_executable.name);
|
||||||
dbgln("Unsupported bytecode op: {}", op.to_deprecated_string(bytecode_executable));
|
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_jump_conditional(Bytecode::Op::JumpConditional const&);
|
||||||
void compile_less_than(Bytecode::Op::LessThan const&);
|
void compile_less_than(Bytecode::Op::LessThan const&);
|
||||||
void compile_increment(Bytecode::Op::Increment 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 store_vm_register(Bytecode::Register, Assembler::Reg);
|
||||||
void load_vm_register(Assembler::Reg, Bytecode::Register);
|
void load_vm_register(Assembler::Reg, Bytecode::Register);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue