1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 15:48:12 +00:00

LibJS/JIT: Compile the Call bytecode instruction

I've left a FIXME about dealing with some throwsy cases.
This commit is contained in:
Andreas Kling 2023-10-20 13:32:59 +02:00
parent 7fc35fde09
commit 640455b1d2
5 changed files with 43 additions and 12 deletions

View file

@ -184,19 +184,17 @@ ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value
return {};
}
template<typename InstructionType>
ThrowCompletionOr<Value> perform_call(Interpreter& interpreter, InstructionType const& call, Value callee, MarkedVector<Value> argument_values)
ThrowCompletionOr<Value> perform_call(Interpreter& interpreter, Value this_value, Op::CallType call_type, Value callee, MarkedVector<Value> argument_values)
{
auto& vm = interpreter.vm();
auto this_value = interpreter.reg(call.this_value());
auto& function = callee.as_function();
Value return_value;
if (call.call_type() == Op::CallType::DirectEval) {
if (call_type == Op::CallType::DirectEval) {
if (callee == interpreter.realm().intrinsics().eval_function())
return_value = TRY(perform_eval(vm, !argument_values.is_empty() ? argument_values[0].value_or(JS::js_undefined()) : js_undefined(), vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct));
else
return_value = TRY(JS::call(vm, function, this_value, move(argument_values)));
} else if (call.call_type() == Op::CallType::Call)
} else if (call_type == Op::CallType::Call)
return_value = TRY(JS::call(vm, function, this_value, move(argument_values)));
else
return_value = TRY(construct(vm, function, move(argument_values)));
@ -204,9 +202,6 @@ ThrowCompletionOr<Value> perform_call(Interpreter& interpreter, InstructionType
return return_value;
}
template ThrowCompletionOr<Value> perform_call(Interpreter&, Op::Call const&, Value, MarkedVector<Value>);
template ThrowCompletionOr<Value> perform_call(Interpreter&, Op::CallWithArgumentArray const&, Value, MarkedVector<Value>);
static Completion throw_type_error_for_callee(Bytecode::Interpreter& interpreter, auto& call, StringView callee_type)
{
auto& vm = interpreter.vm();

View file

@ -17,8 +17,7 @@ ThrowCompletionOr<Value> get_by_id(Bytecode::Interpreter&, IdentifierTableIndex,
ThrowCompletionOr<Value> get_by_value(Bytecode::Interpreter&, Value base_value, Value property_key_value);
ThrowCompletionOr<Value> get_global(Bytecode::Interpreter&, IdentifierTableIndex, u32 cache_index);
ThrowCompletionOr<void> put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind);
template<typename InstructionType>
ThrowCompletionOr<Value> perform_call(Interpreter&, InstructionType const&, Value callee, MarkedVector<Value> argument_values);
ThrowCompletionOr<Value> perform_call(Interpreter&, Value this_value, Op::CallType, Value callee, MarkedVector<Value> argument_values);
template<typename InstructionType>
ThrowCompletionOr<void> throw_if_needed_for_call(Interpreter&, InstructionType const&, Value callee);

View file

@ -1147,7 +1147,7 @@ ThrowCompletionOr<void> Call::execute_impl(Bytecode::Interpreter& interpreter) c
for (u32 i = 0; i < m_argument_count; ++i) {
argument_values.unchecked_append(interpreter.reg(Register { m_first_argument.index() + i }));
}
interpreter.accumulator() = TRY(perform_call(interpreter, *this, callee, move(argument_values)));
interpreter.accumulator() = TRY(perform_call(interpreter, interpreter.reg(m_this_value), call_type(), callee, move(argument_values)));
return {};
}
@ -1156,7 +1156,7 @@ ThrowCompletionOr<void> CallWithArgumentArray::execute_impl(Bytecode::Interprete
auto callee = interpreter.reg(m_callee);
TRY(throw_if_needed_for_call(interpreter, *this, callee));
auto argument_values = argument_list_evaluation(interpreter);
interpreter.accumulator() = TRY(perform_call(interpreter, *this, callee, move(argument_values)));
interpreter.accumulator() = TRY(perform_call(interpreter, interpreter.reg(m_this_value), call_type(), callee, move(argument_values)));
return {};
}

View file

@ -492,6 +492,37 @@ void Compiler::compile_put_by_id(Bytecode::Op::PutById const& op)
check_exception();
}
static Value cxx_call(VM& vm, Value callee, u32 first_argument_index, u32 argument_count, Value this_value, Bytecode::Op::CallType call_type)
{
// FIXME: Uncomment this and deal with it.
// TRY_OR_SET_EXCEPTION(throw_if_needed_for_call(vm.bytecode_interpreter(), *this, callee));
MarkedVector<Value> argument_values(vm.heap());
argument_values.ensure_capacity(argument_count);
for (u32 i = 0; i < argument_count; ++i) {
argument_values.unchecked_append(vm.bytecode_interpreter().reg(Bytecode::Register { first_argument_index + i }));
}
return TRY_OR_SET_EXCEPTION(perform_call(vm.bytecode_interpreter(), this_value, call_type, callee, move(argument_values)));
}
void Compiler::compile_call(Bytecode::Op::Call const& op)
{
load_vm_register(ARG1, op.callee());
m_assembler.mov(
Assembler::Operand::Register(ARG2),
Assembler::Operand::Imm64(op.first_argument().index()));
m_assembler.mov(
Assembler::Operand::Register(ARG3),
Assembler::Operand::Imm64(op.argument_count()));
load_vm_register(ARG4, op.this_value());
m_assembler.mov(
Assembler::Operand::Register(ARG5),
Assembler::Operand::Imm64(to_underlying(op.call_type())));
m_assembler.native_call((void*)cxx_call);
store_vm_register(Bytecode::Register::accumulator(), RET);
check_exception();
}
OwnPtr<NativeExecutable> Compiler::compile(Bytecode::Executable& bytecode_executable)
{
if (getenv("LIBJS_NO_JIT"))
@ -580,6 +611,9 @@ OwnPtr<NativeExecutable> Compiler::compile(Bytecode::Executable& bytecode_execut
case Bytecode::Instruction::Type::ResolveThisBinding:
compiler.compile_resolve_this_binding(static_cast<Bytecode::Op::ResolveThisBinding const&>(op));
break;
case Bytecode::Instruction::Type::Call:
compiler.compile_call(static_cast<Bytecode::Op::Call const&>(op));
break;
#define DO_COMPILE_COMMON_BINARY_OP(TitleCaseName, snake_case_name) \
case Bytecode::Instruction::Type::TitleCaseName: \

View file

@ -25,6 +25,7 @@ private:
static constexpr auto ARG2 = Assembler::Reg::RDX;
static constexpr auto ARG3 = Assembler::Reg::RCX;
static constexpr auto ARG4 = Assembler::Reg::R8;
static constexpr auto ARG5 = Assembler::Reg::R9;
static constexpr auto RET = Assembler::Reg::RAX;
static constexpr auto STACK_POINTER = Assembler::Reg::RSP;
static constexpr auto REGISTER_ARRAY_BASE = Assembler::Reg::R13;
@ -61,6 +62,8 @@ private:
void compile_put_by_id(Bytecode::Op::PutById const&);
void compile_call(Bytecode::Op::Call const&);
void store_vm_register(Bytecode::Register, Assembler::Reg);
void load_vm_register(Assembler::Reg, Bytecode::Register);