From e48645c83f44e02febcfda8119417c01d274bb42 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Thu, 24 Apr 2025 01:37:30 +0200 Subject: [PATCH] LibJS: Cache arguments span in ExecutionContext Allows us to avoid doing math in ExecutionContext::argument() --- Libraries/LibJS/Bytecode/Interpreter.cpp | 6 +++--- .../LibJS/Runtime/AsyncFunctionConstructor.cpp | 2 +- .../Runtime/AsyncGeneratorFunctionConstructor.cpp | 2 +- .../LibJS/Runtime/ECMAScriptFunctionObject.cpp | 4 ++-- Libraries/LibJS/Runtime/ExecutionContext.cpp | 4 +++- Libraries/LibJS/Runtime/ExecutionContext.h | 15 +++------------ Libraries/LibJS/Runtime/FunctionConstructor.cpp | 2 +- Libraries/LibJS/Runtime/FunctionPrototype.cpp | 4 ++-- .../Runtime/GeneratorFunctionConstructor.cpp | 2 +- Libraries/LibJS/Runtime/NativeFunction.cpp | 4 ++-- Libraries/LibJS/Runtime/PromiseConstructor.cpp | 2 +- Libraries/LibJS/Runtime/VM.h | 2 +- .../HTML/CrossOrigin/AbstractOperations.cpp | 6 +++--- 13 files changed, 24 insertions(+), 31 deletions(-) diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index 4e7f5938edb..358762db20e 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -374,7 +374,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* arguments = running_execution_context.arguments.data(); auto& accumulator = this->accumulator(); auto& executable = current_executable(); auto const* bytecode = executable.bytecode.data(); @@ -2331,7 +2331,7 @@ ThrowCompletionOr CreateVariable::execute_impl(Bytecode::Interpreter& inte void CreateRestParams::execute_impl(Bytecode::Interpreter& interpreter) const { - auto const arguments = interpreter.running_execution_context().arguments(); + auto const arguments = interpreter.running_execution_context().arguments; auto arguments_count = interpreter.running_execution_context().passed_argument_count; auto array = MUST(Array::create(interpreter.realm(), 0)); for (size_t rest_index = m_rest_index; rest_index < arguments_count; ++rest_index) @@ -2342,7 +2342,7 @@ void CreateRestParams::execute_impl(Bytecode::Interpreter& interpreter) const void CreateArguments::execute_impl(Bytecode::Interpreter& interpreter) const { auto const& function = interpreter.running_execution_context().function; - auto const arguments = interpreter.running_execution_context().arguments(); + auto const arguments = interpreter.running_execution_context().arguments; auto const& environment = interpreter.running_execution_context().lexical_environment; auto passed_arguments = ReadonlySpan { arguments.data(), interpreter.running_execution_context().passed_argument_count }; diff --git a/Libraries/LibJS/Runtime/AsyncFunctionConstructor.cpp b/Libraries/LibJS/Runtime/AsyncFunctionConstructor.cpp index 4a85830ce5a..e37fc15dab1 100644 --- a/Libraries/LibJS/Runtime/AsyncFunctionConstructor.cpp +++ b/Libraries/LibJS/Runtime/AsyncFunctionConstructor.cpp @@ -46,7 +46,7 @@ ThrowCompletionOr> AsyncFunctionConstructor::construct(FunctionO // 2. If bodyArg is not present, set bodyArg to the empty String. // NOTE: This does that, as well as the string extraction done inside of CreateDynamicFunction - auto extracted = TRY(extract_parameter_arguments_and_body(vm, vm.running_execution_context().arguments())); + auto extracted = TRY(extract_parameter_arguments_and_body(vm, vm.running_execution_context().arguments)); // 3. Return ? CreateDynamicFunction(C, NewTarget, async, parameterArgs, bodyArg). return TRY(FunctionConstructor::create_dynamic_function(vm, *constructor, &new_target, FunctionKind::Async, extracted.parameters, extracted.body)); diff --git a/Libraries/LibJS/Runtime/AsyncGeneratorFunctionConstructor.cpp b/Libraries/LibJS/Runtime/AsyncGeneratorFunctionConstructor.cpp index 23128c67cb3..0ed9fd202c1 100644 --- a/Libraries/LibJS/Runtime/AsyncGeneratorFunctionConstructor.cpp +++ b/Libraries/LibJS/Runtime/AsyncGeneratorFunctionConstructor.cpp @@ -47,7 +47,7 @@ ThrowCompletionOr> AsyncGeneratorFunctionConstructor::construct( // 2. If bodyArg is not present, set bodyArg to the empty String. // NOTE: This does that, as well as the string extraction done inside of CreateDynamicFunction - auto extracted = TRY(extract_parameter_arguments_and_body(vm, vm.running_execution_context().arguments())); + auto extracted = TRY(extract_parameter_arguments_and_body(vm, vm.running_execution_context().arguments)); // 3. Return ? CreateDynamicFunction(C, NewTarget, async-generator, parameterArgs, bodyArg). return TRY(FunctionConstructor::create_dynamic_function(vm, *constructor, &new_target, FunctionKind::AsyncGenerator, extracted.parameters, extracted.body)); diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 95866803f0e..87f11fda074 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -506,7 +506,7 @@ ThrowCompletionOr ECMAScriptFunctionObject::internal_call(Value this_argu ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, registers_and_constants_and_locals_count, arguments_count); // Non-standard - auto arguments = callee_context->arguments(); + auto arguments = callee_context->arguments; if (!arguments_list.is_empty()) arguments.overwrite(0, arguments_list.data(), arguments_list.size() * sizeof(Value)); callee_context->passed_argument_count = arguments_list.size(); @@ -578,7 +578,7 @@ ThrowCompletionOr> ECMAScriptFunctionObject::internal_construct( ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, registers_and_constants_and_locals_count, arguments_count); // Non-standard - auto arguments = callee_context->arguments(); + auto arguments = callee_context->arguments; if (!arguments_list.is_empty()) arguments.overwrite(0, arguments_list.data(), arguments_list.size() * sizeof(Value)); callee_context->passed_argument_count = arguments_list.size(); diff --git a/Libraries/LibJS/Runtime/ExecutionContext.cpp b/Libraries/LibJS/Runtime/ExecutionContext.cpp index 4b88bf6ff4d..d1248d22520 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.cpp +++ b/Libraries/LibJS/Runtime/ExecutionContext.cpp @@ -106,6 +106,7 @@ ExecutionContext::ExecutionContext(u32 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(); + arguments = { registers_and_constants_and_locals_and_arguments + arguments_offset, registers_and_constants_and_locals_and_arguments_count - arguments_offset }; } ExecutionContext::~ExecutionContext() @@ -114,7 +115,7 @@ ExecutionContext::~ExecutionContext() NonnullOwnPtr ExecutionContext::copy() const { - auto copy = create(registers_and_constants_and_locals_and_arguments_count, 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; @@ -134,6 +135,7 @@ NonnullOwnPtr ExecutionContext::copy() const 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]; + copy->arguments = { copy->registers_and_constants_and_locals_and_arguments() + copy->arguments_offset, arguments.size() }; return copy; } diff --git a/Libraries/LibJS/Runtime/ExecutionContext.h b/Libraries/LibJS/Runtime/ExecutionContext.h index c90d9be5ccc..1fb4f71a8e9 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Libraries/LibJS/Runtime/ExecutionContext.h @@ -83,10 +83,9 @@ public: Value argument(size_t index) const { - auto arguments_size = registers_and_constants_and_locals_and_arguments_count - arguments_offset; - if (index >= arguments_size) [[unlikely]] + if (index >= arguments.size()) [[unlikely]] return js_undefined(); - return registers_and_constants_and_locals_and_arguments()[arguments_offset + index]; + return arguments[index]; } Value& local(size_t index) @@ -98,15 +97,7 @@ public: u32 passed_argument_count { 0 }; bool is_strict_mode { false }; - Span arguments() - { - 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() + arguments_offset, registers_and_constants_and_locals_and_arguments_count - arguments_offset }; - } + Span arguments; Vector unwind_contexts; Vector> previously_scheduled_jumps; diff --git a/Libraries/LibJS/Runtime/FunctionConstructor.cpp b/Libraries/LibJS/Runtime/FunctionConstructor.cpp index 39d192f02e0..33780d59934 100644 --- a/Libraries/LibJS/Runtime/FunctionConstructor.cpp +++ b/Libraries/LibJS/Runtime/FunctionConstructor.cpp @@ -269,7 +269,7 @@ ThrowCompletionOr> FunctionConstructor::construct(FunctionObject // 2. If bodyArg is not present, set bodyArg to the empty String. // NOTE: This does that, as well as the string extraction done inside of CreateDynamicFunction - auto extracted = TRY(extract_parameter_arguments_and_body(vm, vm.running_execution_context().arguments())); + auto extracted = TRY(extract_parameter_arguments_and_body(vm, vm.running_execution_context().arguments)); // 3. Return ? CreateDynamicFunction(C, NewTarget, normal, parameterArgs, bodyArg). return TRY(create_dynamic_function(vm, *constructor, &new_target, FunctionKind::Normal, extracted.parameters, extracted.body)); diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Libraries/LibJS/Runtime/FunctionPrototype.cpp index d169b259f50..d5522add542 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -98,7 +98,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind) Vector arguments; if (vm.argument_count() > 1) { - arguments.append(vm.running_execution_context().arguments().slice(1).data(), vm.argument_count() - 1); + arguments.append(vm.running_execution_context().arguments.slice(1).data(), vm.argument_count() - 1); } // 3. Let F be ? BoundFunctionCreate(Target, thisArg, args). @@ -129,7 +129,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::call) // FIXME: 3. Perform PrepareForTailCall(). auto this_arg = vm.argument(0); - auto args = vm.argument_count() > 1 ? vm.running_execution_context().arguments().slice(1) : ReadonlySpan {}; + auto args = vm.argument_count() > 1 ? vm.running_execution_context().arguments.slice(1) : ReadonlySpan {}; // 4. Return ? Call(func, thisArg, args). return TRY(JS::call(vm, function, this_arg, args)); diff --git a/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp b/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp index bc507299edb..2c0632d33ad 100644 --- a/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp +++ b/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp @@ -45,7 +45,7 @@ ThrowCompletionOr> GeneratorFunctionConstructor::construct(Funct // 2. If bodyArg is not present, set bodyArg to the empty String. // NOTE: This does that, as well as the string extraction done inside of CreateDynamicFunction - auto extracted = TRY(extract_parameter_arguments_and_body(vm, vm.running_execution_context().arguments())); + auto extracted = TRY(extract_parameter_arguments_and_body(vm, vm.running_execution_context().arguments)); // 3. Return ? CreateDynamicFunction(C, NewTarget, generator, parameterArgs, bodyArg). return TRY(FunctionConstructor::create_dynamic_function(vm, *constructor, &new_target, FunctionKind::Generator, extracted.parameters, extracted.body)); diff --git a/Libraries/LibJS/Runtime/NativeFunction.cpp b/Libraries/LibJS/Runtime/NativeFunction.cpp index 6b20c5487f4..4592c616269 100644 --- a/Libraries/LibJS/Runtime/NativeFunction.cpp +++ b/Libraries/LibJS/Runtime/NativeFunction.cpp @@ -146,7 +146,7 @@ ThrowCompletionOr NativeFunction::internal_call(Value this_argument, Read // 8. Perform any necessary implementation-defined initialization of calleeContext. callee_context->this_value = this_argument; if (!arguments_list.is_empty()) - callee_context->arguments().overwrite(0, arguments_list.data(), arguments_list.size() * sizeof(Value)); + callee_context->arguments.overwrite(0, arguments_list.data(), arguments_list.size() * sizeof(Value)); callee_context->lexical_environment = caller_context.lexical_environment; callee_context->variable_environment = caller_context.variable_environment; @@ -208,7 +208,7 @@ ThrowCompletionOr> NativeFunction::internal_construct(ReadonlySp // 8. Perform any necessary implementation-defined initialization of calleeContext. if (!arguments_list.is_empty()) - callee_context->arguments().overwrite(0, arguments_list.data(), arguments_list.size() * sizeof(Value)); + callee_context->arguments.overwrite(0, arguments_list.data(), arguments_list.size() * sizeof(Value)); callee_context->lexical_environment = caller_context.lexical_environment; callee_context->variable_environment = caller_context.variable_environment; diff --git a/Libraries/LibJS/Runtime/PromiseConstructor.cpp b/Libraries/LibJS/Runtime/PromiseConstructor.cpp index 053c00b1543..6611cec2e5e 100644 --- a/Libraries/LibJS/Runtime/PromiseConstructor.cpp +++ b/Libraries/LibJS/Runtime/PromiseConstructor.cpp @@ -465,7 +465,7 @@ JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::try_) auto callback = vm.argument(0); Span args; if (vm.argument_count() > 1) { - args = vm.running_execution_context().arguments().slice(1, vm.argument_count() - 1); + args = vm.running_execution_context().arguments.slice(1, vm.argument_count() - 1); } // 1. Let C be the this value. diff --git a/Libraries/LibJS/Runtime/VM.h b/Libraries/LibJS/Runtime/VM.h index d0eab3dc5f5..fa547f39dd4 100644 --- a/Libraries/LibJS/Runtime/VM.h +++ b/Libraries/LibJS/Runtime/VM.h @@ -160,7 +160,7 @@ public: size_t argument_count() const { - return running_execution_context().arguments().size(); + return running_execution_context().arguments.size(); } Value argument(size_t index) const diff --git a/Libraries/LibWeb/HTML/CrossOrigin/AbstractOperations.cpp b/Libraries/LibWeb/HTML/CrossOrigin/AbstractOperations.cpp index b3f3f1f4df4..163cb12c4be 100644 --- a/Libraries/LibWeb/HTML/CrossOrigin/AbstractOperations.cpp +++ b/Libraries/LibWeb/HTML/CrossOrigin/AbstractOperations.cpp @@ -137,7 +137,7 @@ Optional cross_origin_get_own_property_helper(Variantis_function()) { value = JS::NativeFunction::create( realm, [function = GC::make_root(*value)](auto& vm) { - return JS::call(vm, function.value(), JS::js_undefined(), vm.running_execution_context().arguments()); + return JS::call(vm, function.value(), JS::js_undefined(), vm.running_execution_context().arguments); }, 0); } @@ -154,7 +154,7 @@ Optional cross_origin_get_own_property_helper(Variantget)](auto& vm) { - return JS::call(vm, getter.cell(), object_ptr, vm.running_execution_context().arguments()); + return JS::call(vm, getter.cell(), object_ptr, vm.running_execution_context().arguments); }, 0); } @@ -166,7 +166,7 @@ Optional cross_origin_get_own_property_helper(Variantset)](auto& vm) { - return JS::call(vm, setter.cell(), object_ptr, vm.running_execution_context().arguments()); + return JS::call(vm, setter.cell(), object_ptr, vm.running_execution_context().arguments); }, 0); }