mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-21 08:48:57 +00:00
LibJS: Allocate Call{Construct,DirectEval,Builtin) contexts up front
We already do this for normal Call contexts, so this is just continuing to propagate the same pattern to other instructions. Fixes #6026
This commit is contained in:
parent
849ade88ce
commit
e5b07858a2
Notes:
github-actions[bot]
2025-08-31 13:25:46 +00:00
Author: https://github.com/awesomekling
Commit: e5b07858a2
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6035
11 changed files with 81 additions and 98 deletions
|
@ -2836,80 +2836,72 @@ static ThrowCompletionOr<Value> dispatch_builtin_call(Bytecode::Interpreter& int
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> Call::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
template<CallType call_type>
|
||||
static ThrowCompletionOr<void> execute_call(
|
||||
Bytecode::Interpreter& interpreter,
|
||||
Value callee,
|
||||
Value this_value,
|
||||
ReadonlySpan<Operand> arguments,
|
||||
Operand dst,
|
||||
Optional<StringTableIndex> const& expression_string)
|
||||
{
|
||||
auto callee = interpreter.get(m_callee);
|
||||
|
||||
if (!callee.is_function()) [[unlikely]] {
|
||||
return throw_type_error_for_callee(interpreter, callee, "function"sv, m_expression_string);
|
||||
}
|
||||
TRY(throw_if_needed_for_call(interpreter, callee, call_type, expression_string));
|
||||
|
||||
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;
|
||||
size_t argument_count = arguments.size();
|
||||
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));
|
||||
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK_WITHOUT_CLEARING_ARGS(callee_context, registers_and_constants_and_locals_count, max(arguments.size(), 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;
|
||||
auto const insn_argument_count = arguments.size();
|
||||
|
||||
for (size_t i = 0; i < insn_argument_count; ++i)
|
||||
callee_context_argument_values[i] = interpreter.get(m_arguments[i]);
|
||||
callee_context_argument_values[i] = interpreter.get(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);
|
||||
Value retval;
|
||||
if (call_type == CallType::DirectEval && callee == interpreter.realm().intrinsics().eval_function()) {
|
||||
retval = TRY(perform_eval(interpreter.vm(), !callee_context->arguments.is_empty() ? callee_context->arguments[0] : js_undefined(), interpreter.vm().in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct));
|
||||
} else if (call_type == CallType::Construct) {
|
||||
retval = TRY(function.internal_construct(*callee_context, function));
|
||||
} else {
|
||||
retval = TRY(function.internal_call(*callee_context, this_value));
|
||||
}
|
||||
interpreter.set(dst, retval);
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CallConstruct::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
ThrowCompletionOr<void> Call::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto callee = interpreter.get(m_callee);
|
||||
return execute_call<CallType::Call>(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||
}
|
||||
|
||||
TRY(throw_if_needed_for_call(interpreter, callee, CallType::Construct, 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, Value(), CallType::Construct, callee, argument_values)));
|
||||
return {};
|
||||
NEVER_INLINE ThrowCompletionOr<void> CallConstruct::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return execute_call<CallType::Construct>(interpreter, interpreter.get(m_callee), js_undefined(), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CallDirectEval::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto callee = interpreter.get(m_callee);
|
||||
|
||||
TRY(throw_if_needed_for_call(interpreter, callee, CallType::DirectEval, 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::DirectEval, callee, argument_values)));
|
||||
return {};
|
||||
return execute_call<CallType::DirectEval>(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CallBuiltin::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto callee = interpreter.get(m_callee);
|
||||
|
||||
TRY(throw_if_needed_for_call(interpreter, callee, CallType::Call, expression_string()));
|
||||
|
||||
if (m_argument_count == Bytecode::builtin_argument_count(m_builtin) && callee.is_object() && interpreter.realm().get_builtin_value(m_builtin) == &callee.as_object()) {
|
||||
interpreter.set(dst(), TRY(dispatch_builtin_call(interpreter, m_builtin, { m_arguments, m_argument_count })));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
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)));
|
||||
return {};
|
||||
return execute_call<CallType::Call>(interpreter, callee, interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
|
|
|
@ -105,7 +105,18 @@ ThrowCompletionOr<GC::Ref<Object>> construct_impl(VM&, FunctionObject& function,
|
|||
// 2. If argumentsList is not present, set argumentsList to a new empty List.
|
||||
|
||||
// 3. Return ? F.[[Construct]](argumentsList, newTarget).
|
||||
return function.internal_construct(arguments_list, *new_target);
|
||||
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_construct(*callee_context, *new_target);
|
||||
}
|
||||
|
||||
// 7.3.19 LengthOfArrayLike ( obj ), https://tc39.es/ecma262/#sec-lengthofarraylike
|
||||
|
|
|
@ -69,10 +69,8 @@ ThrowCompletionOr<Value> BoundFunction::internal_call(ExecutionContext& callee_c
|
|||
}
|
||||
|
||||
// 10.4.1.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-bound-function-exotic-objects-construct-argumentslist-newtarget
|
||||
ThrowCompletionOr<GC::Ref<Object>> BoundFunction::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
|
||||
ThrowCompletionOr<GC::Ref<Object>> BoundFunction::internal_construct(ExecutionContext& callee_context, FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 1. Let target be F.[[BoundTargetFunction]].
|
||||
auto& target = *m_bound_target_function;
|
||||
|
||||
|
@ -83,9 +81,14 @@ ThrowCompletionOr<GC::Ref<Object>> BoundFunction::internal_construct(ReadonlySpa
|
|||
auto& bound_args = m_bound_arguments;
|
||||
|
||||
// 4. Let args be the list-concatenation of boundArgs and argumentsList.
|
||||
auto args = GC::RootVector<Value> { heap() };
|
||||
args.extend(bound_args);
|
||||
args.append(arguments_list.data(), arguments_list.size());
|
||||
auto* argument_values = callee_context.arguments.data();
|
||||
|
||||
for (ssize_t i = static_cast<ssize_t>(callee_context.arguments.size()) - 1; i >= static_cast<ssize_t>(bound_args.size()); --i)
|
||||
argument_values[i] = argument_values[i - bound_args.size()];
|
||||
for (size_t i = 0; i < bound_args.size(); ++i)
|
||||
argument_values[i] = bound_args[i];
|
||||
|
||||
callee_context.passed_argument_count += bound_args.size();
|
||||
|
||||
// 5. If SameValue(F, newTarget) is true, set newTarget to target.
|
||||
auto* final_new_target = &new_target;
|
||||
|
@ -93,7 +96,7 @@ ThrowCompletionOr<GC::Ref<Object>> BoundFunction::internal_construct(ReadonlySpa
|
|||
final_new_target = ⌖
|
||||
|
||||
// 6. Return ? Construct(target, args, newTarget).
|
||||
return construct(vm, target, args.span(), final_new_target);
|
||||
return target.internal_construct(callee_context, *final_new_target);
|
||||
}
|
||||
|
||||
void BoundFunction::visit_edges(Visitor& visitor)
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
virtual ~BoundFunction() override = default;
|
||||
|
||||
virtual ThrowCompletionOr<Value> internal_call(ExecutionContext&, Value this_argument) override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target) override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ExecutionContext& arguments_list, FunctionObject& new_target) override;
|
||||
|
||||
virtual bool is_strict_mode() const override { return m_bound_target_function->is_strict_mode(); }
|
||||
virtual bool has_constructor() const override { return m_bound_target_function->has_constructor(); }
|
||||
|
|
|
@ -546,35 +546,11 @@ FLATTEN ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Executi
|
|||
}
|
||||
|
||||
// 10.2.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
|
||||
ThrowCompletionOr<GC::Ref<Object>> ECMAScriptFunctionObject::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
|
||||
ThrowCompletionOr<GC::Ref<Object>> ECMAScriptFunctionObject::internal_construct(ExecutionContext& callee_context, FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
if (!m_bytecode_executable) {
|
||||
if (!ecmascript_code().bytecode_executable()) {
|
||||
if (is_module_wrapper()) {
|
||||
const_cast<Statement&>(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, ecmascript_code(), kind(), name())));
|
||||
} else {
|
||||
const_cast<Statement&>(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, *this)));
|
||||
}
|
||||
}
|
||||
m_bytecode_executable = ecmascript_code().bytecode_executable();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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();
|
||||
}
|
||||
ASSERT(m_bytecode_executable);
|
||||
|
||||
// 1. Let callerContext be the running execution context.
|
||||
// NOTE: No-op, kept by the VM in its execution context stack.
|
||||
|
@ -591,16 +567,16 @@ ThrowCompletionOr<GC::Ref<Object>> ECMAScriptFunctionObject::internal_construct(
|
|||
}
|
||||
|
||||
// 4. Let calleeContext be PrepareForOrdinaryCall(F, newTarget).
|
||||
prepare_for_ordinary_call(vm, *callee_context, &new_target);
|
||||
prepare_for_ordinary_call(vm, callee_context, &new_target);
|
||||
|
||||
// 5. Assert: calleeContext is now the running execution context.
|
||||
VERIFY(&vm.running_execution_context() == callee_context);
|
||||
VERIFY(&vm.running_execution_context() == &callee_context);
|
||||
|
||||
// 6. If kind is base, then
|
||||
if (kind == ConstructorKind::Base) {
|
||||
// a. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
|
||||
if (uses_this())
|
||||
ordinary_call_bind_this(vm, *callee_context, this_argument);
|
||||
ordinary_call_bind_this(vm, callee_context, this_argument);
|
||||
|
||||
// b. Let initializeResult be Completion(InitializeInstanceElements(thisArgument, F)).
|
||||
auto initialize_result = this_argument->initialize_instance_elements(*this);
|
||||
|
@ -616,7 +592,7 @@ ThrowCompletionOr<GC::Ref<Object>> ECMAScriptFunctionObject::internal_construct(
|
|||
}
|
||||
|
||||
// 7. Let constructorEnv be the LexicalEnvironment of calleeContext.
|
||||
auto constructor_env = callee_context->lexical_environment;
|
||||
auto constructor_env = callee_context.lexical_environment;
|
||||
|
||||
// 8. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)).
|
||||
auto result = ordinary_call_evaluate_body(vm);
|
||||
|
|
|
@ -119,7 +119,7 @@ public:
|
|||
|
||||
virtual ThrowCompletionOr<void> get_stack_frame_size(size_t& registers_and_constants_and_locals_slots, size_t& argument_count) override;
|
||||
virtual ThrowCompletionOr<Value> internal_call(ExecutionContext&, Value this_argument) override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target) override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ExecutionContext&, FunctionObject& new_target) override;
|
||||
|
||||
void make_method(Object& home_object);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
virtual ThrowCompletionOr<void> get_stack_frame_size([[maybe_unused]] size_t& registers_and_constants_and_locals_count, [[maybe_unused]] size_t& argument_count) { return {}; }
|
||||
virtual ThrowCompletionOr<Value> internal_call(ExecutionContext&, Value this_argument) = 0;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct([[maybe_unused]] ReadonlySpan<Value> arguments_list, [[maybe_unused]] FunctionObject& new_target) { VERIFY_NOT_REACHED(); }
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ExecutionContext&, [[maybe_unused]] FunctionObject& new_target) { VERIFY_NOT_REACHED(); }
|
||||
|
||||
void set_function_name(Variant<PropertyKey, PrivateName> const& name_arg, Optional<StringView> const& prefix = {});
|
||||
void set_function_length(double length);
|
||||
|
|
|
@ -170,7 +170,7 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(ExecutionContext& callee_
|
|||
}
|
||||
|
||||
// 10.3.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-built-in-function-objects-construct-argumentslist-newtarget
|
||||
ThrowCompletionOr<GC::Ref<Object>> NativeFunction::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
|
||||
ThrowCompletionOr<GC::Ref<Object>> NativeFunction::internal_construct(ExecutionContext& callee_context, FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
|
@ -179,16 +179,10 @@ ThrowCompletionOr<GC::Ref<Object>> NativeFunction::internal_construct(ReadonlySp
|
|||
|
||||
// 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());
|
||||
// 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;
|
||||
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;
|
||||
|
@ -202,21 +196,21 @@ ThrowCompletionOr<GC::Ref<Object>> NativeFunction::internal_construct(ReadonlySp
|
|||
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.
|
||||
|
||||
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: This is a LibJS specific hack for NativeFunction to inherit the strictness of its caller.
|
||||
callee_context->is_strict_mode = caller_context.is_strict_mode;
|
||||
callee_context.is_strict_mode = caller_context.is_strict_mode;
|
||||
|
||||
// </8.> --------------------------------------------------------------------------
|
||||
|
||||
// 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. The this value is uninitialized, argumentsList provides the named parameters, and newTarget provides the NewTarget value.
|
||||
auto result = construct(new_target);
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
virtual ~NativeFunction() override = default;
|
||||
|
||||
virtual ThrowCompletionOr<Value> internal_call(ExecutionContext&, Value this_argument) override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target) override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ExecutionContext&, 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.
|
||||
|
|
|
@ -827,7 +827,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<GC::Ref<Object>> ProxyObject::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
|
||||
ThrowCompletionOr<GC::Ref<Object>> ProxyObject::internal_construct(ExecutionContext& callee_context, FunctionObject& new_target)
|
||||
{
|
||||
LIMIT_PROXY_RECURSION_DEPTH();
|
||||
|
||||
|
@ -850,11 +850,11 @@ ThrowCompletionOr<GC::Ref<Object>> ProxyObject::internal_construct(ReadonlySpan<
|
|||
// 7. If trap is undefined, then
|
||||
if (!trap) {
|
||||
// a. Return ? Construct(target, argumentsList, newTarget).
|
||||
return construct(vm, static_cast<FunctionObject&>(*m_target), arguments_list, &new_target);
|
||||
return as<FunctionObject>(*m_target).internal_construct(callee_context, new_target);
|
||||
}
|
||||
|
||||
// 8. Let argArray be CreateArrayFromList(argumentsList).
|
||||
auto arguments_array = Array::create_from(realm, arguments_list);
|
||||
auto arguments_array = Array::create_from(realm, callee_context.arguments);
|
||||
|
||||
// 9. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »).
|
||||
auto new_object = TRY(call(vm, trap, m_handler, m_target, arguments_array, &new_target));
|
||||
|
@ -890,4 +890,9 @@ void ProxyObject::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(m_handler);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ProxyObject::get_stack_frame_size(size_t& registers_and_constants_and_locals_count, size_t& argument_count)
|
||||
{
|
||||
return as<FunctionObject>(*m_target).get_stack_frame_size(registers_and_constants_and_locals_count, argument_count);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
|
||||
virtual ThrowCompletionOr<GC::RootVector<Value>> internal_own_property_keys() const override;
|
||||
virtual ThrowCompletionOr<Value> internal_call(ExecutionContext&, Value this_argument) override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target) override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ExecutionContext&, FunctionObject& new_target) override;
|
||||
ThrowCompletionOr<void> validate_non_revoked_proxy() const;
|
||||
|
||||
private:
|
||||
|
@ -54,6 +54,8 @@ private:
|
|||
virtual bool is_function() const override { return m_target->is_function(); }
|
||||
virtual bool is_proxy_object() const final { return true; }
|
||||
|
||||
virtual ThrowCompletionOr<void> get_stack_frame_size(size_t& registers_and_constants_and_locals_count, size_t& argument_count) override;
|
||||
|
||||
GC::Ref<Object> m_target;
|
||||
GC::Ref<Object> m_handler;
|
||||
bool m_is_revoked { false };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue