1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:47:35 +00:00

LibJS: Introduce Builtins

Builtins are functions that can be detected during bytecode generation
and enable fast-paths in the JIT.
This commit is contained in:
Simon Wanner 2023-11-17 11:48:30 +01:00 committed by Andreas Kling
parent b9141d85d8
commit 86b85aa68b
13 changed files with 191 additions and 4 deletions

View file

@ -2518,9 +2518,56 @@ static Value cxx_call(VM& vm, Value callee, u32 first_argument_index, u32 argume
return TRY_OR_SET_EXCEPTION(perform_call(vm.bytecode_interpreter(), this_value, call_type, callee, move(argument_values)));
}
Assembler::Reg Compiler::argument_register(u32 index)
{
switch (index) {
case 0:
return ARG0;
case 1:
return ARG1;
case 2:
return ARG2;
case 3:
return ARG3;
case 4:
return ARG4;
case 5:
return ARG5;
}
VERIFY_NOT_REACHED();
}
void Compiler::compile_call(Bytecode::Op::Call const& op)
{
Assembler::Label slow_case {};
Assembler::Label end {};
load_vm_register(ARG1, op.callee());
if (op.call_type() == Bytecode::Op::CallType::Call && op.builtin().has_value() && op.argument_count() == Bytecode::builtin_argument_count(op.builtin().value())) {
auto builtin = op.builtin().value();
// GPR0 = vm.running_execution_context().realm;
m_assembler.mov(
Assembler::Operand::Register(GPR0),
Assembler::Operand::Mem64BaseAndOffset(RUNNING_EXECUTION_CONTEXT_BASE, ExecutionContext::realm_offset()));
// GPR0 = GPR0->m_builtins[to_underlying(builtin)]
m_assembler.mov(
Assembler::Operand::Register(GPR0),
Assembler::Operand::Mem64BaseAndOffset(GPR0, Realm::builtins_offset() + sizeof(Value) * to_underlying(builtin)));
// if (callee != GPR0) goto slow_case;
m_assembler.jump_if(
Assembler::Operand::Register(ARG1),
Assembler::Condition::NotEqualTo,
Assembler::Operand::Register(GPR0),
slow_case);
// Load arguments into ARG2, ARG3, ...
for (u32 arg = 0; arg < op.argument_count(); arg++)
load_vm_register(argument_register(arg + 2), Bytecode::Register { op.first_argument().index() + arg });
compile_builtin(builtin, slow_case, end);
}
slow_case.link(m_assembler);
m_assembler.mov(
Assembler::Operand::Register(ARG2),
Assembler::Operand::Imm(op.first_argument().index()));
@ -2537,6 +2584,21 @@ void Compiler::compile_call(Bytecode::Op::Call const& op)
native_call((void*)cxx_call, { Assembler::Operand::Register(GPR0) });
store_accumulator(RET);
check_exception();
end.link(m_assembler);
}
void Compiler::compile_builtin(Bytecode::Builtin builtin, [[maybe_unused]] Assembler::Label& slow_case, [[maybe_unused]] Assembler::Label& end)
{
switch (builtin) {
# define DEFINE_BUILTIN_CASE(name, snake_case_name, ...) \
case Bytecode::Builtin::name: \
compile_builtin_##snake_case_name(slow_case, end); \
break;
JS_ENUMERATE_BUILTINS(DEFINE_BUILTIN_CASE)
# undef DEFINE_BUILTIN_CASE
case Bytecode::Builtin::__Count:
VERIFY_NOT_REACHED();
}
}
static Value cxx_call_with_argument_array(VM& vm, Value arguments, Value callee, Value this_value, Bytecode::Op::CallType call_type, Optional<Bytecode::StringTableIndex> const& expression_string)

View file

@ -9,6 +9,7 @@
#include <AK/Platform.h>
#include <LibJIT/Assembler.h>
#include <LibJS/Bytecode/Builtins.h>
#include <LibJS/Bytecode/Executable.h>
#include <LibJS/Bytecode/Op.h>
#include <LibJS/JIT/NativeExecutable.h>
@ -44,6 +45,8 @@ private:
static constexpr auto RUNNING_EXECUTION_CONTEXT_BASE = Assembler::Reg::R15;
# endif
static Assembler::Reg argument_register(u32);
# define JS_ENUMERATE_COMMON_BINARY_OPS_WITHOUT_FAST_PATH(O) \
O(Div, div) \
O(Exp, exp) \
@ -147,6 +150,12 @@ private:
JS_ENUMERATE_IMPLEMENTED_JIT_OPS(DECLARE_COMPILE_OP)
# undef DECLARE_COMPILE_OP
void compile_builtin(Bytecode::Builtin, Assembler::Label& slow_case, Assembler::Label& end);
# define DECLARE_COMPILE_BUILTIN(name, snake_case_name, ...) \
void compile_builtin_##snake_case_name(Assembler::Label& slow_case, Assembler::Label& end);
JS_ENUMERATE_BUILTINS(DECLARE_COMPILE_BUILTIN)
# undef DECLARE_COMPILE_BUILTIN
void store_vm_register(Bytecode::Register, Assembler::Reg);
void load_vm_register(Assembler::Reg, Bytecode::Register);