1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 04:57:44 +00:00

LibJS: Change ExecutionContext's arguments list to a MarkedValueList

The test262 tests under RegExp/property-escapes/generated will invoke
Reflect.apply with up to 10,000 arguments at a time. In LibJS, when the
call stack reached VM::call_internal, we transfer those arguments from
a MarkedValueList to the execution context's arguments Vector.

Because these types differ (MarkedValueList is a Vector<Value, 32>), the
arguments are copied rather than moved. By changing the arguments vector
to a MarkedValueList, we can properly move the passed arguments over.

This shaves about 2 seconds off the following test262 test (from 15sec):
  RegExp/property-escapes/generated/General_Category_-_Decimal_Number.js
This commit is contained in:
Timothy Flynn 2021-08-09 17:09:48 -04:00 committed by Andreas Kling
parent 34bd25f6c2
commit 66264f7c2a
4 changed files with 25 additions and 17 deletions

View file

@ -44,7 +44,7 @@ Value Interpreter::run(Executable const& executable, BasicBlock const* entry_poi
vm().set_last_value(Badge<Interpreter> {}, {}); vm().set_last_value(Badge<Interpreter> {}, {});
ExecutionContext execution_context; ExecutionContext execution_context(vm().heap());
if (vm().execution_context_stack().is_empty()) { if (vm().execution_context_stack().is_empty()) {
execution_context.this_value = &global_object(); execution_context.this_value = &global_object();
static FlyString global_execution_context_name = "(*BC* global execution context)"; static FlyString global_execution_context_name = "(*BC* global execution context)";

View file

@ -45,7 +45,7 @@ void Interpreter::run(GlobalObject& global_object, const Program& program)
vm.set_last_value(Badge<Interpreter> {}, {}); vm.set_last_value(Badge<Interpreter> {}, {});
ExecutionContext execution_context; ExecutionContext execution_context(heap());
execution_context.current_node = &program; execution_context.current_node = &program;
execution_context.this_value = &global_object; execution_context.this_value = &global_object;
static FlyString global_execution_context_name = "(global execution context)"; static FlyString global_execution_context_name = "(global execution context)";

View file

@ -442,6 +442,18 @@ Reference VM::resolve_binding(FlyString const& name, Environment* environment)
return get_identifier_reference(environment, name, strict); return get_identifier_reference(environment, name, strict);
} }
static void append_bound_and_passed_arguments(MarkedValueList& arguments, Vector<Value> bound_arguments, Optional<MarkedValueList> passed_arguments)
{
arguments.ensure_capacity(bound_arguments.size());
arguments.extend(move(bound_arguments));
if (passed_arguments.has_value()) {
auto arguments_list = move(passed_arguments.release_value().values());
arguments.grow_capacity(arguments_list.size());
arguments.extend(move(arguments_list));
}
}
Value VM::construct(FunctionObject& function, FunctionObject& new_target, Optional<MarkedValueList> arguments) Value VM::construct(FunctionObject& function, FunctionObject& new_target, Optional<MarkedValueList> arguments)
{ {
auto& global_object = function.global_object(); auto& global_object = function.global_object();
@ -453,7 +465,7 @@ Value VM::construct(FunctionObject& function, FunctionObject& new_target, Option
return {}; return {};
} }
ExecutionContext callee_context; ExecutionContext callee_context(heap());
prepare_for_ordinary_call(function, callee_context, &new_target); prepare_for_ordinary_call(function, callee_context, &new_target);
if (exception()) if (exception())
return {}; return {};
@ -465,9 +477,7 @@ Value VM::construct(FunctionObject& function, FunctionObject& new_target, Option
if (auto* interpreter = interpreter_if_exists()) if (auto* interpreter = interpreter_if_exists())
callee_context.current_node = interpreter->current_node(); callee_context.current_node = interpreter->current_node();
callee_context.arguments = function.bound_arguments(); append_bound_and_passed_arguments(callee_context.arguments, function.bound_arguments(), move(arguments));
if (arguments.has_value())
callee_context.arguments.extend(arguments.value().values());
if (auto* environment = callee_context.lexical_environment) { if (auto* environment = callee_context.lexical_environment) {
auto& function_environment = verify_cast<FunctionEnvironment>(*environment); auto& function_environment = verify_cast<FunctionEnvironment>(*environment);
@ -631,19 +641,14 @@ Value VM::call_internal(FunctionObject& function, Value this_value, Optional<Mar
if (is<BoundFunction>(function)) { if (is<BoundFunction>(function)) {
auto& bound_function = static_cast<BoundFunction&>(function); auto& bound_function = static_cast<BoundFunction&>(function);
auto bound_arguments = bound_function.bound_arguments();
if (arguments.has_value())
bound_arguments.extend(*arguments);
MarkedValueList with_bound_arguments { heap() }; MarkedValueList with_bound_arguments { heap() };
with_bound_arguments.extend(bound_function.bound_arguments()); append_bound_and_passed_arguments(with_bound_arguments, bound_function.bound_arguments(), move(arguments));
if (arguments.has_value())
with_bound_arguments.extend(*arguments);
return call_internal(bound_function.target_function(), bound_function.bound_this(), move(with_bound_arguments)); return call_internal(bound_function.target_function(), bound_function.bound_this(), move(with_bound_arguments));
} }
ExecutionContext callee_context; ExecutionContext callee_context(heap());
prepare_for_ordinary_call(function, callee_context, js_undefined()); prepare_for_ordinary_call(function, callee_context, js_undefined());
if (exception()) if (exception())
return {}; return {};
@ -656,9 +661,7 @@ Value VM::call_internal(FunctionObject& function, Value this_value, Optional<Mar
callee_context.current_node = interpreter->current_node(); callee_context.current_node = interpreter->current_node();
callee_context.this_value = function.bound_this().value_or(this_value); callee_context.this_value = function.bound_this().value_or(this_value);
callee_context.arguments = function.bound_arguments(); append_bound_and_passed_arguments(callee_context.arguments, function.bound_arguments(), move(arguments));
if (arguments.has_value())
callee_context.arguments.extend(arguments.value().values());
if (callee_context.lexical_environment) if (callee_context.lexical_environment)
ordinary_call_bind_this(function, callee_context, this_value); ordinary_call_bind_this(function, callee_context, this_value);

View file

@ -43,11 +43,16 @@ struct ScopeFrame {
}; };
struct ExecutionContext { struct ExecutionContext {
explicit ExecutionContext(Heap& heap)
: arguments(heap)
{
}
const ASTNode* current_node { nullptr }; const ASTNode* current_node { nullptr };
FlyString function_name; FlyString function_name;
FunctionObject* function { nullptr }; FunctionObject* function { nullptr };
Value this_value; Value this_value;
Vector<Value> arguments; MarkedValueList arguments;
Object* arguments_object { nullptr }; Object* arguments_object { nullptr };
Environment* lexical_environment { nullptr }; Environment* lexical_environment { nullptr };
Environment* variable_environment { nullptr }; Environment* variable_environment { nullptr };