diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index 4f41a4c8aa2..db85ab05055 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -2616,12 +2616,30 @@ ThrowCompletionOr Call::execute_impl(Bytecode::Interpreter& interpreter) c { auto callee = interpreter.get(m_callee); - TRY(throw_if_needed_for_call(interpreter, callee, CallType::Call, expression_string())); + if (!callee.is_function()) [[unlikely]] { + return throw_type_error_for_callee(interpreter, callee, "function"sv, m_expression_string); + } - auto argument_values = interpreter.allocate_argument_values(m_argument_count); - for (size_t i = 0; i < m_argument_count; ++i) - argument_values[i] = interpreter.get(m_arguments[i]); - interpreter.set(dst(), TRY(perform_call(interpreter, interpreter.get(m_this_value), CallType::Call, callee, argument_values))); + auto& function = callee.as_function(); + + ExecutionContext* callee_context = nullptr; + size_t registers_and_constants_and_locals_count = 0; + size_t argument_count = m_argument_count; + TRY(function.get_stack_frame_size(registers_and_constants_and_locals_count, argument_count)); + ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK_WITHOUT_CLEARING_ARGS(callee_context, registers_and_constants_and_locals_count, max(m_argument_count, argument_count)); + + auto* callee_context_argument_values = callee_context->arguments.data(); + auto const callee_context_argument_count = callee_context->arguments.size(); + auto const insn_argument_count = m_argument_count; + + for (size_t i = 0; i < insn_argument_count; ++i) + callee_context_argument_values[i] = interpreter.get(m_arguments[i]); + for (size_t i = insn_argument_count; i < callee_context_argument_count; ++i) + callee_context_argument_values[i] = js_undefined(); + callee_context->passed_argument_count = insn_argument_count; + + auto retval = TRY(function.internal_call(*callee_context, interpreter.get(m_this_value))); + interpreter.set(m_dst, retval); return {}; } diff --git a/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Libraries/LibJS/Runtime/AbstractOperations.cpp index 82965d1317f..ed3bc322f56 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -59,7 +59,19 @@ ThrowCompletionOr call_impl(VM& vm, Value function, Value this_value, Rea return vm.throw_completion(ErrorType::NotAFunction, function.to_string_without_side_effects()); // 3. Return ? F.[[Call]](V, argumentsList). - return function.as_function().internal_call(this_value, arguments_list); + ExecutionContext* callee_context = nullptr; + auto& function_object = function.as_function(); + size_t registers_and_constants_and_locals_count = 0; + size_t argument_count = arguments_list.size(); + TRY(function_object.get_stack_frame_size(registers_and_constants_and_locals_count, argument_count)); + ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, registers_and_constants_and_locals_count, argument_count); + + auto* argument_values = callee_context->arguments.data(); + for (size_t i = 0; i < arguments_list.size(); ++i) + argument_values[i] = arguments_list[i]; + callee_context->passed_argument_count = arguments_list.size(); + + return function_object.internal_call(*callee_context, this_value); } ThrowCompletionOr call_impl(VM&, FunctionObject& function, Value this_value, ReadonlySpan arguments_list) @@ -70,7 +82,18 @@ ThrowCompletionOr call_impl(VM&, FunctionObject& function, Value this_val // Note: Called with a FunctionObject ref // 3. Return ? F.[[Call]](V, argumentsList). - return function.internal_call(this_value, arguments_list); + ExecutionContext* callee_context = nullptr; + size_t registers_and_constants_and_locals_count = 0; + size_t argument_count = arguments_list.size(); + TRY(function.get_stack_frame_size(registers_and_constants_and_locals_count, argument_count)); + ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, registers_and_constants_and_locals_count, argument_count); + + auto* argument_values = callee_context->arguments.data(); + for (size_t i = 0; i < arguments_list.size(); ++i) + argument_values[i] = arguments_list[i]; + callee_context->passed_argument_count = arguments_list.size(); + + return function.internal_call(*callee_context, this_value); } // 7.3.15 Construct ( F [ , argumentsList [ , newTarget ] ] ), https://tc39.es/ecma262/#sec-construct diff --git a/Libraries/LibJS/Runtime/BoundFunction.cpp b/Libraries/LibJS/Runtime/BoundFunction.cpp index a8d4be7df0b..6356e3b8faf 100644 --- a/Libraries/LibJS/Runtime/BoundFunction.cpp +++ b/Libraries/LibJS/Runtime/BoundFunction.cpp @@ -43,10 +43,8 @@ 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 BoundFunction::internal_call([[maybe_unused]] Value this_argument, ReadonlySpan arguments_list) +ThrowCompletionOr BoundFunction::internal_call(ExecutionContext& outer_context, [[maybe_unused]] Value this_argument) { - auto& vm = this->vm(); - // 1. Let target be F.[[BoundTargetFunction]]. auto& target = *m_bound_target_function; @@ -57,13 +55,24 @@ ThrowCompletionOr BoundFunction::internal_call([[maybe_unused]] Value thi auto& bound_args = m_bound_arguments; // 4. Let args be the list-concatenation of boundArgs and argumentsList. - Vector args; - args.ensure_capacity(bound_args.size() + arguments_list.size()); - args.extend(bound_args); - args.append(arguments_list.data(), arguments_list.size()); + + ExecutionContext* callee_context = nullptr; + size_t registers_and_constants_and_locals_count = 0; + size_t argument_count = bound_args.size() + outer_context.arguments.size(); + TRY(target.get_stack_frame_size(registers_and_constants_and_locals_count, argument_count)); + ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, registers_and_constants_and_locals_count, argument_count); + + auto* argument_values = callee_context->arguments.data(); + for (size_t i = 0; i < bound_args.size(); ++i) + argument_values[i] = bound_args[i]; + + for (size_t i = 0; i < outer_context.arguments.size(); ++i) + argument_values[bound_args.size() + i] = outer_context.arguments[i]; + + callee_context->passed_argument_count = bound_args.size() + outer_context.arguments.size(); // 5. Return ? Call(target, boundThis, args). - return call(vm, &target, bound_this, args.span()); + return target.internal_call(*callee_context, bound_this); } // 10.4.1.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-bound-function-exotic-objects-construct-argumentslist-newtarget diff --git a/Libraries/LibJS/Runtime/BoundFunction.h b/Libraries/LibJS/Runtime/BoundFunction.h index 9f90e3e7779..2f4665726b5 100644 --- a/Libraries/LibJS/Runtime/BoundFunction.h +++ b/Libraries/LibJS/Runtime/BoundFunction.h @@ -20,7 +20,7 @@ public: virtual ~BoundFunction() override = default; - virtual ThrowCompletionOr internal_call(Value this_argument, ReadonlySpan arguments_list) override; + virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) override; virtual ThrowCompletionOr> internal_construct(ReadonlySpan arguments_list, FunctionObject& new_target) override; virtual bool is_strict_mode() const override { return m_bound_target_function->is_strict_mode(); } diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 87f11fda074..3eec2d9e1b4 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -481,46 +481,39 @@ void ECMAScriptFunctionObject::initialize(Realm& realm) } } -// 10.2.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist -ThrowCompletionOr ECMAScriptFunctionObject::internal_call(Value this_argument, ReadonlySpan arguments_list) +ThrowCompletionOr ECMAScriptFunctionObject::get_stack_frame_size(size_t& registers_and_constants_and_locals_count, size_t& argument_count) { - auto& vm = this->vm(); - - // 1. Let callerContext be the running execution context. - // NOTE: No-op, kept by the VM in its execution context stack. - if (!m_bytecode_executable) { if (!ecmascript_code().bytecode_executable()) { if (is_module_wrapper()) { - const_cast(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, ecmascript_code(), kind(), name()))); + const_cast(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm(), ecmascript_code(), kind(), name()))); } else { - const_cast(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, *this))); + const_cast(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm(), *this))); } } m_bytecode_executable = ecmascript_code().bytecode_executable(); } + registers_and_constants_and_locals_count = m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size() + m_bytecode_executable->local_variable_names.size(); + argument_count = max(argument_count, formal_parameters().size()); + return {}; +} - u32 arguments_count = max(arguments_list.size(), formal_parameters().size()); - auto registers_and_constants_and_locals_count = m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size() + m_bytecode_executable->local_variable_names.size(); - ExecutionContext* callee_context = nullptr; - ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, registers_and_constants_and_locals_count, arguments_count); +// 10.2.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist +ThrowCompletionOr ECMAScriptFunctionObject::internal_call(ExecutionContext& callee_context, Value this_argument) +{ + auto& vm = this->vm(); - // Non-standard - 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(); - if (arguments_list.size() < formal_parameters().size()) { - for (size_t i = arguments_list.size(); i < formal_parameters().size(); ++i) - arguments[i] = js_undefined(); - } + VERIFY(m_bytecode_executable); + + // 1. Let callerContext be the running execution context. + // NOTE: No-op, kept by the VM in its execution context stack. // 2. Let calleeContext be PrepareForOrdinaryCall(F, undefined). // NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check. - TRY(prepare_for_ordinary_call(*callee_context, nullptr)); + TRY(prepare_for_ordinary_call(callee_context, nullptr)); // 3. Assert: calleeContext is now the running execution context. - VERIFY(&vm.running_execution_context() == callee_context); + VERIFY(&vm.running_execution_context() == &callee_context); // 4. If F.[[IsClassConstructor]] is true, then if (is_class_constructor()) { @@ -537,7 +530,7 @@ ThrowCompletionOr ECMAScriptFunctionObject::internal_call(Value this_argu // 5. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument). if (uses_this()) - ordinary_call_bind_this(*callee_context, this_argument); + ordinary_call_bind_this(callee_context, this_argument); // 6. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)). auto result = ordinary_call_evaluate_body(); diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index 0bfd51aa4dd..920463c54fe 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -116,7 +116,8 @@ public: virtual void initialize(Realm&) override; virtual ~ECMAScriptFunctionObject() override = default; - virtual ThrowCompletionOr internal_call(Value this_argument, ReadonlySpan arguments_list) override; + virtual ThrowCompletionOr get_stack_frame_size(size_t& registers_and_constants_and_locals_slots, size_t& argument_count) override; + virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) override; virtual ThrowCompletionOr> internal_construct(ReadonlySpan arguments_list, FunctionObject& new_target) override; void make_method(Object& home_object); diff --git a/Libraries/LibJS/Runtime/ExecutionContext.h b/Libraries/LibJS/Runtime/ExecutionContext.h index 8a759de8644..a171491a510 100644 --- a/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Libraries/LibJS/Runtime/ExecutionContext.h @@ -114,7 +114,7 @@ private: u32 registers_and_constants_and_locals_and_arguments_count { 0 }; }; -#define ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(execution_context, \ +#define ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK_WITHOUT_CLEARING_ARGS(execution_context, \ registers_and_constants_and_locals_count, \ arguments_count) \ auto execution_context_size = sizeof(JS::ExecutionContext) \ @@ -130,6 +130,16 @@ private: execution_context->~ExecutionContext(); \ }) +#define ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(execution_context, registers_and_constants_and_locals_count, \ + arguments_count) \ + ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK_WITHOUT_CLEARING_ARGS(execution_context, \ + registers_and_constants_and_locals_count, arguments_count); \ + do { \ + for (size_t i = 0; i < execution_context->arguments.size(); i++) { \ + execution_context->arguments[i] = JS::js_undefined(); \ + } \ + } while (0) + struct StackTraceElement { ExecutionContext* execution_context; RefPtr source_range; diff --git a/Libraries/LibJS/Runtime/FunctionObject.h b/Libraries/LibJS/Runtime/FunctionObject.h index ac1b8803c5b..c87945bab3c 100644 --- a/Libraries/LibJS/Runtime/FunctionObject.h +++ b/Libraries/LibJS/Runtime/FunctionObject.h @@ -23,7 +23,8 @@ public: // Table 5: Additional Essential Internal Methods of Function Objects, https://tc39.es/ecma262/#table-additional-essential-internal-methods-of-function-objects - virtual ThrowCompletionOr internal_call(Value this_argument, ReadonlySpan arguments_list) = 0; + virtual ThrowCompletionOr get_stack_frame_size([[maybe_unused]] size_t& registers_and_constants_and_locals_count, [[maybe_unused]] size_t& argument_count) { return {}; } + virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) = 0; virtual ThrowCompletionOr> internal_construct([[maybe_unused]] ReadonlySpan arguments_list, [[maybe_unused]] FunctionObject& new_target) { VERIFY_NOT_REACHED(); } void set_function_name(Variant const& name_arg, Optional const& prefix = {}); diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Libraries/LibJS/Runtime/FunctionPrototype.cpp index d5522add542..dce44e3232e 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -40,7 +40,7 @@ void FunctionPrototype::initialize(Realm& realm) define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable); } -ThrowCompletionOr FunctionPrototype::internal_call(Value, ReadonlySpan) +ThrowCompletionOr FunctionPrototype::internal_call(ExecutionContext&, Value) { // The Function prototype object: // - accepts any arguments and returns undefined when invoked. diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.h b/Libraries/LibJS/Runtime/FunctionPrototype.h index 493fcd53ca4..d56b755dc50 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.h +++ b/Libraries/LibJS/Runtime/FunctionPrototype.h @@ -18,7 +18,7 @@ public: virtual void initialize(Realm&) override; virtual ~FunctionPrototype() override = default; - virtual ThrowCompletionOr internal_call(Value this_argument, ReadonlySpan arguments_list) override; + virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) override; private: explicit FunctionPrototype(Realm&); diff --git a/Libraries/LibJS/Runtime/NativeFunction.cpp b/Libraries/LibJS/Runtime/NativeFunction.cpp index 4592c616269..68e2bad14d5 100644 --- a/Libraries/LibJS/Runtime/NativeFunction.cpp +++ b/Libraries/LibJS/Runtime/NativeFunction.cpp @@ -110,7 +110,7 @@ NativeFunction::NativeFunction(FlyString 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 NativeFunction::internal_call(Value this_argument, ReadonlySpan arguments_list) +ThrowCompletionOr NativeFunction::internal_call(ExecutionContext& callee_context, Value this_argument) { auto& vm = this->vm(); @@ -119,12 +119,10 @@ ThrowCompletionOr NativeFunction::internal_call(Value this_argument, Read // 2. If callerContext is not already suspended, suspend callerContext. // 3. Let calleeContext be a new execution context. - ExecutionContext* callee_context = nullptr; - ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, 0, arguments_list.size()); // 4. Set the Function of calleeContext to F. - callee_context->function = this; - callee_context->function_name = m_name_string; + callee_context.function = this; + callee_context.function_name = m_name_string; // 5. Let calleeRealm be F.[[Realm]]. auto callee_realm = m_realm; @@ -138,29 +136,27 @@ ThrowCompletionOr NativeFunction::internal_call(Value this_argument, Read VERIFY(callee_realm); // 6. Set the Realm of calleeContext to calleeRealm. - callee_context->realm = callee_realm; + callee_context.realm = callee_realm; // 7. Set the ScriptOrModule of calleeContext to null. // Note: This is already the default value. // 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.this_value = this_argument; - callee_context->lexical_environment = caller_context.lexical_environment; - callee_context->variable_environment = caller_context.variable_environment; + callee_context.lexical_environment = caller_context.lexical_environment; + callee_context.variable_environment = caller_context.variable_environment; // Note: Keeping the private environment is probably only needed because of async methods in classes // calling async_block_start which goes through a NativeFunction here. - callee_context->private_environment = caller_context.private_environment; + callee_context.private_environment = caller_context.private_environment; // NOTE: This is a LibJS specific hack for NativeFunction to inherit the strictness of its caller. - callee_context->is_strict_mode = vm.in_strict_mode(); + callee_context.is_strict_mode = vm.in_strict_mode(); // -------------------------------------------------------------------------- // 9. Push calleeContext onto the execution context stack; calleeContext is now the running execution context. - TRY(vm.push_execution_context(*callee_context, {})); + TRY(vm.push_execution_context(callee_context, {})); // 10. Let result be the Completion Record that is the result of evaluating F in a manner that conforms to the specification of F. thisArgument is the this value, argumentsList provides the named parameters, and the NewTarget value is undefined. auto result = call(); @@ -184,6 +180,10 @@ ThrowCompletionOr> NativeFunction::internal_construct(ReadonlySp // 3. Let calleeContext be a new execution context. ExecutionContext* callee_context = nullptr; ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, 0, arguments_list.size()); + // 8. Perform any necessary implementation-defined initialization of calleeContext. + for (size_t i = 0; i < arguments_list.size(); ++i) + callee_context->arguments[i] = arguments_list[i]; + callee_context->passed_argument_count = arguments_list.size(); // 4. Set the Function of calleeContext to F. callee_context->function = this; @@ -206,10 +206,6 @@ ThrowCompletionOr> NativeFunction::internal_construct(ReadonlySp // 7. Set the ScriptOrModule of calleeContext to null. // Note: This is already the default value. - // 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->lexical_environment = caller_context.lexical_environment; callee_context->variable_environment = caller_context.variable_environment; diff --git a/Libraries/LibJS/Runtime/NativeFunction.h b/Libraries/LibJS/Runtime/NativeFunction.h index 502be0d77e9..3835b0bf81a 100644 --- a/Libraries/LibJS/Runtime/NativeFunction.h +++ b/Libraries/LibJS/Runtime/NativeFunction.h @@ -26,7 +26,7 @@ public: virtual ~NativeFunction() override = default; - virtual ThrowCompletionOr internal_call(Value this_argument, ReadonlySpan arguments_list) override; + virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) override; virtual ThrowCompletionOr> internal_construct(ReadonlySpan 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". diff --git a/Libraries/LibJS/Runtime/ProxyObject.cpp b/Libraries/LibJS/Runtime/ProxyObject.cpp index abc2b9714e1..4bb1b760bd0 100644 --- a/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -779,7 +779,7 @@ ThrowCompletionOr> 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 ProxyObject::internal_call(Value this_argument, ReadonlySpan arguments_list) +ThrowCompletionOr ProxyObject::internal_call(ExecutionContext& callee_context, Value this_argument) { LIMIT_PROXY_RECURSION_DEPTH(); @@ -802,11 +802,11 @@ ThrowCompletionOr ProxyObject::internal_call(Value this_argument, Readonl // 6. If trap is undefined, then if (!trap) { // a. Return ? Call(target, thisArgument, argumentsList). - return call(vm, m_target, this_argument, arguments_list); + return call(vm, m_target, this_argument, callee_context.arguments); } // 7. Let argArray be CreateArrayFromList(argumentsList). - auto arguments_array = Array::create_from(realm, arguments_list); + auto arguments_array = Array::create_from(realm, callee_context.arguments); // 8. Return ? Call(trap, handler, « target, thisArgument, argArray »). return call(vm, trap, m_handler, m_target, this_argument, arguments_array); diff --git a/Libraries/LibJS/Runtime/ProxyObject.h b/Libraries/LibJS/Runtime/ProxyObject.h index 8f77eea9738..b49105e6cf4 100644 --- a/Libraries/LibJS/Runtime/ProxyObject.h +++ b/Libraries/LibJS/Runtime/ProxyObject.h @@ -42,7 +42,7 @@ public: virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override; virtual ThrowCompletionOr internal_delete(PropertyKey const&) override; virtual ThrowCompletionOr> internal_own_property_keys() const override; - virtual ThrowCompletionOr internal_call(Value this_argument, ReadonlySpan arguments_list) override; + virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) override; virtual ThrowCompletionOr> internal_construct(ReadonlySpan arguments_list, FunctionObject& new_target) override; ThrowCompletionOr validate_non_revoked_proxy() const; diff --git a/Libraries/LibJS/Runtime/WrappedFunction.cpp b/Libraries/LibJS/Runtime/WrappedFunction.cpp index e3d0bcb3de4..2be73e70eb2 100644 --- a/Libraries/LibJS/Runtime/WrappedFunction.cpp +++ b/Libraries/LibJS/Runtime/WrappedFunction.cpp @@ -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 WrappedFunction::internal_call(Value this_argument, ReadonlySpan arguments_list) +ThrowCompletionOr WrappedFunction::internal_call(ExecutionContext& callee_context, Value this_argument) { auto& vm = this->vm(); @@ -62,16 +62,13 @@ ThrowCompletionOr WrappedFunction::internal_call(Value this_argument, Rea // NOTE: No-op, kept by the VM in its execution context stack. // 2. Let calleeContext be PrepareForWrappedFunctionCall(F). - ExecutionContext* callee_context = nullptr; - ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, 0, 0); - - prepare_for_wrapped_function_call(*this, *callee_context); + prepare_for_wrapped_function_call(*this, callee_context); // 3. Assert: calleeContext is now the running execution context. - VERIFY(&vm.running_execution_context() == callee_context); + VERIFY(&vm.running_execution_context() == &callee_context); // 4. Let result be Completion(OrdinaryWrappedFunctionCall(F, thisArgument, argumentsList)). - auto result = ordinary_wrapped_function_call(*this, this_argument, arguments_list); + auto result = ordinary_wrapped_function_call(*this, this_argument, callee_context.arguments); // 5. Remove calleeContext from the execution context stack and restore callerContext as the running execution context. vm.pop_execution_context(); @@ -80,13 +77,18 @@ ThrowCompletionOr WrappedFunction::internal_call(Value this_argument, Rea return result; } +ThrowCompletionOr WrappedFunction::get_stack_frame_size(size_t& registers_and_constants_and_locals_count, size_t& argument_count) +{ + return m_wrapped_target_function->get_stack_frame_size(registers_and_constants_and_locals_count, argument_count); +} + // 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 ordinary_wrapped_function_call(WrappedFunction const& function, Value this_argument, ReadonlySpan arguments_list) +ThrowCompletionOr ordinary_wrapped_function_call(WrappedFunction& function, Value this_argument, Span arguments_list) { auto& vm = function.vm(); // 1. Let target be F.[[WrappedTargetFunction]]. - auto const& target = function.wrapped_target_function(); + auto& target = function.wrapped_target_function(); // 2. Assert: IsCallable(target) is true. VERIFY(Value(&target).is_function()); @@ -134,7 +136,7 @@ ThrowCompletionOr ordinary_wrapped_function_call(WrappedFunction const& f } // 2.3 PrepareForWrappedFunctionCall ( F: a wrapped function exotic object, ), https://tc39.es/proposal-shadowrealm/#sec-prepare-for-wrapped-function-call -void prepare_for_wrapped_function_call(WrappedFunction const& function, ExecutionContext& callee_context) +void prepare_for_wrapped_function_call(WrappedFunction& function, ExecutionContext& callee_context) { auto& vm = function.vm(); diff --git a/Libraries/LibJS/Runtime/WrappedFunction.h b/Libraries/LibJS/Runtime/WrappedFunction.h index d29e67db66a..86bc0a7c95c 100644 --- a/Libraries/LibJS/Runtime/WrappedFunction.h +++ b/Libraries/LibJS/Runtime/WrappedFunction.h @@ -20,13 +20,15 @@ public: virtual ~WrappedFunction() = default; - virtual ThrowCompletionOr internal_call(Value this_argument, ReadonlySpan arguments_list) override; + virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) override; virtual Realm* realm() const override { return m_realm; } FunctionObject const& wrapped_target_function() const { return m_wrapped_target_function; } FunctionObject& wrapped_target_function() { return m_wrapped_target_function; } + virtual ThrowCompletionOr get_stack_frame_size(size_t& registers_and_constants_and_locals_count, size_t& argument_count) override; + private: WrappedFunction(Realm&, FunctionObject&, Object& prototype); @@ -37,7 +39,7 @@ private: GC::Ref m_realm; // [[Realm]] }; -ThrowCompletionOr ordinary_wrapped_function_call(WrappedFunction const&, Value this_argument, ReadonlySpan arguments_list); -void prepare_for_wrapped_function_call(WrappedFunction const&, ExecutionContext& callee_context); +ThrowCompletionOr ordinary_wrapped_function_call(WrappedFunction&, Value this_argument, Span arguments_list); +void prepare_for_wrapped_function_call(WrappedFunction&, ExecutionContext& callee_context); } diff --git a/Libraries/LibWeb/WebDriver/ExecuteScript.cpp b/Libraries/LibWeb/WebDriver/ExecuteScript.cpp index e4951b8c10a..1a0fefb0931 100644 --- a/Libraries/LibWeb/WebDriver/ExecuteScript.cpp +++ b/Libraries/LibWeb/WebDriver/ExecuteScript.cpp @@ -92,7 +92,7 @@ static JS::ThrowCompletionOr execute_a_function_body(HTML::BrowsingCo // 9. Let completion be Function.[[Call]](window, parameters) with function as the this value. // NOTE: This is not entirely clear, but I don't think they mean actually passing `function` as // the this value argument, but using it as the object [[Call]] is executed on. - auto completion = function->internal_call(window, parameters); + auto completion = JS::call(realm.vm(), *function, window, parameters); // 10. Clean up after running a callback with environment settings. HTML::clean_up_after_running_callback(realm); diff --git a/Libraries/LibWeb/WebDriver/JSON.cpp b/Libraries/LibWeb/WebDriver/JSON.cpp index f614f9f26b5..6ae29a2809c 100644 --- a/Libraries/LibWeb/WebDriver/JSON.cpp +++ b/Libraries/LibWeb/WebDriver/JSON.cpp @@ -253,7 +253,7 @@ static Response internal_json_clone(HTML::BrowsingContext const& browsing_contex // -> has an own property named "toJSON" that is a Function if (auto to_json = object.get_without_side_effects(vm.names.toJSON); to_json.is_function()) { // Return success with the value returned by Function.[[Call]](toJSON) with value as the this value. - auto to_json_result = TRY_OR_JS_ERROR(to_json.as_function().internal_call(value, GC::RootVector { vm.heap() })); + auto to_json_result = TRY_OR_JS_ERROR(JS::call(vm, to_json.as_function(), value)); if (!to_json_result.is_string()) return WebDriver::Error::from_code(ErrorCode::JavascriptError, "toJSON did not return a String"sv);