diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp index 6d43aee9b9..71a1ab5094 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp @@ -327,4 +327,52 @@ ThrowCompletionOr get_variable(Bytecode::Interpreter& interpreter, Deprec return TRY(reference.get_value(vm)); } +ThrowCompletionOr get_callee_and_this_from_environment(Bytecode::Interpreter& interpreter, DeprecatedFlyString const& name, u32 cache_index) +{ + auto& vm = interpreter.vm(); + + Value callee = js_undefined(); + Value this_value = js_undefined(); + + auto& cached_environment_coordinate = interpreter.current_executable().environment_variable_caches[cache_index]; + if (cached_environment_coordinate.has_value()) { + auto environment = vm.running_execution_context().lexical_environment; + for (size_t i = 0; i < cached_environment_coordinate->hops; ++i) + environment = environment->outer_environment(); + VERIFY(environment); + VERIFY(environment->is_declarative_environment()); + if (!environment->is_permanently_screwed_by_eval()) { + callee = TRY(verify_cast(*environment).get_binding_value_direct(vm, cached_environment_coordinate.value().index, vm.in_strict_mode())); + this_value = js_undefined(); + if (auto base_object = environment->with_base_object()) + this_value = base_object; + return CalleeAndThis { + .callee = callee, + .this_value = this_value, + }; + } + cached_environment_coordinate = {}; + } + + auto reference = TRY(vm.resolve_binding(name)); + if (reference.environment_coordinate().has_value()) + cached_environment_coordinate = reference.environment_coordinate(); + + callee = TRY(reference.get_value(vm)); + + if (reference.is_property_reference()) { + this_value = reference.get_this_value(); + } else { + if (reference.is_environment_reference()) { + if (auto base_object = reference.base_environment().with_base_object(); base_object != nullptr) + this_value = base_object; + } + } + + return CalleeAndThis { + .callee = callee, + .this_value = this_value, + }; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h index 6a4d33bd74..2db69725a8 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h @@ -25,4 +25,10 @@ Value new_function(VM&, FunctionExpression const&, Optional put_by_value(VM&, Value base, Value property_key_value, Value value, Op::PropertyKind); ThrowCompletionOr get_variable(Bytecode::Interpreter&, DeprecatedFlyString const& name, u32 cache_index); +struct CalleeAndThis { + Value callee; + Value this_value; +}; +ThrowCompletionOr get_callee_and_this_from_environment(Bytecode::Interpreter&, DeprecatedFlyString const& name, u32 cache_index); + } diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 8b3e35eb65..037a12ed61 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -786,44 +786,9 @@ ThrowCompletionOr GetVariable::execute_impl(Bytecode::Interpreter& interpr ThrowCompletionOr GetCalleeAndThisFromEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const { - auto& vm = interpreter.vm(); - - auto& cached_environment_coordinate = interpreter.current_executable().environment_variable_caches[m_cache_index]; - if (cached_environment_coordinate.has_value()) { - auto environment = vm.running_execution_context().lexical_environment; - for (size_t i = 0; i < cached_environment_coordinate->hops; ++i) - environment = environment->outer_environment(); - VERIFY(environment); - VERIFY(environment->is_declarative_environment()); - if (!environment->is_permanently_screwed_by_eval()) { - interpreter.reg(m_callee_reg) = TRY(verify_cast(*environment).get_binding_value_direct(vm, cached_environment_coordinate.value().index, vm.in_strict_mode())); - Value this_value = js_undefined(); - if (auto base_object = environment->with_base_object()) - this_value = base_object; - interpreter.reg(m_this_reg) = this_value; - return {}; - } - cached_environment_coordinate = {}; - } - - auto const& string = interpreter.current_executable().get_identifier(m_identifier); - auto reference = TRY(vm.resolve_binding(string)); - if (reference.environment_coordinate().has_value()) - cached_environment_coordinate = reference.environment_coordinate(); - - interpreter.reg(m_callee_reg) = TRY(reference.get_value(vm)); - - Value this_value = js_undefined(); - if (reference.is_property_reference()) { - this_value = reference.get_this_value(); - } else { - if (reference.is_environment_reference()) { - if (auto base_object = reference.base_environment().with_base_object(); base_object != nullptr) - this_value = base_object; - } - } - interpreter.reg(m_this_reg) = this_value; - + auto callee_and_this = TRY(get_callee_and_this_from_environment(interpreter, interpreter.current_executable().get_identifier(m_identifier), m_cache_index)); + interpreter.reg(m_callee_reg) = callee_and_this.callee; + interpreter.reg(m_this_reg) = callee_and_this.this_value; return {}; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index c3bec8b25e..5334432e06 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -470,6 +470,8 @@ public: IdentifierTableIndex identifier() const { return m_identifier; } u32 cache_index() const { return m_cache_index; } + Register callee() const { return m_callee_reg; } + Register this_() const { return m_this_reg; } private: IdentifierTableIndex m_identifier; diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index 1fdbaac0ad..92d7f5033f 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -674,6 +674,37 @@ void Compiler::compile_get_variable(Bytecode::Op::GetVariable const& op) check_exception(); } +static Value cxx_get_callee_and_this_from_environment(VM& vm, DeprecatedFlyString const& name, u32 cache_index, Bytecode::Register callee_reg, Bytecode::Register this_reg) +{ + auto& bytecode_interpreter = vm.bytecode_interpreter(); + auto callee_and_this = TRY_OR_SET_EXCEPTION(Bytecode::get_callee_and_this_from_environment( + bytecode_interpreter, + name, + cache_index)); + + bytecode_interpreter.reg(callee_reg) = callee_and_this.callee; + bytecode_interpreter.reg(this_reg) = callee_and_this.this_value; + return {}; +} + +void Compiler::compile_get_callee_and_this_from_environment(Bytecode::Op::GetCalleeAndThisFromEnvironment const& op) +{ + m_assembler.mov( + Assembler::Operand::Register(ARG1), + Assembler::Operand::Imm64(bit_cast(&m_bytecode_executable.get_identifier(op.identifier())))); + m_assembler.mov( + Assembler::Operand::Register(ARG2), + Assembler::Operand::Imm64(op.cache_index())); + m_assembler.mov( + Assembler::Operand::Register(ARG3), + Assembler::Operand::Imm64(op.callee().index())); + m_assembler.mov( + Assembler::Operand::Register(ARG4), + Assembler::Operand::Imm64(op.this_().index())); + m_assembler.native_call((void*)cxx_get_callee_and_this_from_environment); + check_exception(); +} + static Value cxx_to_numeric(VM& vm, Value value) { return TRY_OR_SET_EXCEPTION(value.to_numeric(vm)); @@ -924,6 +955,9 @@ OwnPtr Compiler::compile(Bytecode::Executable& bytecode_execut case Bytecode::Instruction::Type::GetVariable: compiler.compile_get_variable(static_cast(op)); break; + case Bytecode::Instruction::Type::GetCalleeAndThisFromEnvironment: + compiler.compile_get_callee_and_this_from_environment(static_cast(op)); + break; case Bytecode::Instruction::Type::PutById: compiler.compile_put_by_id(static_cast(op)); break; diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index afd4ff74ca..846e006a66 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -96,6 +96,7 @@ private: void compile_get_by_value(Bytecode::Op::GetByValue const&); void compile_get_global(Bytecode::Op::GetGlobal const&); void compile_get_variable(Bytecode::Op::GetVariable const&); + void compile_get_callee_and_this_from_environment(Bytecode::Op::GetCalleeAndThisFromEnvironment const&); void compile_put_by_id(Bytecode::Op::PutById const&); void compile_put_by_value(Bytecode::Op::PutByValue const&);