diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index 289fbcb0f3f..82ba095d65e 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -741,11 +741,11 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe auto& running_execution_context = vm().running_execution_context(); u32 registers_and_constants_and_locals_count = executable.number_of_registers + executable.constants.size() + executable.local_variable_names.size(); - VERIFY(registers_and_constants_and_locals_count <= running_execution_context.registers_and_constants_and_locals_and_arguments.size()); + VERIFY(registers_and_constants_and_locals_count <= running_execution_context.registers_and_constants_and_locals_and_arguments_span().size()); TemporaryChange restore_running_execution_context { m_running_execution_context, &running_execution_context }; TemporaryChange restore_arguments { m_arguments, running_execution_context.arguments() }; - TemporaryChange restore_registers_and_constants_and_locals { m_registers_and_constants_and_locals, running_execution_context.registers_and_constants_and_locals_and_arguments.span() }; + TemporaryChange restore_registers_and_constants_and_locals { m_registers_and_constants_and_locals, running_execution_context.registers_and_constants_and_locals_and_arguments_span() }; reg(Register::accumulator()) = initial_accumulator_value; reg(Register::return_value()) = js_special_empty_value(); @@ -759,8 +759,9 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe running_execution_context.executable = &executable; + auto* registers_and_constants_and_locals_and_arguments = running_execution_context.registers_and_constants_and_locals_and_arguments(); for (size_t i = 0; i < executable.constants.size(); ++i) { - running_execution_context.registers_and_constants_and_locals_and_arguments[executable.number_of_registers + i] = executable.constants[i]; + registers_and_constants_and_locals_and_arguments[executable.number_of_registers + i] = executable.constants[i]; } run_bytecode(entry_point.value_or(0)); @@ -768,7 +769,6 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter did run unit {:p}", &executable); if constexpr (JS_BYTECODE_DEBUG) { - auto const& registers_and_constants_and_locals_and_arguments = running_execution_context.registers_and_constants_and_locals_and_arguments; for (size_t i = 0; i < executable.number_of_registers; ++i) { String value_string; if (registers_and_constants_and_locals_and_arguments[i].is_special_empty_value()) @@ -788,8 +788,8 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe vm().finish_execution_generation(); if (!exception.is_special_empty_value()) - return { throw_completion(exception), running_execution_context.registers_and_constants_and_locals_and_arguments[0] }; - return { return_value, running_execution_context.registers_and_constants_and_locals_and_arguments[0] }; + return { throw_completion(exception), registers_and_constants_and_locals_and_arguments[0] }; + return { return_value, registers_and_constants_and_locals_and_arguments[0] }; } void Interpreter::enter_unwind_context() diff --git a/Libraries/LibJS/Runtime/ExecutionContext.cpp b/Libraries/LibJS/Runtime/ExecutionContext.cpp index cd523b9acac..4b88bf6ff4d 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.cpp +++ b/Libraries/LibJS/Runtime/ExecutionContext.cpp @@ -2,6 +2,7 @@ * Copyright (c) 2020-2024, Andreas Kling * Copyright (c) 2020-2021, Linus Groh * Copyright (c) 2022, Luke Wilde + * Copyright (c) 2024-2025, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -15,39 +16,96 @@ namespace JS { class ExecutionContextAllocator { public: - NonnullOwnPtr allocate() + NonnullOwnPtr allocate(u32 registers_and_constants_and_locals_count, u32 arguments_count) { - if (m_execution_contexts.is_empty()) - return adopt_own(*new ExecutionContext); - void* slot = m_execution_contexts.take_last(); - return adopt_own(*new (slot) ExecutionContext); + auto tail_size = registers_and_constants_and_locals_count + arguments_count; + + void* slot = nullptr; + if (tail_size <= 4 && !m_execution_contexts_with_4_tail.is_empty()) { + slot = m_execution_contexts_with_4_tail.take_last(); + } else if (tail_size <= 16 && !m_execution_contexts_with_16_tail.is_empty()) { + slot = m_execution_contexts_with_16_tail.take_last(); + } else if (tail_size <= 64 && !m_execution_contexts_with_64_tail.is_empty()) { + slot = m_execution_contexts_with_64_tail.take_last(); + } else if (tail_size <= 128 && !m_execution_contexts_with_128_tail.is_empty()) { + slot = m_execution_contexts_with_128_tail.take_last(); + } else if (tail_size <= 256 && !m_execution_contexts_with_256_tail.is_empty()) { + slot = m_execution_contexts_with_256_tail.take_last(); + } else if (tail_size <= 512 && !m_execution_contexts_with_512_tail.is_empty()) { + slot = m_execution_contexts_with_512_tail.take_last(); + } + + if (slot) { + return adopt_own(*new (slot) ExecutionContext(registers_and_constants_and_locals_count, arguments_count)); + } + + auto tail_allocation_size = [tail_size] -> u32 { + if (tail_size <= 4) + return 4; + if (tail_size <= 16) + return 16; + if (tail_size <= 64) + return 64; + if (tail_size <= 128) + return 128; + if (tail_size <= 256) + return 256; + if (tail_size <= 512) + return 512; + return tail_size; + }; + + auto* memory = ::operator new(sizeof(ExecutionContext) + tail_allocation_size() * sizeof(Value)); + return adopt_own(*::new (memory) ExecutionContext(registers_and_constants_and_locals_count, arguments_count)); } - void deallocate(void* ptr) + void deallocate(void* ptr, u32 tail_size) { - m_execution_contexts.append(ptr); + if (tail_size <= 4) { + m_execution_contexts_with_4_tail.append(ptr); + } else if (tail_size <= 16) { + m_execution_contexts_with_16_tail.append(ptr); + } else if (tail_size <= 64) { + m_execution_contexts_with_64_tail.append(ptr); + } else if (tail_size <= 128) { + m_execution_contexts_with_128_tail.append(ptr); + } else if (tail_size <= 256) { + m_execution_contexts_with_256_tail.append(ptr); + } else if (tail_size <= 512) { + m_execution_contexts_with_512_tail.append(ptr); + } else { + ::operator delete(ptr); + } } private: - Vector m_execution_contexts; + Vector m_execution_contexts_with_4_tail; + Vector m_execution_contexts_with_16_tail; + Vector m_execution_contexts_with_64_tail; + Vector m_execution_contexts_with_128_tail; + Vector m_execution_contexts_with_256_tail; + Vector m_execution_contexts_with_512_tail; }; static NeverDestroyed s_execution_context_allocator; NonnullOwnPtr ExecutionContext::create(u32 registers_and_constants_and_locals_count, u32 arguments_count) { - auto execution_context = s_execution_context_allocator->allocate(); - execution_context->registers_and_constants_and_locals_and_arguments.resize_with_default_value(registers_and_constants_and_locals_count + arguments_count, js_special_empty_value()); - execution_context->arguments_offset = registers_and_constants_and_locals_count; - return execution_context; + return s_execution_context_allocator->allocate(registers_and_constants_and_locals_count, arguments_count); } void ExecutionContext::operator delete(void* ptr) { - s_execution_context_allocator->deallocate(ptr); + auto const* execution_context = static_cast(ptr); + s_execution_context_allocator->deallocate(ptr, execution_context->registers_and_constants_and_locals_and_arguments_count); } -ExecutionContext::ExecutionContext() +ExecutionContext::ExecutionContext(u32 registers_and_constants_and_locals_count, u32 arguments_count) { + registers_and_constants_and_locals_and_arguments_count = registers_and_constants_and_locals_count + arguments_count; + arguments_offset = registers_and_constants_and_locals_count; + auto* registers_and_constants_and_locals_and_arguments = this->registers_and_constants_and_locals_and_arguments(); + for (size_t i = 0; i < registers_and_constants_and_locals_count; ++i) + registers_and_constants_and_locals_and_arguments[i] = js_special_empty_value(); } ExecutionContext::~ExecutionContext() @@ -56,7 +114,7 @@ ExecutionContext::~ExecutionContext() NonnullOwnPtr ExecutionContext::copy() const { - auto copy = create(registers_and_constants_and_locals_and_arguments.size(), arguments().size()); + auto copy = create(registers_and_constants_and_locals_and_arguments_count, arguments().size()); copy->function = function; copy->realm = realm; copy->script_or_module = script_or_module; @@ -70,10 +128,12 @@ NonnullOwnPtr ExecutionContext::copy() const copy->executable = executable; copy->arguments_offset = arguments_offset; copy->passed_argument_count = passed_argument_count; - copy->registers_and_constants_and_locals_and_arguments = registers_and_constants_and_locals_and_arguments; copy->unwind_contexts = unwind_contexts; copy->saved_lexical_environments = saved_lexical_environments; copy->previously_scheduled_jumps = previously_scheduled_jumps; + copy->registers_and_constants_and_locals_and_arguments_count = registers_and_constants_and_locals_and_arguments_count; + for (size_t i = 0; i < registers_and_constants_and_locals_and_arguments_count; ++i) + copy->registers_and_constants_and_locals_and_arguments()[i] = registers_and_constants_and_locals_and_arguments()[i]; return copy; } @@ -89,7 +149,7 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor) visitor.visit(*this_value); visitor.visit(executable); visitor.visit(function_name); - visitor.visit(registers_and_constants_and_locals_and_arguments); + visitor.visit(registers_and_constants_and_locals_and_arguments_span()); for (auto& context : unwind_contexts) { visitor.visit(context.lexical_environment); } diff --git a/Libraries/LibJS/Runtime/ExecutionContext.h b/Libraries/LibJS/Runtime/ExecutionContext.h index 25a66936f7c..5ae9f5cd838 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Libraries/LibJS/Runtime/ExecutionContext.h @@ -2,6 +2,7 @@ * Copyright (c) 2020-2024, Andreas Kling * Copyright (c) 2020-2021, Linus Groh * Copyright (c) 2022, Luke Wilde + * Copyright (c) 2024-2025, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -42,7 +43,7 @@ struct ExecutionContext { private: friend class ExecutionContextAllocator; - ExecutionContext(); + ExecutionContext(u32 registers_and_constants_and_locals_count, u32 arguments_count); public: void operator delete(void* ptr); @@ -70,17 +71,27 @@ public: // FIXME: Move this out of LibJS (e.g. by using the CustomData concept), as it's used exclusively by LibWeb. size_t skip_when_determining_incumbent_counter { 0 }; + Span registers_and_constants_and_locals_and_arguments_span() + { + return { registers_and_constants_and_locals_and_arguments(), registers_and_constants_and_locals_and_arguments_count }; + } + + Value const* registers_and_constants_and_locals_and_arguments() const + { + return reinterpret_cast(reinterpret_cast(this) + sizeof(ExecutionContext)); + } + Value argument(size_t index) const { - auto arguments_size = registers_and_constants_and_locals_and_arguments.size() - arguments_offset; + auto arguments_size = registers_and_constants_and_locals_and_arguments_count - arguments_offset; if (index >= arguments_size) [[unlikely]] return js_undefined(); - return registers_and_constants_and_locals_and_arguments[arguments_offset + index]; + return registers_and_constants_and_locals_and_arguments()[arguments_offset + index]; } Value& local(size_t index) { - return registers_and_constants_and_locals_and_arguments[index]; + return registers_and_constants_and_locals_and_arguments()[index]; } u32 arguments_offset { 0 }; @@ -89,22 +100,27 @@ public: Span arguments() { - return registers_and_constants_and_locals_and_arguments.span().slice(arguments_offset); + return { registers_and_constants_and_locals_and_arguments() + arguments_offset, registers_and_constants_and_locals_and_arguments_count - arguments_offset }; } ReadonlySpan arguments() const { - return registers_and_constants_and_locals_and_arguments.span().slice(arguments_offset); + return { registers_and_constants_and_locals_and_arguments() + arguments_offset, registers_and_constants_and_locals_and_arguments_count - arguments_offset }; } -private: - friend class Bytecode::Interpreter; - Vector registers_and_constants_and_locals_and_arguments; - -public: Vector unwind_contexts; Vector> previously_scheduled_jumps; Vector> saved_lexical_environments; + +private: + friend class Bytecode::Interpreter; + + Value* registers_and_constants_and_locals_and_arguments() + { + return reinterpret_cast(reinterpret_cast(this) + sizeof(ExecutionContext)); + } + + u32 registers_and_constants_and_locals_and_arguments_count { 0 }; }; struct StackTraceElement {