mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-21 08:48:57 +00:00
LibJS: Allocate context up front when calling with argument array
This necessitated splitting CallWithArgumentArray into three variants, one for each call type (call, construct and direct eval).
This commit is contained in:
parent
e5b07858a2
commit
996ea109b3
Notes:
github-actions[bot]
2025-08-31 13:25:40 +00:00
Author: https://github.com/awesomekling
Commit: 996ea109b3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6035
4 changed files with 143 additions and 36 deletions
|
@ -1777,7 +1777,13 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> CallExpression::generat
|
||||||
|
|
||||||
if (has_spread) {
|
if (has_spread) {
|
||||||
auto arguments = TRY(arguments_to_array_for_call(generator, this->arguments())).value();
|
auto arguments = TRY(arguments_to_array_for_call(generator, this->arguments())).value();
|
||||||
generator.emit<Bytecode::Op::CallWithArgumentArray>(call_type, dst, callee, this_value, arguments, expression_string_index);
|
if (call_type == Op::CallType::Construct) {
|
||||||
|
generator.emit<Bytecode::Op::CallConstructWithArgumentArray>(dst, callee, this_value, arguments, expression_string_index);
|
||||||
|
} else if (call_type == Op::CallType::DirectEval) {
|
||||||
|
generator.emit<Bytecode::Op::CallDirectEvalWithArgumentArray>(dst, callee, this_value, arguments, expression_string_index);
|
||||||
|
} else {
|
||||||
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(dst, callee, this_value, arguments, expression_string_index);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Vector<ScopedOperand> argument_operands;
|
Vector<ScopedOperand> argument_operands;
|
||||||
argument_operands.ensure_capacity(arguments().size());
|
argument_operands.ensure_capacity(arguments().size());
|
||||||
|
@ -2019,7 +2025,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> YieldExpression::genera
|
||||||
auto array = generator.allocate_register();
|
auto array = generator.allocate_register();
|
||||||
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
|
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
|
||||||
auto inner_result = generator.allocate_register();
|
auto inner_result = generator.allocate_register();
|
||||||
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, inner_result, next_method, iterator, array);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_result, next_method, iterator, array);
|
||||||
|
|
||||||
// ii. If generatorKind is async, set innerResult to ? Await(innerResult).
|
// ii. If generatorKind is async, set innerResult to ? Await(innerResult).
|
||||||
if (generator.is_in_async_generator_function()) {
|
if (generator.is_in_async_generator_function()) {
|
||||||
|
@ -2108,7 +2114,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> YieldExpression::genera
|
||||||
// 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
|
// 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
|
||||||
auto received_value_array = generator.allocate_register();
|
auto received_value_array = generator.allocate_register();
|
||||||
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, received_value_array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
|
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, received_value_array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
|
||||||
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, inner_result, throw_method, iterator, received_value_array);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_result, throw_method, iterator, received_value_array);
|
||||||
|
|
||||||
// 2. If generatorKind is async, set innerResult to ? Await(innerResult).
|
// 2. If generatorKind is async, set innerResult to ? Await(innerResult).
|
||||||
if (generator.is_in_async_generator_function()) {
|
if (generator.is_in_async_generator_function()) {
|
||||||
|
@ -2205,7 +2211,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> YieldExpression::genera
|
||||||
auto call_array = generator.allocate_register();
|
auto call_array = generator.allocate_register();
|
||||||
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, call_array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
|
generator.emit_with_extra_operand_slots<Bytecode::Op::NewArray>(1, call_array, ReadonlySpan<ScopedOperand> { &received_completion_value, 1 });
|
||||||
auto inner_return_result = generator.allocate_register();
|
auto inner_return_result = generator.allocate_register();
|
||||||
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, inner_return_result, return_method, iterator, call_array);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(inner_return_result, return_method, iterator, call_array);
|
||||||
|
|
||||||
// v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
|
// v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
|
||||||
if (generator.is_in_async_generator_function()) {
|
if (generator.is_in_async_generator_function()) {
|
||||||
|
@ -2542,7 +2548,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TaggedTemplateLiteral::
|
||||||
generator.emit<Bytecode::Op::NewArray>(arguments);
|
generator.emit<Bytecode::Op::NewArray>(arguments);
|
||||||
|
|
||||||
auto dst = choose_dst(generator, preferred_dst);
|
auto dst = choose_dst(generator, preferred_dst);
|
||||||
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, dst, tag, this_value, arguments);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(dst, tag, this_value, arguments);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3502,7 +3508,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_optional_chain(Bytecode::G
|
||||||
TRY(reference.visit(
|
TRY(reference.visit(
|
||||||
[&](OptionalChain::Call const& call) -> Bytecode::CodeGenerationErrorOr<void> {
|
[&](OptionalChain::Call const& call) -> Bytecode::CodeGenerationErrorOr<void> {
|
||||||
auto arguments = TRY(arguments_to_array_for_call(generator, call.arguments)).value();
|
auto arguments = TRY(arguments_to_array_for_call(generator, call.arguments)).value();
|
||||||
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, current_value, current_value, current_base, arguments);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(current_value, current_value, current_base, arguments);
|
||||||
generator.emit_mov(current_base, generator.add_constant(js_undefined()));
|
generator.emit_mov(current_base, generator.add_constant(js_undefined()));
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,7 +27,9 @@
|
||||||
O(Call) \
|
O(Call) \
|
||||||
O(CallBuiltin) \
|
O(CallBuiltin) \
|
||||||
O(CallConstruct) \
|
O(CallConstruct) \
|
||||||
|
O(CallConstructWithArgumentArray) \
|
||||||
O(CallDirectEval) \
|
O(CallDirectEval) \
|
||||||
|
O(CallDirectEvalWithArgumentArray) \
|
||||||
O(CallWithArgumentArray) \
|
O(CallWithArgumentArray) \
|
||||||
O(Catch) \
|
O(Catch) \
|
||||||
O(ConcatString) \
|
O(ConcatString) \
|
||||||
|
|
|
@ -587,7 +587,9 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
||||||
HANDLE_INSTRUCTION(Call);
|
HANDLE_INSTRUCTION(Call);
|
||||||
HANDLE_INSTRUCTION(CallBuiltin);
|
HANDLE_INSTRUCTION(CallBuiltin);
|
||||||
HANDLE_INSTRUCTION(CallConstruct);
|
HANDLE_INSTRUCTION(CallConstruct);
|
||||||
|
HANDLE_INSTRUCTION(CallConstructWithArgumentArray);
|
||||||
HANDLE_INSTRUCTION(CallDirectEval);
|
HANDLE_INSTRUCTION(CallDirectEval);
|
||||||
|
HANDLE_INSTRUCTION(CallDirectEvalWithArgumentArray);
|
||||||
HANDLE_INSTRUCTION(CallWithArgumentArray);
|
HANDLE_INSTRUCTION(CallWithArgumentArray);
|
||||||
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(Catch);
|
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(Catch);
|
||||||
HANDLE_INSTRUCTION(ConcatString);
|
HANDLE_INSTRUCTION(ConcatString);
|
||||||
|
@ -2904,13 +2906,69 @@ ThrowCompletionOr<void> CallBuiltin::execute_impl(Bytecode::Interpreter& interpr
|
||||||
return execute_call<CallType::Call>(interpreter, callee, interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
return execute_call<CallType::Call>(interpreter, callee, interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<CallType call_type>
|
||||||
|
static ThrowCompletionOr<void> call_with_argument_array(
|
||||||
|
Bytecode::Interpreter& interpreter,
|
||||||
|
Value callee,
|
||||||
|
Value this_value,
|
||||||
|
Value arguments,
|
||||||
|
Operand dst,
|
||||||
|
Optional<StringTableIndex> const& expression_string)
|
||||||
|
{
|
||||||
|
TRY(throw_if_needed_for_call(interpreter, callee, call_type, expression_string));
|
||||||
|
|
||||||
|
auto& function = callee.as_function();
|
||||||
|
|
||||||
|
auto& argument_array = arguments.as_array();
|
||||||
|
auto argument_array_length = argument_array.indexed_properties().array_like_size();
|
||||||
|
|
||||||
|
ExecutionContext* callee_context = nullptr;
|
||||||
|
size_t argument_count = argument_array_length;
|
||||||
|
size_t registers_and_constants_and_locals_count = 0;
|
||||||
|
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(argument_array_length, 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 = argument_array_length;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < insn_argument_count; ++i) {
|
||||||
|
if (auto maybe_value = argument_array.indexed_properties().get(i); maybe_value.has_value())
|
||||||
|
callee_context_argument_values[i] = maybe_value.release_value().value;
|
||||||
|
else
|
||||||
|
callee_context_argument_values[i] = js_undefined();
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
Value retval;
|
||||||
|
if (call_type == CallType::DirectEval && callee == interpreter.realm().intrinsics().eval_function()) {
|
||||||
|
auto& vm = interpreter.vm();
|
||||||
|
retval = TRY(perform_eval(vm, !callee_context->arguments.is_empty() ? callee_context->arguments[0] : js_undefined(), 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> CallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
ThrowCompletionOr<void> CallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
auto callee = interpreter.get(m_callee);
|
return call_with_argument_array<CallType::Call>(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string());
|
||||||
TRY(throw_if_needed_for_call(interpreter, callee, call_type(), expression_string()));
|
}
|
||||||
auto argument_values = argument_list_evaluation(interpreter, interpreter.get(arguments()));
|
|
||||||
interpreter.set(dst(), TRY(perform_call(interpreter, interpreter.get(m_this_value), call_type(), callee, move(argument_values))));
|
ThrowCompletionOr<void> CallDirectEvalWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
return {};
|
{
|
||||||
|
return call_with_argument_array<CallType::DirectEval>(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> CallConstructWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
|
{
|
||||||
|
return call_with_argument_array<CallType::Construct>(interpreter, interpreter.get(callee()), js_undefined(), interpreter.get(arguments()), dst(), expression_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 13.3.7.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
|
// 13.3.7.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
|
||||||
|
@ -3645,19 +3703,6 @@ ByteString JumpUndefined::to_byte_string_impl(Bytecode::Executable const& execut
|
||||||
m_false_target);
|
m_false_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static StringView call_type_to_string(CallType type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case CallType::Call:
|
|
||||||
return ""sv;
|
|
||||||
case CallType::Construct:
|
|
||||||
return " (Construct)"sv;
|
|
||||||
case CallType::DirectEval:
|
|
||||||
return " (DirectEval)"sv;
|
|
||||||
}
|
|
||||||
VERIFY_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteString Call::to_byte_string_impl(Bytecode::Executable const& executable) const
|
ByteString Call::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
@ -3729,10 +3774,8 @@ ByteString CallBuiltin::to_byte_string_impl(Bytecode::Executable const& executab
|
||||||
|
|
||||||
ByteString CallWithArgumentArray::to_byte_string_impl(Bytecode::Executable const& executable) const
|
ByteString CallWithArgumentArray::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||||
{
|
{
|
||||||
auto type = call_type_to_string(m_type);
|
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
builder.appendff("CallWithArgumentArray{} {}, {}, {}, {}",
|
builder.appendff("CallWithArgumentArray {}, {}, {}, {}",
|
||||||
type,
|
|
||||||
format_operand("dst"sv, m_dst, executable),
|
format_operand("dst"sv, m_dst, executable),
|
||||||
format_operand("callee"sv, m_callee, executable),
|
format_operand("callee"sv, m_callee, executable),
|
||||||
format_operand("this"sv, m_this_value, executable),
|
format_operand("this"sv, m_this_value, executable),
|
||||||
|
@ -3743,6 +3786,33 @@ ByteString CallWithArgumentArray::to_byte_string_impl(Bytecode::Executable const
|
||||||
return builder.to_byte_string();
|
return builder.to_byte_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteString CallDirectEvalWithArgumentArray::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||||
|
{
|
||||||
|
StringBuilder builder;
|
||||||
|
builder.appendff("CallDirectEvalWithArgumentArray {}, {}, {}, {}",
|
||||||
|
format_operand("dst"sv, m_dst, executable),
|
||||||
|
format_operand("callee"sv, m_callee, executable),
|
||||||
|
format_operand("this"sv, m_this_value, executable),
|
||||||
|
format_operand("arguments"sv, m_arguments, executable));
|
||||||
|
|
||||||
|
if (m_expression_string.has_value())
|
||||||
|
builder.appendff(" ({})", executable.get_string(m_expression_string.value()));
|
||||||
|
return builder.to_byte_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteString CallConstructWithArgumentArray::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||||
|
{
|
||||||
|
StringBuilder builder;
|
||||||
|
builder.appendff("CallConstructWithArgumentArray {}, {}, {}",
|
||||||
|
format_operand("dst"sv, m_dst, executable),
|
||||||
|
format_operand("callee"sv, m_callee, executable),
|
||||||
|
format_operand("arguments"sv, m_arguments, executable));
|
||||||
|
|
||||||
|
if (m_expression_string.has_value())
|
||||||
|
builder.appendff(" ({})", executable.get_string(m_expression_string.value()));
|
||||||
|
return builder.to_byte_string();
|
||||||
|
}
|
||||||
|
|
||||||
ByteString SuperCallWithArgumentArray::to_byte_string_impl(Bytecode::Executable const& executable) const
|
ByteString SuperCallWithArgumentArray::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||||
{
|
{
|
||||||
return ByteString::formatted("SuperCallWithArgumentArray {}, {}",
|
return ByteString::formatted("SuperCallWithArgumentArray {}, {}",
|
||||||
|
|
|
@ -2005,28 +2005,25 @@ private:
|
||||||
Operand m_arguments[];
|
Operand m_arguments[];
|
||||||
};
|
};
|
||||||
|
|
||||||
class CallWithArgumentArray final : public Instruction {
|
template<CallType call_type>
|
||||||
|
class CallWithArgumentArrayBase : public Instruction {
|
||||||
public:
|
public:
|
||||||
CallWithArgumentArray(CallType type, Operand dst, Operand callee, Operand this_value, Operand arguments, Optional<StringTableIndex> expression_string = {})
|
CallWithArgumentArrayBase(Type type, Operand dst, Operand callee, Operand this_value, Operand arguments, Optional<StringTableIndex> expression_string = {})
|
||||||
: Instruction(Type::CallWithArgumentArray)
|
: Instruction(type)
|
||||||
, m_dst(dst)
|
, m_dst(dst)
|
||||||
, m_callee(callee)
|
, m_callee(callee)
|
||||||
, m_this_value(this_value)
|
, m_this_value(this_value)
|
||||||
, m_arguments(arguments)
|
, m_arguments(arguments)
|
||||||
, m_type(type)
|
|
||||||
, m_expression_string(expression_string)
|
, m_expression_string(expression_string)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand dst() const { return m_dst; }
|
Operand dst() const { return m_dst; }
|
||||||
CallType call_type() const { return m_type; }
|
|
||||||
Operand callee() const { return m_callee; }
|
Operand callee() const { return m_callee; }
|
||||||
Operand this_value() const { return m_this_value; }
|
Operand this_value() const { return m_this_value; }
|
||||||
Operand arguments() const { return m_arguments; }
|
Operand arguments() const { return m_arguments; }
|
||||||
Optional<StringTableIndex> const& expression_string() const { return m_expression_string; }
|
Optional<StringTableIndex> const& expression_string() const { return m_expression_string; }
|
||||||
|
|
||||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
|
||||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
|
||||||
void visit_operands_impl(Function<void(Operand&)> visitor)
|
void visit_operands_impl(Function<void(Operand&)> visitor)
|
||||||
{
|
{
|
||||||
visitor(m_dst);
|
visitor(m_dst);
|
||||||
|
@ -2035,15 +2032,47 @@ public:
|
||||||
visitor(m_arguments);
|
visitor(m_arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
Operand m_dst;
|
Operand m_dst;
|
||||||
Operand m_callee;
|
Operand m_callee;
|
||||||
Operand m_this_value;
|
Operand m_this_value;
|
||||||
Operand m_arguments;
|
Operand m_arguments;
|
||||||
CallType m_type;
|
|
||||||
Optional<StringTableIndex> m_expression_string;
|
Optional<StringTableIndex> m_expression_string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CallWithArgumentArray final : public CallWithArgumentArrayBase<CallType::Call> {
|
||||||
|
public:
|
||||||
|
CallWithArgumentArray(Operand dst, Operand callee, Operand this_value, Operand arguments, Optional<StringTableIndex> expression_string = {})
|
||||||
|
: CallWithArgumentArrayBase(Type::CallWithArgumentArray, dst, callee, this_value, arguments, expression_string)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||||
|
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CallDirectEvalWithArgumentArray final : public CallWithArgumentArrayBase<CallType::DirectEval> {
|
||||||
|
public:
|
||||||
|
CallDirectEvalWithArgumentArray(Operand dst, Operand callee, Operand this_value, Operand arguments, Optional<StringTableIndex> expression_string = {})
|
||||||
|
: CallWithArgumentArrayBase(Type::CallDirectEvalWithArgumentArray, dst, callee, this_value, arguments, expression_string)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||||
|
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CallConstructWithArgumentArray final : public CallWithArgumentArrayBase<CallType::Construct> {
|
||||||
|
public:
|
||||||
|
CallConstructWithArgumentArray(Operand dst, Operand callee, Operand this_value, Operand arguments, Optional<StringTableIndex> expression_string = {})
|
||||||
|
: CallWithArgumentArrayBase(Type::CallConstructWithArgumentArray, dst, callee, this_value, arguments, expression_string)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||||
|
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||||
|
};
|
||||||
|
|
||||||
class SuperCallWithArgumentArray : public Instruction {
|
class SuperCallWithArgumentArray : public Instruction {
|
||||||
public:
|
public:
|
||||||
explicit SuperCallWithArgumentArray(Operand dst, Operand arguments, bool is_synthetic)
|
explicit SuperCallWithArgumentArray(Operand dst, Operand arguments, bool is_synthetic)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue