1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 09:14:58 +00:00

LibJS: Pass call/construct argument lists as ReadonlySpan<Value>

(Instead of MarkedVector<Value>.) This is a step towards not storing
argument lists in MarkedVector<Value> at all. Note that they still end
up in MarkedVectors since that's what ExecutionContext has.
This commit is contained in:
Andreas Kling 2023-11-27 12:56:20 +01:00
parent 9fa6628efa
commit ece961f882
29 changed files with 119 additions and 112 deletions

View file

@ -279,7 +279,7 @@ ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value
return {};
}
ThrowCompletionOr<Value> perform_call(Interpreter& interpreter, Value this_value, Op::CallType call_type, Value callee, MarkedVector<Value> argument_values)
ThrowCompletionOr<Value> perform_call(Interpreter& interpreter, Value this_value, Op::CallType call_type, Value callee, ReadonlySpan<Value> argument_values)
{
auto& vm = interpreter.vm();
auto& function = callee.as_function();
@ -288,11 +288,11 @@ ThrowCompletionOr<Value> perform_call(Interpreter& interpreter, Value this_value
if (callee == interpreter.realm().intrinsics().eval_function())
return_value = TRY(perform_eval(vm, !argument_values.is_empty() ? argument_values[0].value_or(JS::js_undefined()) : js_undefined(), vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct));
else
return_value = TRY(JS::call(vm, function, this_value, move(argument_values)));
return_value = TRY(JS::call(vm, function, this_value, argument_values));
} else if (call_type == Op::CallType::Call)
return_value = TRY(JS::call(vm, function, this_value, move(argument_values)));
return_value = TRY(JS::call(vm, function, this_value, argument_values));
else
return_value = TRY(construct(vm, function, move(argument_values)));
return_value = TRY(construct(vm, function, argument_values));
return return_value;
}
@ -633,7 +633,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> super_call_with_argument_array(VM& vm, V
return vm.throw_completion<TypeError>(ErrorType::NotAConstructor, "Super constructor");
// 6. Let result be ? Construct(func, argList, newTarget).
auto result = TRY(construct(vm, static_cast<FunctionObject&>(*func), move(arg_list), &new_target.as_function()));
auto result = TRY(construct(vm, static_cast<FunctionObject&>(*func), arg_list.span(), &new_target.as_function()));
// 7. Let thisER be GetThisEnvironment().
auto& this_environment = verify_cast<FunctionEnvironment>(*get_this_environment(vm));

View file

@ -17,7 +17,7 @@ ThrowCompletionOr<Value> get_by_id(VM&, DeprecatedFlyString const& property, Val
ThrowCompletionOr<Value> get_by_value(VM&, Value base_value, Value property_key_value);
ThrowCompletionOr<Value> get_global(Bytecode::Interpreter&, DeprecatedFlyString const& identifier, GlobalVariableCache&);
ThrowCompletionOr<void> put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind, PropertyLookupCache* = nullptr);
ThrowCompletionOr<Value> perform_call(Interpreter&, Value this_value, Op::CallType, Value callee, MarkedVector<Value> argument_values);
ThrowCompletionOr<Value> perform_call(Interpreter&, Value this_value, Op::CallType, Value callee, ReadonlySpan<Value> argument_values);
ThrowCompletionOr<void> throw_if_needed_for_call(Interpreter&, Value callee, Op::CallType, Optional<StringTableIndex> const& expression_string);
ThrowCompletionOr<Value> typeof_variable(VM&, DeprecatedFlyString const&);
ThrowCompletionOr<void> set_variable(VM&, DeprecatedFlyString const&, Value, Op::EnvironmentMode, Op::SetVariable::InitializationMode, EnvironmentVariableCache&);

View file

@ -2507,12 +2507,8 @@ static Value cxx_call(VM& vm, Value callee, u32 first_argument_index, u32 argume
{
TRY_OR_SET_EXCEPTION(throw_if_needed_for_call(vm.bytecode_interpreter(), callee, call_type, expression_string));
MarkedVector<Value> argument_values(vm.heap());
argument_values.ensure_capacity(argument_count);
for (u32 i = 0; i < argument_count; ++i) {
argument_values.unchecked_append(vm.bytecode_interpreter().reg(Bytecode::Register { first_argument_index + i }));
}
return TRY_OR_SET_EXCEPTION(perform_call(vm.bytecode_interpreter(), this_value, call_type, callee, move(argument_values)));
auto argument_values = vm.bytecode_interpreter().registers().slice(first_argument_index, argument_count);
return TRY_OR_SET_EXCEPTION(perform_call(vm.bytecode_interpreter(), this_value, call_type, callee, argument_values));
}
Assembler::Reg Compiler::argument_register(u32 index)

View file

@ -47,46 +47,40 @@ ThrowCompletionOr<Value> require_object_coercible(VM& vm, Value value)
}
// 7.3.14 Call ( F, V [ , argumentsList ] ), https://tc39.es/ecma262/#sec-call
ThrowCompletionOr<Value> call_impl(VM& vm, Value function, Value this_value, Optional<MarkedVector<Value>> arguments_list)
ThrowCompletionOr<Value> call_impl(VM& vm, Value function, Value this_value, ReadonlySpan<Value> arguments_list)
{
// 1. If argumentsList is not present, set argumentsList to a new empty List.
if (!arguments_list.has_value())
arguments_list = MarkedVector<Value> { vm.heap() };
// 2. If IsCallable(F) is false, throw a TypeError exception.
if (!function.is_function())
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, function.to_string_without_side_effects());
// 3. Return ? F.[[Call]](V, argumentsList).
return function.as_function().internal_call(this_value, move(*arguments_list));
return function.as_function().internal_call(this_value, arguments_list);
}
ThrowCompletionOr<Value> call_impl(VM& vm, FunctionObject& function, Value this_value, Optional<MarkedVector<Value>> arguments_list)
ThrowCompletionOr<Value> call_impl(VM&, FunctionObject& function, Value this_value, ReadonlySpan<Value> arguments_list)
{
// 1. If argumentsList is not present, set argumentsList to a new empty List.
if (!arguments_list.has_value())
arguments_list = MarkedVector<Value> { vm.heap() };
// 2. If IsCallable(F) is false, throw a TypeError exception.
// Note: Called with a FunctionObject ref
// 3. Return ? F.[[Call]](V, argumentsList).
return function.internal_call(this_value, move(*arguments_list));
return function.internal_call(this_value, arguments_list);
}
// 7.3.15 Construct ( F [ , argumentsList [ , newTarget ] ] ), https://tc39.es/ecma262/#sec-construct
ThrowCompletionOr<NonnullGCPtr<Object>> construct_impl(VM& vm, FunctionObject& function, Optional<MarkedVector<Value>> arguments_list, FunctionObject* new_target)
ThrowCompletionOr<NonnullGCPtr<Object>> construct_impl(VM&, FunctionObject& function, ReadonlySpan<Value> arguments_list, FunctionObject* new_target)
{
// 1. If newTarget is not present, set newTarget to F.
if (!new_target)
new_target = &function;
// 2. If argumentsList is not present, set argumentsList to a new empty List.
if (!arguments_list.has_value())
arguments_list = MarkedVector<Value> { vm.heap() };
// 3. Return ? F.[[Construct]](argumentsList, newTarget).
return function.internal_construct(move(*arguments_list), *new_target);
return function.internal_construct(arguments_list, *new_target);
}
// 7.3.19 LengthOfArrayLike ( obj ), https://tc39.es/ecma262/#sec-lengthofarraylike

