mirror of
https://github.com/RGBCube/serenity
synced 2025-05-22 19:25:07 +00:00
LibJS/Bytecode: Rename Call and SuperCall to &WithArgumentArray
Forcing every function call to allocate a new Array just to accommodate spread parameters is not very nice, so let's start moving towards making this a special case rather than the general (and only) case.
This commit is contained in:
parent
dc884aa0d3
commit
7eb87dec9f
5 changed files with 38 additions and 40 deletions
|
@ -344,7 +344,7 @@ Bytecode::CodeGenerationErrorOr<void> SuperCall::generate_bytecode(Bytecode::Gen
|
||||||
TRY(arguments_to_array_for_call(generator, m_arguments));
|
TRY(arguments_to_array_for_call(generator, m_arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.emit<Bytecode::Op::SuperCall>(m_is_synthetic == IsPartOfSyntheticConstructor::Yes);
|
generator.emit<Bytecode::Op::SuperCallWithArgumentArray>(m_is_synthetic == IsPartOfSyntheticConstructor::Yes);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1465,20 +1465,20 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
|
||||||
|
|
||||||
TRY(arguments_to_array_for_call(generator, arguments()));
|
TRY(arguments_to_array_for_call(generator, arguments()));
|
||||||
|
|
||||||
Bytecode::Op::Call::CallType call_type;
|
Bytecode::Op::CallType call_type;
|
||||||
if (is<NewExpression>(*this)) {
|
if (is<NewExpression>(*this)) {
|
||||||
call_type = Bytecode::Op::Call::CallType::Construct;
|
call_type = Bytecode::Op::CallType::Construct;
|
||||||
} else if (m_callee->is_identifier() && static_cast<Identifier const&>(*m_callee).string() == "eval"sv) {
|
} else if (m_callee->is_identifier() && static_cast<Identifier const&>(*m_callee).string() == "eval"sv) {
|
||||||
call_type = Bytecode::Op::Call::CallType::DirectEval;
|
call_type = Bytecode::Op::CallType::DirectEval;
|
||||||
} else {
|
} else {
|
||||||
call_type = Bytecode::Op::Call::CallType::Call;
|
call_type = Bytecode::Op::CallType::Call;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Bytecode::StringTableIndex> expression_string_index;
|
Optional<Bytecode::StringTableIndex> expression_string_index;
|
||||||
if (auto expression_string = this->expression_string(); expression_string.has_value())
|
if (auto expression_string = this->expression_string(); expression_string.has_value())
|
||||||
expression_string_index = generator.intern_string(expression_string.release_value());
|
expression_string_index = generator.intern_string(expression_string.release_value());
|
||||||
|
|
||||||
generator.emit<Bytecode::Op::Call>(call_type, callee_reg, this_reg, expression_string_index);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(call_type, callee_reg, this_reg, expression_string_index);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1582,7 +1582,7 @@ Bytecode::CodeGenerationErrorOr<void> YieldExpression::generate_bytecode(Bytecod
|
||||||
|
|
||||||
// i. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »).
|
// i. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »).
|
||||||
generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2, AK::Array { received_completion_value_register, received_completion_value_register });
|
generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2, AK::Array { received_completion_value_register, received_completion_value_register });
|
||||||
generator.emit<Bytecode::Op::Call>(Bytecode::Op::Call::CallType::Call, next_method_register, iterator_register);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, next_method_register, iterator_register);
|
||||||
|
|
||||||
// FIXME: ii. If generatorKind is async, set innerResult to ? Await(innerResult).
|
// FIXME: ii. If generatorKind is async, set innerResult to ? Await(innerResult).
|
||||||
|
|
||||||
|
@ -1654,7 +1654,7 @@ Bytecode::CodeGenerationErrorOr<void> YieldExpression::generate_bytecode(Bytecod
|
||||||
|
|
||||||
// 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
|
// 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
|
||||||
generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2, AK::Array { received_completion_value_register, received_completion_value_register });
|
generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2, AK::Array { received_completion_value_register, received_completion_value_register });
|
||||||
generator.emit<Bytecode::Op::Call>(Bytecode::Op::Call::CallType::Call, throw_method_register, iterator_register);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, throw_method_register, iterator_register);
|
||||||
|
|
||||||
// FIXME: 2. If generatorKind is async, set innerResult to ? Await(innerResult).
|
// FIXME: 2. If generatorKind is async, set innerResult to ? Await(innerResult).
|
||||||
|
|
||||||
|
@ -1742,7 +1742,7 @@ Bytecode::CodeGenerationErrorOr<void> YieldExpression::generate_bytecode(Bytecod
|
||||||
|
|
||||||
// iv. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »).
|
// iv. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »).
|
||||||
generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2, AK::Array { received_completion_value_register, received_completion_value_register });
|
generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2, AK::Array { received_completion_value_register, received_completion_value_register });
|
||||||
generator.emit<Bytecode::Op::Call>(Bytecode::Op::Call::CallType::Call, return_method_register, iterator_register);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, return_method_register, iterator_register);
|
||||||
|
|
||||||
// FIXME: v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
|
// FIXME: v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
|
||||||
|
|
||||||
|
@ -2047,7 +2047,7 @@ Bytecode::CodeGenerationErrorOr<void> TaggedTemplateLiteral::generate_bytecode(B
|
||||||
else
|
else
|
||||||
generator.emit<Bytecode::Op::NewArray>();
|
generator.emit<Bytecode::Op::NewArray>();
|
||||||
|
|
||||||
generator.emit<Bytecode::Op::Call>(Bytecode::Op::Call::CallType::Call, tag_reg, this_reg);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, tag_reg, this_reg);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2815,7 +2815,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> {
|
||||||
TRY(arguments_to_array_for_call(generator, call.arguments));
|
TRY(arguments_to_array_for_call(generator, call.arguments));
|
||||||
generator.emit<Bytecode::Op::Call>(Bytecode::Op::Call::CallType::Call, current_value_register, current_base_register);
|
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, current_value_register, current_base_register);
|
||||||
|
|
||||||
generator.emit<Bytecode::Op::Store>(current_value_register);
|
generator.emit<Bytecode::Op::Store>(current_value_register);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
O(BitwiseOr) \
|
O(BitwiseOr) \
|
||||||
O(BitwiseXor) \
|
O(BitwiseXor) \
|
||||||
O(BlockDeclarationInstantiation) \
|
O(BlockDeclarationInstantiation) \
|
||||||
O(Call) \
|
O(CallWithArgumentArray) \
|
||||||
O(ConcatString) \
|
O(ConcatString) \
|
||||||
O(ContinuePendingUnwind) \
|
O(ContinuePendingUnwind) \
|
||||||
O(CopyObjectExcludingProperties) \
|
O(CopyObjectExcludingProperties) \
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
O(StrictlyEquals) \
|
O(StrictlyEquals) \
|
||||||
O(StrictlyInequals) \
|
O(StrictlyInequals) \
|
||||||
O(Sub) \
|
O(Sub) \
|
||||||
O(SuperCall) \
|
O(SuperCallWithArgumentArray) \
|
||||||
O(Throw) \
|
O(Throw) \
|
||||||
O(ThrowIfNotObject) \
|
O(ThrowIfNotObject) \
|
||||||
O(ThrowIfNullish) \
|
O(ThrowIfNullish) \
|
||||||
|
|
|
@ -694,7 +694,7 @@ static MarkedVector<Value> argument_list_evaluation(Bytecode::Interpreter& inter
|
||||||
return argument_values;
|
return argument_values;
|
||||||
}
|
}
|
||||||
|
|
||||||
Completion Call::throw_type_error_for_callee(Bytecode::Interpreter& interpreter, StringView callee_type) const
|
Completion CallWithArgumentArray::throw_type_error_for_callee(Bytecode::Interpreter& interpreter, StringView callee_type) const
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
auto& vm = interpreter.vm();
|
||||||
auto callee = interpreter.reg(m_callee);
|
auto callee = interpreter.reg(m_callee);
|
||||||
|
@ -705,7 +705,7 @@ Completion Call::throw_type_error_for_callee(Bytecode::Interpreter& interpreter,
|
||||||
return vm.throw_completion<TypeError>(ErrorType::IsNotA, TRY_OR_THROW_OOM(vm, callee.to_string_without_side_effects()), callee_type);
|
return vm.throw_completion<TypeError>(ErrorType::IsNotA, TRY_OR_THROW_OOM(vm, callee.to_string_without_side_effects()), callee_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowCompletionOr<void> Call::execute_impl(Bytecode::Interpreter& interpreter) const
|
ThrowCompletionOr<void> CallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
auto& vm = interpreter.vm();
|
||||||
|
|
||||||
|
@ -738,7 +738,7 @@ ThrowCompletionOr<void> Call::execute_impl(Bytecode::Interpreter& interpreter) c
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
ThrowCompletionOr<void> SuperCall::execute_impl(Bytecode::Interpreter& interpreter) const
|
ThrowCompletionOr<void> SuperCallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
auto& vm = interpreter.vm();
|
||||||
// 1. Let newTarget be GetNewTarget().
|
// 1. Let newTarget be GetNewTarget().
|
||||||
|
@ -896,7 +896,7 @@ void CopyObjectExcludingProperties::replace_references_impl(Register from, Regis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Call::replace_references_impl(Register from, Register to)
|
void CallWithArgumentArray::replace_references_impl(Register from, Register to)
|
||||||
{
|
{
|
||||||
if (m_callee == from)
|
if (m_callee == from)
|
||||||
m_callee = to;
|
m_callee = to;
|
||||||
|
@ -1383,30 +1383,30 @@ DeprecatedString JumpUndefined::to_deprecated_string_impl(Bytecode::Executable c
|
||||||
return DeprecatedString::formatted("JumpUndefined undefined:{} not undefined:{}", true_string, false_string);
|
return DeprecatedString::formatted("JumpUndefined undefined:{} not undefined:{}", true_string, false_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString Call::to_deprecated_string_impl(Bytecode::Executable const& executable) const
|
DeprecatedString CallWithArgumentArray::to_deprecated_string_impl(Bytecode::Executable const& executable) const
|
||||||
{
|
{
|
||||||
StringView type;
|
StringView type;
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case Call::CallType::Call:
|
case CallType::Call:
|
||||||
type = ""sv;
|
type = ""sv;
|
||||||
break;
|
break;
|
||||||
case Call::CallType::Construct:
|
case CallType::Construct:
|
||||||
type = " (Construct)"sv;
|
type = " (Construct)"sv;
|
||||||
break;
|
break;
|
||||||
case Call::CallType::DirectEval:
|
case CallType::DirectEval:
|
||||||
type = " (DirectEval)"sv;
|
type = " (DirectEval)"sv;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_expression_string.has_value())
|
if (m_expression_string.has_value())
|
||||||
return DeprecatedString::formatted("Call{} callee:{}, this:{}, arguments:[...acc] ({})", type, m_callee, m_this_value, executable.get_string(m_expression_string.value()));
|
return DeprecatedString::formatted("CallWithArgumentArray{} callee:{}, this:{}, arguments:[...acc] ({})", type, m_callee, m_this_value, executable.get_string(m_expression_string.value()));
|
||||||
|
|
||||||
return DeprecatedString::formatted("Call{} callee:{}, this:{}, arguments:[...acc]", type, m_callee, m_this_value);
|
return DeprecatedString::formatted("CallWithArgumentArray{} callee:{}, this:{}, arguments:[...acc]", type, m_callee, m_this_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString SuperCall::to_deprecated_string_impl(Bytecode::Executable const&) const
|
DeprecatedString SuperCallWithArgumentArray::to_deprecated_string_impl(Bytecode::Executable const&) const
|
||||||
{
|
{
|
||||||
return "SuperCall arguments:[...acc]"sv;
|
return "SuperCallWithArgumentArray arguments:[...acc]"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString NewFunction::to_deprecated_string_impl(Bytecode::Executable const&) const
|
DeprecatedString NewFunction::to_deprecated_string_impl(Bytecode::Executable const&) const
|
||||||
|
|
|
@ -770,17 +770,16 @@ public:
|
||||||
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
|
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: This instruction is variable-width depending on the number of arguments!
|
enum class CallType {
|
||||||
class Call final : public Instruction {
|
Call,
|
||||||
public:
|
Construct,
|
||||||
enum class CallType {
|
DirectEval,
|
||||||
Call,
|
};
|
||||||
Construct,
|
|
||||||
DirectEval,
|
|
||||||
};
|
|
||||||
|
|
||||||
Call(CallType type, Register callee, Register this_value, Optional<StringTableIndex> expression_string = {})
|
class CallWithArgumentArray final : public Instruction {
|
||||||
: Instruction(Type::Call)
|
public:
|
||||||
|
CallWithArgumentArray(CallType type, Register callee, Register this_value, Optional<StringTableIndex> expression_string = {})
|
||||||
|
: Instruction(Type::CallWithArgumentArray)
|
||||||
, m_callee(callee)
|
, m_callee(callee)
|
||||||
, m_this_value(this_value)
|
, m_this_value(this_value)
|
||||||
, m_type(type)
|
, m_type(type)
|
||||||
|
@ -802,11 +801,10 @@ private:
|
||||||
Optional<StringTableIndex> m_expression_string;
|
Optional<StringTableIndex> m_expression_string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: This instruction is variable-width depending on the number of arguments!
|
class SuperCallWithArgumentArray : public Instruction {
|
||||||
class SuperCall : public Instruction {
|
|
||||||
public:
|
public:
|
||||||
explicit SuperCall(bool is_synthetic)
|
explicit SuperCallWithArgumentArray(bool is_synthetic)
|
||||||
: Instruction(Type::SuperCall)
|
: Instruction(Type::SuperCallWithArgumentArray)
|
||||||
, m_is_synthetic(is_synthetic)
|
, m_is_synthetic(is_synthetic)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ static NonnullOwnPtr<BasicBlock> eliminate_loads(BasicBlock const& block, size_t
|
||||||
// Attribute accesses (`a.o` or `a[o]`) may result in calls to getters or setters
|
// Attribute accesses (`a.o` or `a[o]`) may result in calls to getters or setters
|
||||||
// or may trigger proxies
|
// or may trigger proxies
|
||||||
// So these are treated like calls
|
// So these are treated like calls
|
||||||
case Call:
|
case CallWithArgumentArray:
|
||||||
// Calls, especially to local functions and eval, may poison visible and
|
// Calls, especially to local functions and eval, may poison visible and
|
||||||
// cached variables, hence we need to clear the lookup cache after emitting them
|
// cached variables, hence we need to clear the lookup cache after emitting them
|
||||||
// FIXME: In strict mode and with better identifier metrics, we might be able
|
// FIXME: In strict mode and with better identifier metrics, we might be able
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue