diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h index 166dbf69a25..efb88cc56cd 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h @@ -58,8 +58,8 @@ public: auto const& source_map() const { return m_source_map; } void add_source_map_entry(size_t bytecode_offset, SourceRecord const& source_record) { m_source_map.set(bytecode_offset, source_record); } - auto const& this_() const { return m_this; } - void set_this(ScopedOperand operand) { m_this = operand; } + [[nodiscard]] bool has_resolved_this() const { return m_has_resolved_this; } + void set_has_resolved_this() { m_has_resolved_this = true; } [[nodiscard]] size_t last_instruction_start_offset() const { return m_last_instruction_start_offset; } void set_last_instruction_start_offset(size_t offset) { m_last_instruction_start_offset = offset; } @@ -73,11 +73,10 @@ private: BasicBlock const* m_finalizer { nullptr }; String m_name; bool m_terminated { false }; + bool m_has_resolved_this { false }; HashMap m_source_map; - Optional m_this; - size_t m_last_instruction_start_offset { 0 }; }; diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 70e6a8a7d56..1247e4ea40f 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -24,6 +24,7 @@ Generator::Generator(VM& vm, GCPtr function, Mus , m_regex_table(make()) , m_constants(vm.heap()) , m_accumulator(*this, Operand(Register::accumulator())) + , m_this_value(*this, Operand(Register::this_value())) , m_must_propagate_completion(must_propagate_completion == MustPropagateCompletion::Yes) , m_function(function) { @@ -571,8 +572,7 @@ CodeGenerationErrorOr Generator::emit_super_refere // https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation // 1. Let env be GetThisEnvironment(). // 2. Let actualThis be ? env.GetThisBinding(). - auto actual_this = allocate_register(); - emit(actual_this); + auto actual_this = get_this(); Optional computed_property_value; @@ -1081,16 +1081,16 @@ void Generator::set_local_initialized(u32 local_index) ScopedOperand Generator::get_this(Optional preferred_dst) { - if (m_current_basic_block->this_().has_value()) - return m_current_basic_block->this_().value(); - if (m_root_basic_blocks[0]->this_().has_value()) { - m_current_basic_block->set_this(m_root_basic_blocks[0]->this_().value()); - return m_root_basic_blocks[0]->this_().value(); + if (m_current_basic_block->has_resolved_this()) + return this_value(); + if (m_root_basic_blocks[0]->has_resolved_this()) { + m_current_basic_block->set_has_resolved_this(); + return this_value(); } auto dst = preferred_dst.has_value() ? preferred_dst.value() : allocate_register(); - emit(dst); - m_current_basic_block->set_this(dst); - return dst; + emit(); + m_current_basic_block->set_has_resolved_this(); + return this_value(); } ScopedOperand Generator::accumulator() @@ -1098,6 +1098,11 @@ ScopedOperand Generator::accumulator() return m_accumulator; } +ScopedOperand Generator::this_value() +{ + return m_this_value; +} + bool Generator::fuse_compare_and_jump(ScopedOperand const& condition, Label true_target, Label false_target) { auto& last_instruction = *reinterpret_cast(m_current_basic_block->data() + m_current_basic_block->last_instruction_start_offset()); diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index a8dc8885392..a686407026c 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -46,6 +46,7 @@ public: [[nodiscard]] ScopedOperand allocate_register(); [[nodiscard]] ScopedOperand local(u32 local_index); [[nodiscard]] ScopedOperand accumulator(); + [[nodiscard]] ScopedOperand this_value(); void free_register(Register); @@ -377,6 +378,7 @@ private: MarkedVector m_constants; ScopedOperand m_accumulator; + ScopedOperand m_this_value; Vector m_free_registers; u32 m_next_register { Register::reserved_register_count }; diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 8416bcda6ab..ddc13403c27 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1563,18 +1563,17 @@ ThrowCompletionOr DeleteByIdWithThis::execute_impl(Bytecode::Interpreter& ThrowCompletionOr ResolveThisBinding::execute_impl(Bytecode::Interpreter& interpreter) const { auto& cached_this_value = interpreter.reg(Register::this_value()); - if (cached_this_value.is_empty()) { - // OPTIMIZATION: Because the value of 'this' cannot be reassigned during a function execution, it's - // resolved once and then saved for subsequent use. - auto& running_execution_context = interpreter.running_execution_context(); - if (auto function = running_execution_context.function; function && is(*function) && !static_cast(*function).allocates_function_environment()) { - cached_this_value = running_execution_context.this_value; - } else { - auto& vm = interpreter.vm(); - cached_this_value = TRY(vm.resolve_this_binding()); - } + if (!cached_this_value.is_empty()) + return {}; + // OPTIMIZATION: Because the value of 'this' cannot be reassigned during a function execution, it's + // resolved once and then saved for subsequent use. + auto& running_execution_context = interpreter.running_execution_context(); + if (auto function = running_execution_context.function; function && is(*function) && !static_cast(*function).allocates_function_environment()) { + cached_this_value = running_execution_context.this_value; + } else { + auto& vm = interpreter.vm(); + cached_this_value = TRY(vm.resolve_this_binding()); } - interpreter.set(dst(), cached_this_value); return {}; } @@ -2655,9 +2654,9 @@ ByteString IteratorNext::to_byte_string_impl(Executable const& executable) const format_operand("iterator_record"sv, m_iterator_record, executable)); } -ByteString ResolveThisBinding::to_byte_string_impl(Bytecode::Executable const& executable) const +ByteString ResolveThisBinding::to_byte_string_impl(Bytecode::Executable const&) const { - return ByteString::formatted("ResolveThisBinding {}", format_operand("dst"sv, m_dst, executable)); + return "ResolveThisBinding"sv; } ByteString ResolveSuperBase::to_byte_string_impl(Bytecode::Executable const& executable) const diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index a4a2c0fea0a..8a674785e12 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -2550,23 +2550,14 @@ private: class ResolveThisBinding final : public Instruction { public: - explicit ResolveThisBinding(Operand dst) + ResolveThisBinding() : Instruction(Type::ResolveThisBinding) - , m_dst(dst) { } ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; - void visit_operands_impl(Function visitor) - { - visitor(m_dst); - } - - Operand dst() const { return m_dst; } - -private: - Operand m_dst; + void visit_operands_impl(Function) { } }; class ResolveSuperBase final : public Instruction { diff --git a/Userland/Libraries/LibJS/Bytecode/ScopedOperand.cpp b/Userland/Libraries/LibJS/Bytecode/ScopedOperand.cpp index 50aa61d3368..69392ebc1f6 100644 --- a/Userland/Libraries/LibJS/Bytecode/ScopedOperand.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ScopedOperand.cpp @@ -11,7 +11,7 @@ namespace JS::Bytecode { ScopedOperandImpl::~ScopedOperandImpl() { - if (!m_generator.is_finished() && m_operand.is_register() && m_operand.as_register().index() != 0) + if (!m_generator.is_finished() && m_operand.is_register() && m_operand.as_register().index() >= Register::reserved_register_count) m_generator.free_register(m_operand.as_register()); }