View file

@ -28,9 +28,9 @@ NonnullGCPtr<Environment> get_this_environment(VM&);
bool can_be_held_weakly(Value);
Object* get_super_constructor(VM&);
ThrowCompletionOr<Value> require_object_coercible(VM&, Value);
ThrowCompletionOr<Value> call_impl(VM&, Value function, Value this_value, Optional<MarkedVector<Value>> = {});
ThrowCompletionOr<Value> call_impl(VM&, FunctionObject& function, Value this_value, Optional<MarkedVector<Value>> = {});
ThrowCompletionOr<NonnullGCPtr<Object>> construct_impl(VM&, FunctionObject&, Optional<MarkedVector<Value>> = {}, FunctionObject* new_target = nullptr);
ThrowCompletionOr<Value> call_impl(VM&, Value function, Value this_value, ReadonlySpan<Value> arguments = {});
ThrowCompletionOr<Value> call_impl(VM&, FunctionObject& function, Value this_value, ReadonlySpan<Value> arguments = {});
ThrowCompletionOr<NonnullGCPtr<Object>> construct_impl(VM&, FunctionObject&, ReadonlySpan<Value> arguments = {}, FunctionObject* new_target = nullptr);
ThrowCompletionOr<size_t> length_of_array_like(VM&, Object const&);
ThrowCompletionOr<MarkedVector<Value>> create_list_from_array_like(VM&, Value, Function<ThrowCompletionOr<void>(Value)> = {});
ThrowCompletionOr<FunctionObject*> species_constructor(VM&, Object const&, FunctionObject& default_constructor);
@ -75,45 +75,45 @@ ThrowCompletionOr<Value> perform_eval(VM&, Value, CallerMode, EvalMode);
ThrowCompletionOr<void> eval_declaration_instantiation(VM& vm, Program const& program, Environment* variable_environment, Environment* lexical_environment, PrivateEnvironment* private_environment, bool strict);
// 7.3.14 Call ( F, V [ , argumentsList ] ), https://tc39.es/ecma262/#sec-call
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, Value function, Value this_value, MarkedVector<Value> arguments_list)
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, Value function, Value this_value, ReadonlySpan<Value> arguments_list)
{
return call_impl(vm, function, this_value, move(arguments_list));
return call_impl(vm, function, this_value, arguments_list);
}
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, Value function, Value this_value, Optional<MarkedVector<Value>> arguments_list)
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, Value function, Value this_value, Span<Value> arguments_list)
{
return call_impl(vm, function, this_value, move(arguments_list));
return call_impl(vm, function, this_value, static_cast<ReadonlySpan<Value>>(arguments_list));
}
template<typename... Args>
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, Value function, Value this_value, Args&&... args)
{
if constexpr (sizeof...(Args) > 0) {
MarkedVector<Value> arguments_list { vm.heap() };
(..., arguments_list.append(forward<Args>(args)));
return call_impl(vm, function, this_value, move(arguments_list));
constexpr auto argument_count = sizeof...(Args);
if constexpr (argument_count > 0) {
AK::Array<Value, argument_count> arguments { forward<Args>(args)... };
return call_impl(vm, function, this_value, static_cast<ReadonlySpan<Value>>(arguments.span()));
}
return call_impl(vm, function, this_value);
}
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, FunctionObject& function, Value this_value, MarkedVector<Value> arguments_list)
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, FunctionObject& function, Value this_value, ReadonlySpan<Value> arguments_list)
{
return call_impl(vm, function, this_value, move(arguments_list));
return call_impl(vm, function, this_value, arguments_list);
}
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, FunctionObject& function, Value this_value, Optional<MarkedVector<Value>> arguments_list)
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, FunctionObject& function, Value this_value, Span<Value> arguments_list)
{
return call_impl(vm, function, this_value, move(arguments_list));
return call_impl(vm, function, this_value, static_cast<ReadonlySpan<Value>>(arguments_list));
}
template<typename... Args>
ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, FunctionObject& function, Value this_value, Args&&... args)
{
if constexpr (sizeof...(Args) > 0) {
MarkedVector<Value> arguments_list { vm.heap() };
(..., arguments_list.append(forward<Args>(args)));
return call_impl(vm, function, this_value, move(arguments_list));
constexpr auto argument_count = sizeof...(Args);
if constexpr (argument_count > 0) {
AK::Array<Value, argument_count> arguments { forward<Args>(args)... };
return call_impl(vm, function, this_value, static_cast<ReadonlySpan<Value>>(arguments.span()));
}
return call_impl(vm, function, this_value);
@ -123,23 +123,23 @@ ALWAYS_INLINE ThrowCompletionOr<Value> call(VM& vm, FunctionObject& function, Va
template<typename... Args>
ALWAYS_INLINE ThrowCompletionOr<NonnullGCPtr<Object>> construct(VM& vm, FunctionObject& function, Args&&... args)
{
if constexpr (sizeof...(Args) > 0) {
MarkedVector<Value> arguments_list { vm.heap() };
(..., arguments_list.append(forward<Args>(args)));
return construct_impl(vm, function, move(arguments_list));
constexpr auto argument_count = sizeof...(Args);
if constexpr (argument_count > 0) {
AK::Array<Value, argument_count> arguments { forward<Args>(args)... };
return construct_impl(vm, function, static_cast<ReadonlySpan<Value>>(arguments.span()));
}
return construct_impl(vm, function);
}
ALWAYS_INLINE ThrowCompletionOr<NonnullGCPtr<Object>> construct(VM& vm, FunctionObject& function, MarkedVector<Value> arguments_list, FunctionObject* new_target = nullptr)
ALWAYS_INLINE ThrowCompletionOr<NonnullGCPtr<Object>> construct(VM& vm, FunctionObject& function, ReadonlySpan<Value> arguments_list, FunctionObject* new_target = nullptr)
{
return construct_impl(vm, function, move(arguments_list), new_target);
return construct_impl(vm, function, arguments_list, new_target);
}
ALWAYS_INLINE ThrowCompletionOr<NonnullGCPtr<Object>> construct(VM& vm, FunctionObject& function, Optional<MarkedVector<Value>> arguments_list, FunctionObject* new_target = nullptr)
ALWAYS_INLINE ThrowCompletionOr<NonnullGCPtr<Object>> construct(VM& vm, FunctionObject& function, Span<Value> arguments_list, FunctionObject* new_target = nullptr)
{
return construct_impl(vm, function, move(arguments_list), new_target);
return construct_impl(vm, function, static_cast<ReadonlySpan<Value>>(arguments_list), new_target);
}
// 10.1.13 OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinarycreatefromconstructor

View file

@ -63,6 +63,24 @@ NonnullGCPtr<Array> Array::create_from(Realm& realm, Vector<Value> const& elemen
return array;
}
NonnullGCPtr<Array> Array::create_from(Realm& realm, ReadonlySpan<Value> const& elements)
{
// 1. Let array be ! ArrayCreate(0).
auto array = MUST(Array::create(realm, 0));
// 2. Let n be 0.
// 3. For each element e of elements, do
for (u32 n = 0; n < elements.size(); ++n) {
// a. Perform ! CreateDataPropertyOrThrow(array, ! ToString(𝔽(n)), e).
MUST(array->create_data_property_or_throw(n, elements[n]));
// b. Set n to n + 1.
}
// 4. Return array.
return array;
}
Array::Array(Object& prototype)
: Object(ConstructWithPrototypeTag::Tag, prototype)
{

View file

@ -26,6 +26,7 @@ class Array : public Object {
public:
static ThrowCompletionOr<NonnullGCPtr<Array>> create(Realm&, u64 length, Object* prototype = nullptr);
static NonnullGCPtr<Array> create_from(Realm&, Vector<Value> const&);
static NonnullGCPtr<Array> create_from(Realm&, ReadonlySpan<Value> const&);
// Non-standard but equivalent to CreateArrayFromList.
template<typename T>

View file

@ -45,7 +45,7 @@ BoundFunction::BoundFunction(Realm& realm, FunctionObject& bound_target_function
}
// 10.4.1.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-bound-function-exotic-objects-call-thisargument-argumentslist
ThrowCompletionOr<Value> BoundFunction::internal_call([[maybe_unused]] Value this_argument, MarkedVector<Value> arguments_list)
ThrowCompletionOr<Value> BoundFunction::internal_call([[maybe_unused]] Value this_argument, ReadonlySpan<Value> arguments_list)
{
auto& vm = this->vm();
@ -59,16 +59,17 @@ ThrowCompletionOr<Value> BoundFunction::internal_call([[maybe_unused]] Value thi
auto& bound_args = m_bound_arguments;
// 4. Let args be the list-concatenation of boundArgs and argumentsList.
auto args = MarkedVector<Value> { heap() };
Vector<Value> args;
args.ensure_capacity(bound_args.size() + arguments_list.size());
args.extend(bound_args);
args.extend(move(arguments_list));
args.append(arguments_list.data(), arguments_list.size());
// 5. Return ? Call(target, boundThis, args).
return call(vm, &target, bound_this, move(args));
return call(vm, &target, bound_this, args.span());
}
// 10.4.1.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-bound-function-exotic-objects-construct-argumentslist-newtarget
ThrowCompletionOr<NonnullGCPtr<Object>> BoundFunction::internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target)
ThrowCompletionOr<NonnullGCPtr<Object>> BoundFunction::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
{
auto& vm = this->vm();
@ -84,7 +85,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> BoundFunction::internal_construct(Marked
// 4. Let args be the list-concatenation of boundArgs and argumentsList.
auto args = MarkedVector<Value> { heap() };
args.extend(bound_args);
args.extend(move(arguments_list));
args.append(arguments_list.data(), arguments_list.size());
// 5. If SameValue(F, newTarget) is true, set newTarget to target.
auto* final_new_target = &new_target;
@ -92,7 +93,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> BoundFunction::internal_construct(Marked
final_new_target = &target;
// 6. Return ? Construct(target, args, newTarget).
return construct(vm, target, move(args), final_new_target);
return construct(vm, target, args.span(), final_new_target);
}
void BoundFunction::visit_edges(Visitor& visitor)

View file

@ -20,8 +20,8 @@ public:
virtual ~BoundFunction() override = default;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target) override;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, ReadonlySpan<Value> arguments_list) override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target) override;
virtual DeprecatedFlyString const& name() const override { return m_name; }
virtual bool is_strict_mode() const override { return m_bound_target_function->is_strict_mode(); }

View file

@ -361,7 +361,7 @@ void ECMAScriptFunctionObject::initialize(Realm& realm)
}
// 10.2.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist
ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argument, MarkedVector<Value> arguments_list)
ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argument, ReadonlySpan<Value> arguments_list)
{
auto& vm = this->vm();
@ -373,7 +373,7 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
callee_context.local_variables.resize(m_local_variables_names.size());
// Non-standard
callee_context.arguments.extend(move(arguments_list));
callee_context.arguments.append(arguments_list.data(), arguments_list.size());
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
// 2. Let calleeContext be PrepareForOrdinaryCall(F, undefined).
@ -420,7 +420,7 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
}
// 10.2.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
ThrowCompletionOr<NonnullGCPtr<Object>> ECMAScriptFunctionObject::internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target)
ThrowCompletionOr<NonnullGCPtr<Object>> ECMAScriptFunctionObject::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
{
auto& vm = this->vm();
@ -443,7 +443,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> ECMAScriptFunctionObject::internal_const
callee_context.local_variables.resize(m_local_variables_names.size());
// Non-standard
callee_context.arguments.extend(move(arguments_list));
callee_context.arguments.append(arguments_list.data(), arguments_list.size());
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
// 4. Let calleeContext be PrepareForOrdinaryCall(F, newTarget).

View file

@ -44,8 +44,8 @@ public:
virtual void initialize(Realm&) override;
virtual ~ECMAScriptFunctionObject() override = default;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target) override;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, ReadonlySpan<Value> arguments_list) override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target) override;
void make_method(Object& home_object);

View file

@ -23,8 +23,8 @@ public:
// Table 7: Additional Essential Internal Methods of Function Objects, https://tc39.es/ecma262/#table-additional-essential-internal-methods-of-function-objects
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) = 0;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct([[maybe_unused]] MarkedVector<Value> arguments_list, [[maybe_unused]] FunctionObject& new_target) { VERIFY_NOT_REACHED(); }
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, ReadonlySpan<Value> arguments_list) = 0;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct([[maybe_unused]] ReadonlySpan<Value> arguments_list, [[maybe_unused]] FunctionObject& new_target) { VERIFY_NOT_REACHED(); }
virtual DeprecatedFlyString const& name() const = 0;

View file

@ -40,7 +40,7 @@ void FunctionPrototype::initialize(Realm& realm)
define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
}
ThrowCompletionOr<Value> FunctionPrototype::internal_call(Value, MarkedVector<Value>)
ThrowCompletionOr<Value> FunctionPrototype::internal_call(Value, ReadonlySpan<Value>)
{
// The Function prototype object:
// - accepts any arguments and returns undefined when invoked.
@ -76,7 +76,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
// FIXME: 5. Perform PrepareForTailCall().
// 6. Return ? Call(func, thisArg, argList).
return TRY(JS::call(vm, function, this_arg, move(arguments)));
return TRY(JS::call(vm, function, this_arg, arguments.span()));
}
// 20.2.3.2 Function.prototype.bind ( thisArg, ...args ), https://tc39.es/ecma262/#sec-function.prototype.bind
@ -130,14 +130,10 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::call)
// FIXME: 3. Perform PrepareForTailCall().
auto this_arg = vm.argument(0);
MarkedVector<Value> arguments(vm.heap());
if (vm.argument_count() > 1) {
for (size_t i = 1; i < vm.argument_count(); ++i)
arguments.append(vm.argument(i));
}
auto args = vm.argument_count() > 1 ? vm.running_execution_context().arguments.span().slice(1) : ReadonlySpan<Value> {};
// 4. Return ? Call(func, thisArg, args).
return TRY(JS::call(vm, function, this_arg, move(arguments)));
return TRY(JS::call(vm, function, this_arg, args));
}
// 20.2.3.5 Function.prototype.toString ( ), https://tc39.es/ecma262/#sec-function.prototype.tostring

View file

@ -18,7 +18,7 @@ public:
virtual void initialize(Realm&) override;
virtual ~FunctionPrototype() override = default;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, ReadonlySpan<Value> arguments_list) override;
virtual DeprecatedFlyString const& name() const override { return m_name; }
private:

View file

@ -18,13 +18,13 @@ JobCallback make_job_callback(FunctionObject& callback)
}
// 9.5.3 HostCallJobCallback ( jobCallback, V, argumentsList ), https://tc39.es/ecma262/#sec-hostcalljobcallback
ThrowCompletionOr<Value> call_job_callback(VM& vm, JobCallback& job_callback, Value this_value, MarkedVector<Value> arguments_list)
ThrowCompletionOr<Value> call_job_callback(VM& vm, JobCallback& job_callback, Value this_value, ReadonlySpan<Value> arguments_list)
{
// 1. Assert: IsCallable(jobCallback.[[Callback]]) is true.
VERIFY(!job_callback.callback.is_null());
// 2. Return ? Call(jobCallback.[[Callback]], V, argumentsList).
return call(vm, job_callback.callback.cell(), this_value, move(arguments_list));
return call(vm, job_callback.callback.cell(), this_value, arguments_list);
}
}

View file

@ -23,6 +23,6 @@ struct JobCallback {
};
JobCallback make_job_callback(FunctionObject& callback);
ThrowCompletionOr<Value> call_job_callback(VM&, JobCallback&, Value this_value, MarkedVector<Value> arguments_list);
ThrowCompletionOr<Value> call_job_callback(VM&, JobCallback&, Value this_value, ReadonlySpan<Value> arguments_list);
}

