diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp index 64d34767fa..50388890fe 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp @@ -184,19 +184,17 @@ ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value this_value return {}; } -template -ThrowCompletionOr perform_call(Interpreter& interpreter, InstructionType const& call, Value callee, MarkedVector argument_values) +ThrowCompletionOr perform_call(Interpreter& interpreter, Value this_value, Op::CallType call_type, Value callee, MarkedVector 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 perform_call(Interpreter& interpreter, InstructionType return return_value; } -template ThrowCompletionOr perform_call(Interpreter&, Op::Call const&, Value, MarkedVector); -template ThrowCompletionOr perform_call(Interpreter&, Op::CallWithArgumentArray const&, Value, MarkedVector); - static Completion throw_type_error_for_callee(Bytecode::Interpreter& interpreter, auto& call, StringView callee_type) { auto& vm = interpreter.vm(); diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h index 219eb664b8..979951d1e7 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h @@ -17,8 +17,7 @@ ThrowCompletionOr get_by_id(Bytecode::Interpreter&, IdentifierTableIndex, ThrowCompletionOr get_by_value(Bytecode::Interpreter&, Value base_value, Value property_key_value); ThrowCompletionOr get_global(Bytecode::Interpreter&, IdentifierTableIndex, u32 cache_index); ThrowCompletionOr put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind); -template -ThrowCompletionOr perform_call(Interpreter&, InstructionType const&, Value callee, MarkedVector argument_values); +ThrowCompletionOr perform_call(Interpreter&, Value this_value, Op::CallType, Value callee, MarkedVector argument_values); template ThrowCompletionOr throw_if_needed_for_call(Interpreter&, InstructionType const&, Value callee); diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index d1c878c647..90566a84ac 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1147,7 +1147,7 @@ ThrowCompletionOr 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 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 {}; } diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index 1345bb196a..b0ce4e5ac9 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -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 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 Compiler::compile(Bytecode::Executable& bytecode_executable) { if (getenv("LIBJS_NO_JIT")) @@ -580,6 +611,9 @@ OwnPtr Compiler::compile(Bytecode::Executable& bytecode_execut case Bytecode::Instruction::Type::ResolveThisBinding: compiler.compile_resolve_this_binding(static_cast(op)); break; + case Bytecode::Instruction::Type::Call: + compiler.compile_call(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 721ec2b28b..2c1ebce484 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -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);