From d79438a2a69613f738a4cdab8a54fb6b5505db41 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Sun, 12 May 2024 18:49:03 +0200 Subject: [PATCH] LibJS: Join locals, constants and registers into single vector Merging registers, constants and locals into single vector means: - Better data locality - No need to check type in Interpreter::get() and Interpreter::set() which are very hot functions Performance improvement is visible in almost all Octane and Kraken tests. --- Userland/Libraries/LibJS/AST.cpp | 5 +- .../Libraries/LibJS/Bytecode/Generator.cpp | 42 ++ .../Libraries/LibJS/Bytecode/Instruction.cpp | 16 + .../Libraries/LibJS/Bytecode/Instruction.h | 2 + .../Libraries/LibJS/Bytecode/Interpreter.cpp | 52 +-- .../Libraries/LibJS/Bytecode/Interpreter.h | 11 +- Userland/Libraries/LibJS/Bytecode/Op.h | 388 +++++++++++++++++- Userland/Libraries/LibJS/Bytecode/Operand.h | 2 + .../Runtime/ECMAScriptFunctionObject.cpp | 6 +- .../LibJS/Runtime/ExecutionContext.cpp | 6 +- .../LibJS/Runtime/ExecutionContext.h | 5 +- 11 files changed, 478 insertions(+), 57 deletions(-) diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index deadf11ddea..223a33a749e 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -1624,7 +1624,10 @@ void ScopeNode::block_declaration_instantiation(VM& vm, Environment* environment // iii. Perform ! env.InitializeBinding(fn, fo). NOTE: This step is replaced in section B.3.2.6. if (function_declaration.name_identifier()->is_local()) { - vm.running_execution_context().local(function_declaration.name_identifier()->local_variable_index()) = function; + auto& running_execution_context = vm.running_execution_context(); + auto number_of_registers = running_execution_context.executable->number_of_registers; + auto number_of_constants = running_execution_context.executable->constants.size(); + running_execution_context.local(function_declaration.name_identifier()->local_variable_index() + number_of_registers + number_of_constants) = function; } else { VERIFY(is(*environment)); static_cast(*environment).initialize_or_set_mutable_binding({}, vm, function_declaration.name(), function); diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 2f6d611fc36..75b1a2ffbab 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -266,6 +266,19 @@ CodeGenerationErrorOr> Generator::emit_function_body_by HashMap source_map; + for (auto& block : generator.m_root_basic_blocks) { + if (!block->is_terminated()) { + // NOTE: We must ensure that the "undefined" constant, which will be used by the not yet + // emitted End instruction, is taken into account while shifting local operands by the + // number of constants. + (void)generator.add_constant(js_undefined()); + break; + } + } + + auto number_of_registers = generator.m_next_register; + auto number_of_constants = generator.m_constants.size(); + for (auto& block : generator.m_root_basic_blocks) { basic_block_start_offsets.append(bytecode.size()); if (block->handler() || block->finalizer()) { @@ -287,6 +300,21 @@ CodeGenerationErrorOr> Generator::emit_function_body_by while (!it.at_end()) { auto& instruction = const_cast(*it); + instruction.visit_operands([number_of_registers, number_of_constants](Operand& operand) { + switch (operand.type()) { + case Operand::Type::Register: + break; + case Operand::Type::Local: + operand.offset_index_by(number_of_registers + number_of_constants); + break; + case Operand::Type::Constant: + operand.offset_index_by(number_of_registers); + break; + default: + VERIFY_NOT_REACHED(); + } + }); + // OPTIMIZATION: Don't emit jumps that just jump to the next block. if (instruction.type() == Instruction::Type::Jump) { auto& jump = static_cast(instruction); @@ -333,6 +361,20 @@ CodeGenerationErrorOr> Generator::emit_function_body_by } if (!block->is_terminated()) { Op::End end(generator.add_constant(js_undefined())); + end.visit_operands([number_of_registers, number_of_constants](Operand& operand) { + switch (operand.type()) { + case Operand::Type::Register: + break; + case Operand::Type::Local: + operand.offset_index_by(number_of_registers + number_of_constants); + break; + case Operand::Type::Constant: + operand.offset_index_by(number_of_registers); + break; + default: + VERIFY_NOT_REACHED(); + } + }); bytecode.append(reinterpret_cast(&end), end.length()); } if (block->handler() || block->finalizer()) { diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.cpp b/Userland/Libraries/LibJS/Bytecode/Instruction.cpp index ac3462f7443..9632bd143d8 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.cpp @@ -42,6 +42,22 @@ void Instruction::visit_labels(Function visitor) #undef __BYTECODE_OP } +void Instruction::visit_operands(Function visitor) +{ +#define __BYTECODE_OP(op) \ + case Type::op: \ + static_cast(*this).visit_operands_impl(move(visitor)); \ + return; + + switch (type()) { + ENUMERATE_BYTECODE_OPS(__BYTECODE_OP) + default: + VERIFY_NOT_REACHED(); + } + +#undef __BYTECODE_OP +} + template concept HasVariableLength = Op::IsVariableLength; diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index d02b08fc818..2999f164bb4 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -157,6 +157,7 @@ public: size_t length() const; ByteString to_byte_string(Bytecode::Executable const&) const; void visit_labels(Function visitor); + void visit_operands(Function visitor); static void destroy(Instruction&); protected: @@ -166,6 +167,7 @@ protected: } void visit_labels_impl(Function) { } + void visit_operands_impl(Function) { } private: Type m_type {}; diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index b3f27ff30b7..c0e01a57560 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -54,7 +54,7 @@ static ByteString format_operand(StringView name, Operand operand, Bytecode::Exe break; case Operand::Type::Constant: { builder.append("\033[36m"sv); - auto value = executable.constants[operand.index()]; + auto value = executable.constants[operand.index() - executable.number_of_registers]; if (value.is_empty()) builder.append(""sv); else if (value.is_boolean()) @@ -153,30 +153,12 @@ Interpreter::~Interpreter() ALWAYS_INLINE Value Interpreter::get(Operand op) const { - switch (op.type()) { - case Operand::Type::Register: - return m_registers.data()[op.index()]; - case Operand::Type::Local: - return m_locals.data()[op.index()]; - case Operand::Type::Constant: - return m_constants.data()[op.index()]; - } - __builtin_unreachable(); + return m_registers_and_constants_and_locals.data()[op.index()]; } ALWAYS_INLINE void Interpreter::set(Operand op, Value value) { - switch (op.type()) { - case Operand::Type::Register: - m_registers.data()[op.index()] = value; - return; - case Operand::Type::Local: - m_locals.data()[op.index()] = value; - return; - case Operand::Type::Constant: - break; - } - __builtin_unreachable(); + m_registers_and_constants_and_locals.data()[op.index()] = value; } // 16.1.6 ScriptEvaluation ( scriptRecord ), https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation @@ -346,7 +328,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point) auto& running_execution_context = this->running_execution_context(); auto* arguments = running_execution_context.arguments.data(); - auto* locals = running_execution_context.locals.data(); + auto* registers_and_constants_and_locals = running_execution_context.registers_and_constants_and_locals.data(); auto& accumulator = this->accumulator(); auto& executable = current_executable(); auto const* bytecode = executable.bytecode.data(); @@ -384,7 +366,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point) handle_SetLocal: { auto& instruction = *reinterpret_cast(&bytecode[program_counter]); - locals[instruction.index()] = get(instruction.src()); + registers_and_constants_and_locals[instruction.index()] = get(instruction.src()); DISPATCH_NEXT(SetLocal); } @@ -715,31 +697,35 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe VERIFY(!vm().execution_context_stack().is_empty()); auto& running_execution_context = vm().running_execution_context(); - if (running_execution_context.registers.size() < executable.number_of_registers) - running_execution_context.registers.resize(executable.number_of_registers); + u32 registers_and_contants_count = executable.number_of_registers + executable.constants.size(); + if (running_execution_context.registers_and_constants_and_locals.size() < registers_and_contants_count) + running_execution_context.registers_and_constants_and_locals.resize(registers_and_contants_count); TemporaryChange restore_running_execution_context { m_running_execution_context, &running_execution_context }; TemporaryChange restore_arguments { m_arguments, running_execution_context.arguments.span() }; - TemporaryChange restore_registers { m_registers, running_execution_context.registers.span() }; - TemporaryChange restore_locals { m_locals, running_execution_context.locals.span() }; - TemporaryChange restore_constants { m_constants, executable.constants.span() }; + TemporaryChange restore_registers_and_constants_and_locals { m_registers_and_constants_and_locals, running_execution_context.registers_and_constants_and_locals.span() }; reg(Register::accumulator()) = initial_accumulator_value; reg(Register::return_value()) = {}; running_execution_context.executable = &executable; + for (size_t i = 0; i < executable.constants.size(); ++i) { + running_execution_context.registers_and_constants_and_locals[executable.number_of_registers + i] = executable.constants[i]; + } + run_bytecode(entry_point.value_or(0)); dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter did run unit {:p}", &executable); if constexpr (JS_BYTECODE_DEBUG) { - for (size_t i = 0; i < registers().size(); ++i) { + auto const& registers_and_constants_and_locals = running_execution_context.registers_and_constants_and_locals; + for (size_t i = 0; i < executable.number_of_registers; ++i) { String value_string; - if (registers()[i].is_empty()) + if (registers_and_constants_and_locals[i].is_empty()) value_string = "(empty)"_string; else - value_string = registers()[i].to_string_without_side_effects(); + value_string = registers_and_constants_and_locals[i].to_string_without_side_effects(); dbgln("[{:3}] {}", i, value_string); } } @@ -758,8 +744,8 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe vm().finish_execution_generation(); if (!exception.is_empty()) - return { throw_completion(exception), running_execution_context.registers[0] }; - return { return_value, running_execution_context.registers[0] }; + return { throw_completion(exception), running_execution_context.registers_and_constants_and_locals[0] }; + return { return_value, running_execution_context.registers_and_constants_and_locals[0] }; } void Interpreter::enter_unwind_context() diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index 0153403bade..ee1e5c47326 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -49,11 +49,11 @@ public: ALWAYS_INLINE Value& saved_return_value() { return reg(Register::saved_return_value()); } Value& reg(Register const& r) { - return m_registers.data()[r.index()]; + return m_registers_and_constants_and_locals.data()[r.index()]; } Value reg(Register const& r) const { - return m_registers.data()[r.index()]; + return m_registers_and_constants_and_locals.data()[r.index()]; } [[nodiscard]] Value get(Operand) const; @@ -77,9 +77,6 @@ public: Executable const& current_executable() const { return *m_current_executable; } Optional program_counter() const { return m_program_counter; } - Vector& registers() { return vm().running_execution_context().registers; } - Vector const& registers() const { return vm().running_execution_context().registers; } - ExecutionContext& running_execution_context() { return *m_running_execution_context; } private: @@ -99,9 +96,7 @@ private: GCPtr m_global_declarative_environment { nullptr }; Optional m_program_counter; Span m_arguments; - Span m_registers; - Span m_locals; - Span m_constants; + Span m_registers_and_constants_and_locals; ExecutionContext* m_running_execution_context { nullptr }; }; diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 0ed10ef1ea3..485f0e75bf2 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -43,6 +43,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + } private: Operand m_dst; @@ -82,6 +86,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_src); + } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -130,6 +139,12 @@ private: \ ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ ByteString to_byte_string_impl(Bytecode::Executable const&) const; \ + void visit_operands_impl(Function visitor) \ + { \ + visitor(m_dst); \ + visitor(m_lhs); \ + visitor(m_rhs); \ + } \ \ Operand dst() const { return m_dst; } \ Operand lhs() const { return m_lhs; } \ @@ -164,6 +179,11 @@ JS_ENUMERATE_COMMON_BINARY_OPS_WITH_FAST_PATH(JS_DECLARE_COMMON_BINARY_OP) \ ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ ByteString to_byte_string_impl(Bytecode::Executable const&) const; \ + void visit_operands_impl(Function visitor) \ + { \ + visitor(m_dst); \ + visitor(m_src); \ + } \ \ Operand dst() const { return m_dst; } \ Operand src() const { return m_src; } \ @@ -186,6 +206,10 @@ public: void 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; } @@ -206,6 +230,10 @@ public: void 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; } StringTableIndex source_index() const { return m_source_index; } @@ -234,6 +262,10 @@ private: \ void 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; } \ StringTableIndex error_string() const { return m_error_string; } \ @@ -263,6 +295,13 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_from_object); + for (size_t i = 0; i < m_excluded_names_count; i++) + visitor(m_excluded_names[i]); + } size_t length_impl() const { @@ -304,6 +343,12 @@ public: void execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + for (size_t i = 0; i < m_element_count; i++) + visitor(m_elements[i]); + } Operand dst() const { return m_dst; } @@ -340,6 +385,10 @@ public: void 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; } ReadonlySpan elements() const { return { m_elements, m_element_count }; } @@ -377,6 +426,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_src); + } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -400,6 +454,12 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_specifier); + visitor(m_options); + } Operand dst() const { return m_dst; } Operand specifier() const { return m_specifier; } @@ -426,6 +486,12 @@ public: Operand dst() const { return m_dst; } Operand iterator() const { return m_iterator; } + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_iterator); + } + private: Operand m_dst; Operand m_iterator; @@ -446,6 +512,12 @@ public: Operand dst() const { return m_dst; } Operand src() const { return m_src; } + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_src); + } + private: Operand m_dst; Operand m_src; @@ -510,6 +582,11 @@ public: Operand object() const { return m_object; } + void visit_operands_impl(Function visitor) + { + visitor(m_object); + } + private: Operand m_object; }; @@ -527,6 +604,11 @@ public: Operand dst() const { return m_dst; } + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + } + private: Operand m_dst; }; @@ -599,6 +681,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_src); + } IdentifierTableIndex identifier() const { return m_identifier; } Operand src() const { return m_src; } @@ -617,20 +703,25 @@ class SetLocal final : public Instruction { public: SetLocal(size_t index, Operand src) : Instruction(Type::SetLocal) - , m_index(index) + , m_dst(Operand(Operand::Type::Local, index)) , m_src(src) { } ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_src); + } - u32 index() const { return m_index; } - Operand dst() const { return Operand(Operand::Type::Local, m_index); } + u32 index() const { return m_dst.index(); } + Operand dst() const { return m_dst; } Operand src() const { return m_src; } private: - u32 m_index; + Operand m_dst; Operand m_src; }; @@ -645,6 +736,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_src); + } size_t index() const { return m_index; } Operand src() const { return m_src; } @@ -665,6 +760,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + } u32 index() const { return m_index; } Operand dst() const { return m_dst; } @@ -686,6 +785,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_callee); + visitor(m_this_value); + } IdentifierTableIndex identifier() const { return m_identifier; } Operand callee() const { return m_callee; } @@ -713,6 +817,11 @@ public: Operand dst() const { return m_dst; } IdentifierTableIndex identifier() const { return m_identifier; } + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + } + private: Operand m_dst; IdentifierTableIndex m_identifier; @@ -736,6 +845,11 @@ public: IdentifierTableIndex identifier() const { return m_identifier; } u32 cache_index() const { return m_cache_index; } + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + } + private: Operand m_dst; IdentifierTableIndex m_identifier; @@ -757,6 +871,11 @@ public: Operand dst() const { return m_dst; } IdentifierTableIndex identifier() const { return m_identifier; } + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + } + private: Operand m_dst; IdentifierTableIndex m_identifier; @@ -776,6 +895,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -804,6 +928,12 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + visitor(m_this_value); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -831,6 +961,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -854,6 +989,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -889,6 +1029,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_base); + visitor(m_src); + } Operand base() const { return m_base; } IdentifierTableIndex property() const { return m_property; } @@ -920,6 +1065,12 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_base); + visitor(m_this_value); + visitor(m_src); + } Operand base() const { return m_base; } Operand this_value() const { return m_this_value; } @@ -950,6 +1101,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_base); + visitor(m_src); + } Operand base() const { return m_base; } IdentifierTableIndex property() const { return m_property; } @@ -974,6 +1130,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -998,6 +1159,12 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + visitor(m_this_value); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -1024,6 +1191,12 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + visitor(m_property); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -1051,6 +1224,13 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + visitor(m_property); + visitor(m_this_value); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -1078,6 +1258,12 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_base); + visitor(m_property); + visitor(m_src); + } Operand base() const { return m_base; } Operand property() const { return m_property; } @@ -1106,6 +1292,13 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_base); + visitor(m_property); + visitor(m_this_value); + visitor(m_src); + } Operand base() const { return m_base; } Operand property() const { return m_property; } @@ -1133,6 +1326,12 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + visitor(m_property); + } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -1162,6 +1361,13 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_base); + visitor(m_this_value); + visitor(m_property); + } private: Operand m_dst; @@ -1212,6 +1418,10 @@ public: visitor(m_true_target); visitor(m_false_target); } + void visit_operands_impl(Function visitor) + { + visitor(m_condition); + } Operand condition() const { return m_condition; } auto& true_target() const { return m_true_target; } @@ -1240,6 +1450,10 @@ public: { visitor(m_target); } + void visit_operands_impl(Function visitor) + { + visitor(m_condition); + } Operand condition() const { return m_condition; } auto& target() const { return m_target; } @@ -1266,6 +1480,10 @@ public: { visitor(m_target); } + void visit_operands_impl(Function visitor) + { + visitor(m_condition); + } Operand condition() const { return m_condition; } auto& target() const { return m_target; } @@ -1305,6 +1523,11 @@ private: { \ visitor(m_true_target); \ visitor(m_false_target); \ + } \ + void visit_operands_impl(Function visitor) \ + { \ + visitor(m_lhs); \ + visitor(m_rhs); \ } \ \ Operand lhs() const { return m_lhs; } \ @@ -1340,6 +1563,10 @@ public: visitor(m_true_target); visitor(m_false_target); } + void visit_operands_impl(Function visitor) + { + visitor(m_condition); + } Operand condition() const { return m_condition; } auto& true_target() const { return m_true_target; } @@ -1370,6 +1597,10 @@ public: visitor(m_true_target); visitor(m_false_target); } + void visit_operands_impl(Function visitor) + { + visitor(m_condition); + } Operand condition() const { return m_condition; } auto& true_target() const { return m_true_target; } @@ -1422,6 +1653,14 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_callee); + visitor(m_this_value); + for (size_t i = 0; i < m_argument_count; i++) + visitor(m_arguments[i]); + } private: Operand m_dst; @@ -1456,6 +1695,13 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_callee); + visitor(m_this_value); + visitor(m_arguments); + } private: Operand m_dst; @@ -1478,6 +1724,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_arguments); + } Operand dst() const { return m_dst; } Operand arguments() const { return m_arguments; } @@ -1514,6 +1765,16 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + if (m_super_class.has_value()) + visitor(m_super_class.value()); + for (size_t i = 0; i < m_element_keys_count; i++) { + if (m_element_keys[i].has_value()) + visitor(m_element_keys[i].value()); + } + } Operand dst() const { return m_dst; } Optional const& super_class() const { return m_super_class; } @@ -1542,6 +1803,12 @@ public: void execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + if (m_home_object.has_value()) + visitor(m_home_object.value()); + } Operand dst() const { return m_dst; } FunctionNode const& function_node() const { return m_function_node; } @@ -1584,6 +1851,11 @@ public: void execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + if (m_value.has_value()) + visitor(m_value.value()); + } Optional const& value() const { return m_value; } @@ -1601,6 +1873,10 @@ public: 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; } @@ -1619,6 +1895,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_src); + } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -1638,6 +1919,10 @@ public: 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; } @@ -1656,6 +1941,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_src); + } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -1677,6 +1967,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_src); + } Operand src() const { return m_src; } @@ -1694,6 +1988,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_src); + } Operand src() const { return m_src; } @@ -1711,6 +2009,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_src); + } Operand src() const { return m_src; } @@ -1728,6 +2030,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_src); + } Operand src() const { return m_src; } @@ -1863,6 +2169,10 @@ public: if (m_continuation_label.has_value()) visitor(m_continuation_label.value()); } + void visit_operands_impl(Function visitor) + { + visitor(m_value); + } auto& continuation() const { return m_continuation_label; } Operand value() const { return m_value; } @@ -1889,6 +2199,10 @@ public: { visitor(m_continuation_label); } + void visit_operands_impl(Function visitor) + { + visitor(m_argument); + } auto& continuation() const { return m_continuation_label; } Operand argument() const { return m_argument; } @@ -1910,6 +2224,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_iterable); + } Operand dst() const { return m_dst; } Operand iterable() const { return m_iterable; } @@ -1932,6 +2251,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_object); + visitor(m_iterator_record); + } Operand object() const { return m_object; } Operand iterator_record() const { return m_iterator_record; } @@ -1952,6 +2276,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_next_method); + visitor(m_iterator_record); + } Operand next_method() const { return m_next_method; } Operand iterator_record() const { return m_iterator_record; } @@ -1973,6 +2302,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_object); + } Operand dst() const { return m_dst; } Operand object() const { return m_object; } @@ -1995,6 +2329,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_object); + } Operand dst() const { return m_dst; } Operand object() const { return m_object; } @@ -2016,6 +2355,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_iterator_record); + } Operand iterator_record() const { return m_iterator_record; } Completion::Type completion_type() const { return m_completion_type; } @@ -2039,6 +2382,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_iterator_record); + } Operand iterator_record() const { return m_iterator_record; } Completion::Type completion_type() const { return m_completion_type; } @@ -2061,6 +2408,11 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_dst); + visitor(m_iterator_record); + } Operand dst() const { return m_dst; } Operand iterator_record() const { return m_iterator_record; } @@ -2080,6 +2432,10 @@ public: 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; } @@ -2097,6 +2453,10 @@ public: 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; } @@ -2114,6 +2474,10 @@ public: void 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; } @@ -2131,6 +2495,10 @@ public: void 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; } @@ -2149,6 +2517,10 @@ public: 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; } IdentifierTableIndex identifier() const { return m_identifier; } @@ -2170,6 +2542,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_value); + } Operand value() const { return m_value; } @@ -2188,6 +2564,10 @@ public: void execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void visit_operands_impl(Function visitor) + { + visitor(m_value); + } private: StringView m_text; diff --git a/Userland/Libraries/LibJS/Bytecode/Operand.h b/Userland/Libraries/LibJS/Bytecode/Operand.h index 89482af46c5..e07a7de453d 100644 --- a/Userland/Libraries/LibJS/Bytecode/Operand.h +++ b/Userland/Libraries/LibJS/Bytecode/Operand.h @@ -38,6 +38,8 @@ public: [[nodiscard]] Register as_register() const; + void offset_index_by(u32 offset) { m_index += offset; } + private: Type m_type {}; u32 m_index { 0 }; diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 822450d0163..f859f4c98f3 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -380,8 +380,6 @@ ThrowCompletionOr ECMAScriptFunctionObject::internal_call(Value this_argu auto callee_context = ExecutionContext::create(heap()); - callee_context->locals.resize(m_local_variables_names.size()); - // Non-standard callee_context->arguments.ensure_capacity(max(arguments_list.size(), m_formal_parameters.size())); callee_context->arguments.append(arguments_list.data(), arguments_list.size()); @@ -457,8 +455,6 @@ ThrowCompletionOr> ECMAScriptFunctionObject::internal_const auto callee_context = ExecutionContext::create(heap()); - callee_context->locals.resize(m_local_variables_names.size()); - // Non-standard callee_context->arguments.ensure_capacity(max(arguments_list.size(), m_formal_parameters.size())); callee_context->arguments.append(arguments_list.data(), arguments_list.size()); @@ -841,6 +837,8 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body() m_bytecode_executable = m_ecmascript_code->bytecode_executable(); } + vm.running_execution_context().registers_and_constants_and_locals.resize(m_local_variables_names.size() + m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size()); + auto result_and_frame = vm.bytecode_interpreter().run_executable(*m_bytecode_executable, {}); if (result_and_frame.value.is_error()) diff --git a/Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp b/Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp index 7208d0d5a31..7094d132c57 100644 --- a/Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp +++ b/Userland/Libraries/LibJS/Runtime/ExecutionContext.cpp @@ -43,8 +43,7 @@ NonnullOwnPtr ExecutionContext::copy() const copy->executable = executable; copy->arguments = arguments; copy->passed_argument_count = passed_argument_count; - copy->locals = locals; - copy->registers = registers; + copy->registers_and_constants_and_locals = registers_and_constants_and_locals; copy->unwind_contexts = unwind_contexts; copy->saved_lexical_environments = saved_lexical_environments; copy->previously_scheduled_jumps = previously_scheduled_jumps; @@ -63,8 +62,7 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor) visitor.visit(executable); visitor.visit(function_name); visitor.visit(arguments); - visitor.visit(locals); - visitor.visit(registers); + visitor.visit(registers_and_constants_and_locals); for (auto& context : unwind_contexts) { visitor.visit(context.lexical_environment); } diff --git a/Userland/Libraries/LibJS/Runtime/ExecutionContext.h b/Userland/Libraries/LibJS/Runtime/ExecutionContext.h index 55bfb3e51b1..4b7694c92ab 100644 --- a/Userland/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Userland/Libraries/LibJS/Runtime/ExecutionContext.h @@ -70,14 +70,13 @@ public: Value& local(size_t index) { - return locals[index]; + return registers_and_constants_and_locals[index]; } u32 passed_argument_count { 0 }; Vector arguments; - Vector locals; - Vector registers; + Vector registers_and_constants_and_locals; Vector unwind_contexts; Vector> previously_scheduled_jumps; Vector> saved_lexical_environments;