View file

@ -96,7 +96,7 @@ NativeFunction::NativeFunction(DeprecatedFlyString name, Object& prototype)
// these good candidates for a bit of code duplication :^)
// 10.3.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-built-in-function-objects-call-thisargument-argumentslist
ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, MarkedVector<Value> arguments_list)
ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, ReadonlySpan<Value> arguments_list)
{
auto& vm = this->vm();
@ -132,7 +132,7 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, Mark
// 8. Perform any necessary implementation-defined initialization of calleeContext.
callee_context.this_value = this_argument;
callee_context.arguments.extend(move(arguments_list));
callee_context.arguments.append(arguments_list.data(), arguments_list.size());
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
callee_context.lexical_environment = caller_context.lexical_environment;
@ -160,7 +160,7 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, Mark
}
// 10.3.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-built-in-function-objects-construct-argumentslist-newtarget
ThrowCompletionOr<NonnullGCPtr<Object>> NativeFunction::internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target)
ThrowCompletionOr<NonnullGCPtr<Object>> NativeFunction::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
{
auto& vm = this->vm();
@ -195,7 +195,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> NativeFunction::internal_construct(Marke
// Note: This is already the default value.
// 8. Perform any necessary implementation-defined initialization of calleeContext.
callee_context.arguments.extend(move(arguments_list));
callee_context.arguments.append(arguments_list.data(), arguments_list.size());
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
callee_context.lexical_environment = caller_context.lexical_environment;

View file

@ -26,8 +26,8 @@ public:
virtual ~NativeFunction() override = default;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target) override;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, ReadonlySpan<Value> arguments_list) override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target) override;
// Used for [[Call]] / [[Construct]]'s "...result of evaluating F in a manner that conforms to the specification of F".
// Needs to be overridden by all NativeFunctions without an m_native_function.

View file

@ -52,9 +52,7 @@ static ThrowCompletionOr<Value> run_reaction_job(VM& vm, PromiseReaction& reacti
// e. Else, let handlerResult be Completion(HostCallJobCallback(handler, undefined, « argument »)).
else {
dbgln_if(PROMISE_DEBUG, "run_reaction_job: Calling handler callback {} @ {} with argument {}", handler.value().callback.cell()->class_name(), handler.value().callback.cell(), argument);
MarkedVector<Value> arguments(vm.heap());
arguments.append(argument);
handler_result = vm.host_call_job_callback(handler.value(), js_undefined(), move(arguments));
handler_result = vm.host_call_job_callback(handler.value(), js_undefined(), ReadonlySpan<Value> { &argument, 1 });
}
// f. If promiseCapability is undefined, then
@ -128,10 +126,10 @@ static ThrowCompletionOr<Value> run_resolve_thenable_job(VM& vm, Promise& promis
// b. Let thenCallResult be Completion(HostCallJobCallback(then, thenable, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »)).
dbgln_if(PROMISE_DEBUG, "run_resolve_thenable_job: Calling then job callback for thenable {}", &thenable);
MarkedVector<Value> arguments(vm.heap());
arguments.append(Value(resolve_function));
arguments.append(Value(reject_function));
auto then_call_result = vm.host_call_job_callback(then, thenable, move(arguments));
AK::Array<Value, 2> arguments;
arguments[0] = Value(resolve_function);
arguments[1] = Value(reject_function);
auto then_call_result = vm.host_call_job_callback(then, thenable, arguments.span());
// c. If thenCallResult is an abrupt completion, then
if (then_call_result.is_error()) {

View file

@ -774,7 +774,7 @@ ThrowCompletionOr<MarkedVector<Value>> ProxyObject::internal_own_property_keys()
}
// 10.5.12 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
ThrowCompletionOr<Value> ProxyObject::internal_call(Value this_argument, MarkedVector<Value> arguments_list)
ThrowCompletionOr<Value> ProxyObject::internal_call(Value this_argument, ReadonlySpan<Value> arguments_list)
{
auto& vm = this->vm();
auto& realm = *vm.current_realm();
@ -797,7 +797,7 @@ ThrowCompletionOr<Value> ProxyObject::internal_call(Value this_argument, MarkedV
// 6. If trap is undefined, then
if (!trap) {
// a. Return ? Call(target, thisArgument, argumentsList).
return call(vm, m_target, this_argument, move(arguments_list));
return call(vm, m_target, this_argument, arguments_list);
}
// 7. Let argArray be CreateArrayFromList(argumentsList).
@ -818,7 +818,7 @@ bool ProxyObject::has_constructor() const
}
// 10.5.13 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-construct-argumentslist-newtarget
ThrowCompletionOr<NonnullGCPtr<Object>> ProxyObject::internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target)
ThrowCompletionOr<NonnullGCPtr<Object>> ProxyObject::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
{
auto& vm = this->vm();
auto& realm = *vm.current_realm();
@ -842,7 +842,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> ProxyObject::internal_construct(MarkedVe
// 7. If trap is undefined, then
if (!trap) {
// a. Return ? Construct(target, argumentsList, newTarget).
return construct(vm, static_cast<FunctionObject&>(*m_target), move(arguments_list), &new_target);
return construct(vm, static_cast<FunctionObject&>(*m_target), arguments_list, &new_target);
}
// 8. Let argArray be CreateArrayFromList(argumentsList).

View file

@ -43,8 +43,8 @@ public:
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target) override;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, ReadonlySpan<Value> arguments_list) override;
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target) override;
private:
ProxyObject(Object& target, Object& handler, Object& prototype);

View file

@ -61,7 +61,7 @@ JS_DEFINE_NATIVE_FUNCTION(ReflectObject::apply)
// 3. Perform PrepareForTailCall().
// 4. Return ? Call(target, thisArgument, args).
return TRY(call(vm, target.as_function(), this_argument, move(args)));
return TRY(call(vm, target.as_function(), this_argument, args.span()));
}
// 28.1.2 Reflect.construct ( target, argumentsList [ , newTarget ] ), https://tc39.es/ecma262/#sec-reflect.construct
@ -86,7 +86,7 @@ JS_DEFINE_NATIVE_FUNCTION(ReflectObject::construct)
auto args = TRY(create_list_from_array_like(vm, arguments_list));
// 5. Return ? Construct(target, args, newTarget).
return TRY(JS::construct(vm, target.as_function(), move(args), &new_target.as_function()));
return TRY(JS::construct(vm, target.as_function(), args.span(), &new_target.as_function()));
}
// 28.1.3 Reflect.defineProperty ( target, propertyKey, attributes ), https://tc39.es/ecma262/#sec-reflect.defineproperty

View file

@ -777,7 +777,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_replace)
}
// iii. Let replValue be ? Call(replaceValue, undefined, replacerArgs).
auto replace_result = TRY(call(vm, replace_value.as_function(), js_undefined(), move(replacer_args)));
auto replace_result = TRY(call(vm, replace_value.as_function(), js_undefined(), replacer_args.span()));
// iv. Let replacement be ? ToString(replValue).
replacement = TRY(replace_result.to_string(vm));

View file

@ -322,7 +322,7 @@ ThrowCompletionOr<TypedArrayBase*> typed_array_create(VM& vm, FunctionObject& co
if (!arguments.is_empty())
first_argument = arguments[0];
// 1. Let newTypedArray be ? Construct(constructor, argumentList).
auto new_typed_array = TRY(construct(vm, constructor, move(arguments)));
auto new_typed_array = TRY(construct(vm, constructor, arguments.span()));
// 2. Perform ? ValidateTypedArray(newTypedArray).
if (!new_typed_array->is_typed_array())

View file

@ -78,8 +78,8 @@ VM::VM(OwnPtr<CustomData> custom_data, ErrorMessages error_messages)
promise_rejection_tracker(promise, operation);
};
host_call_job_callback = [this](JobCallback& job_callback, Value this_value, MarkedVector<Value> arguments) {
return call_job_callback(*this, job_callback, this_value, move(arguments));
host_call_job_callback = [this](JobCallback& job_callback, Value this_value, ReadonlySpan<Value> arguments) {
return call_job_callback(*this, job_callback, this_value, arguments);
};
host_enqueue_finalization_registry_cleanup_job = [this](FinalizationRegistry& finalization_registry) {

View file

@ -243,7 +243,7 @@ public:
void enable_default_host_import_module_dynamically_hook();
Function<void(Promise&, Promise::RejectionOperation)> host_promise_rejection_tracker;
Function<ThrowCompletionOr<Value>(JobCallback&, Value, MarkedVector<Value>)> host_call_job_callback;
Function<ThrowCompletionOr<Value>(JobCallback&, Value, ReadonlySpan<Value>)> host_call_job_callback;
Function<void(FinalizationRegistry&)> host_enqueue_finalization_registry_cleanup_job;
Function<void(Function<ThrowCompletionOr<Value>()>, Realm*)> host_enqueue_promise_job;
Function<JobCallback(FunctionObject&)> host_make_job_callback;

View file

@ -2505,7 +2505,10 @@ ThrowCompletionOr<Value> Value::invoke_internal(VM& vm, PropertyKey const& prope
auto function = TRY(get(vm, property_key));
// 3. Return ? Call(func, V, argumentsList).
return call(vm, function, *this, move(arguments));
ReadonlySpan<Value> argument_list;
if (arguments.has_value())
argument_list = arguments.value().span();
return call(vm, function, *this, argument_list);
}
}

View file

@ -54,7 +54,7 @@ void WrappedFunction::visit_edges(Visitor& visitor)
}
// 2.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/proposal-shadowrealm/#sec-wrapped-function-exotic-objects-call-thisargument-argumentslist
ThrowCompletionOr<Value> WrappedFunction::internal_call(Value this_argument, MarkedVector<Value> arguments_list)
ThrowCompletionOr<Value> WrappedFunction::internal_call(Value this_argument, ReadonlySpan<Value> arguments_list)
{
auto& vm = this->vm();
@ -82,7 +82,7 @@ ThrowCompletionOr<Value> WrappedFunction::internal_call(Value this_argument, Mar
}
// 2.2 OrdinaryWrappedFunctionCall ( F: a wrapped function exotic object, thisArgument: an ECMAScript language value, argumentsList: a List of ECMAScript language values, ), https://tc39.es/proposal-shadowrealm/#sec-ordinary-wrapped-function-call
ThrowCompletionOr<Value> ordinary_wrapped_function_call(WrappedFunction const& function, Value this_argument, MarkedVector<Value> const& arguments_list)
ThrowCompletionOr<Value> ordinary_wrapped_function_call(WrappedFunction const& function, Value this_argument, ReadonlySpan<Value> arguments_list)
{
auto& vm = function.vm();
@ -118,7 +118,7 @@ ThrowCompletionOr<Value> ordinary_wrapped_function_call(WrappedFunction const& f
auto wrapped_this_argument = TRY(get_wrapped_value(vm, *target_realm, this_argument));
// 9. Let result be the Completion Record of Call(target, wrappedThisArgument, wrappedArgs).
auto result = call(vm, &target, wrapped_this_argument, move(wrapped_args));
auto result = call(vm, &target, wrapped_this_argument, wrapped_args.span());
// 10. If result.[[Type]] is normal or result.[[Type]] is return, then
if (!result.is_throw_completion()) {

View file

@ -20,7 +20,7 @@ public:
virtual ~WrappedFunction() = default;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, ReadonlySpan<Value> arguments_list) override;
// FIXME: Remove this (and stop inventing random internal slots that shouldn't exist, jeez)
virtual DeprecatedFlyString const& name() const override { return m_wrapped_target_function->name(); }
@ -40,7 +40,7 @@ private:
NonnullGCPtr<Realm> m_realm; // [[Realm]]
};
ThrowCompletionOr<Value> ordinary_wrapped_function_call(WrappedFunction const&, Value this_argument, MarkedVector<Value> const& arguments_list);
ThrowCompletionOr<Value> ordinary_wrapped_function_call(WrappedFunction const&, Value this_argument, ReadonlySpan<Value> arguments_list);
void prepare_for_wrapped_function_call(WrappedFunction const&, ExecutionContext& callee_context);
}