mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 23:37:35 +00:00
LibJS: Make one compact allocation for CallExpression and its Arguments
Instead of CallExpression storing its arguments in a Vector<Argument>, we now custom-allocate the memory slot for CallExpression (and its subclass NewExpression) so that it fits both CallExpression and its list of Arguments in one allocation. This reduces memory usage on twitter.com/awesomekling by 8.8 MiB :^)
This commit is contained in:
parent
8a8d8ecb35
commit
b894acd6b2
4 changed files with 56 additions and 32 deletions
|
@ -372,7 +372,7 @@ ThrowCompletionOr<CallExpression::ThisAndCallee> CallExpression::compute_this_an
|
||||||
}
|
}
|
||||||
|
|
||||||
// 13.3.8.1 Runtime Semantics: ArgumentListEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-argumentlistevaluation
|
// 13.3.8.1 Runtime Semantics: ArgumentListEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-argumentlistevaluation
|
||||||
static ThrowCompletionOr<void> argument_list_evaluation(Interpreter& interpreter, Vector<CallExpression::Argument> const& arguments, MarkedVector<Value>& list)
|
static ThrowCompletionOr<void> argument_list_evaluation(Interpreter& interpreter, Span<CallExpression::Argument const> const arguments, MarkedVector<Value>& list)
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
auto& vm = interpreter.vm();
|
||||||
list.ensure_capacity(arguments.size());
|
list.ensure_capacity(arguments.size());
|
||||||
|
@ -406,7 +406,7 @@ Completion NewExpression::execute(Interpreter& interpreter) const
|
||||||
// 4. Else,
|
// 4. Else,
|
||||||
// a. Let argList be ? ArgumentListEvaluation of arguments.
|
// a. Let argList be ? ArgumentListEvaluation of arguments.
|
||||||
MarkedVector<Value> arg_list(vm.heap());
|
MarkedVector<Value> arg_list(vm.heap());
|
||||||
TRY(argument_list_evaluation(interpreter, m_arguments, arg_list));
|
TRY(argument_list_evaluation(interpreter, arguments(), arg_list));
|
||||||
|
|
||||||
// 5. If IsConstructor(constructor) is false, throw a TypeError exception.
|
// 5. If IsConstructor(constructor) is false, throw a TypeError exception.
|
||||||
if (!constructor.is_constructor())
|
if (!constructor.is_constructor())
|
||||||
|
@ -451,7 +451,7 @@ Completion CallExpression::execute(Interpreter& interpreter) const
|
||||||
VERIFY(!callee.is_empty());
|
VERIFY(!callee.is_empty());
|
||||||
|
|
||||||
MarkedVector<Value> arg_list(vm.heap());
|
MarkedVector<Value> arg_list(vm.heap());
|
||||||
TRY(argument_list_evaluation(interpreter, m_arguments, arg_list));
|
TRY(argument_list_evaluation(interpreter, arguments(), arg_list));
|
||||||
|
|
||||||
if (!callee.is_function())
|
if (!callee.is_function())
|
||||||
return throw_type_error_for_callee(interpreter, callee, "function"sv);
|
return throw_type_error_for_callee(interpreter, callee, "function"sv);
|
||||||
|
@ -2183,7 +2183,7 @@ void CallExpression::dump(int indent) const
|
||||||
else
|
else
|
||||||
outln("CallExpression");
|
outln("CallExpression");
|
||||||
m_callee->dump(indent + 1);
|
m_callee->dump(indent + 1);
|
||||||
for (auto& argument : m_arguments)
|
for (auto& argument : arguments())
|
||||||
argument.value->dump(indent + 1);
|
argument.value->dump(indent + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3216,7 +3216,7 @@ ThrowCompletionOr<OptionalChain::ReferenceAndValue> OptionalChain::to_reference_
|
||||||
|
|
||||||
auto expression = reference.visit(
|
auto expression = reference.visit(
|
||||||
[&](Call const& call) -> NonnullRefPtr<Expression> {
|
[&](Call const& call) -> NonnullRefPtr<Expression> {
|
||||||
return create_ast_node<CallExpression>(source_range(),
|
return CallExpression::create(source_range(),
|
||||||
create_ast_node<SyntheticReferenceExpression>(source_range(), base_reference, base),
|
create_ast_node<SyntheticReferenceExpression>(source_range(), base_reference, base),
|
||||||
call.arguments);
|
call.arguments);
|
||||||
},
|
},
|
||||||
|
@ -4823,4 +4823,14 @@ DeprecatedString const& SourceRange::filename() const
|
||||||
return code->filename();
|
return code->filename();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<CallExpression> CallExpression::create(SourceRange source_range, NonnullRefPtr<Expression> callee, Span<Argument const> arguments)
|
||||||
|
{
|
||||||
|
return ASTNodeWithTailArray::create<CallExpression>(arguments.size(), move(source_range), move(callee), arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<NewExpression> NewExpression::create(SourceRange source_range, NonnullRefPtr<Expression> callee, Span<Argument const> arguments)
|
||||||
|
{
|
||||||
|
return ASTNodeWithTailArray::create<NewExpression>(arguments.size(), move(source_range), move(callee), arguments);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1472,19 +1472,18 @@ public:
|
||||||
virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override;
|
virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CallExpression : public Expression {
|
struct CallExpressionArgument {
|
||||||
public:
|
NonnullRefPtr<Expression> value;
|
||||||
struct Argument {
|
bool is_spread;
|
||||||
NonnullRefPtr<Expression> value;
|
};
|
||||||
bool is_spread;
|
|
||||||
};
|
|
||||||
|
|
||||||
CallExpression(SourceRange source_range, NonnullRefPtr<Expression> callee, Vector<Argument> arguments = {})
|
class CallExpression : public ASTNodeWithTailArray<CallExpression, Expression, CallExpressionArgument> {
|
||||||
: Expression(source_range)
|
friend class ASTNodeWithTailArray;
|
||||||
, m_callee(move(callee))
|
|
||||||
, m_arguments(move(arguments))
|
public:
|
||||||
{
|
using Argument = CallExpressionArgument;
|
||||||
}
|
|
||||||
|
static NonnullRefPtr<CallExpression> create(SourceRange, NonnullRefPtr<Expression> callee, Span<Argument const> arguments);
|
||||||
|
|
||||||
virtual Completion execute(Interpreter&) const override;
|
virtual Completion execute(Interpreter&) const override;
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
|
@ -1492,6 +1491,22 @@ public:
|
||||||
|
|
||||||
Expression const& callee() const { return m_callee; }
|
Expression const& callee() const { return m_callee; }
|
||||||
|
|
||||||
|
Span<Argument const> arguments() const { return tail_span(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CallExpression(SourceRange source_range, NonnullRefPtr<Expression> callee, Span<Argument const> arguments)
|
||||||
|
: ASTNodeWithTailArray(move(source_range), arguments)
|
||||||
|
, m_callee(move(callee))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ThisAndCallee {
|
||||||
|
Value this_value;
|
||||||
|
Value callee;
|
||||||
|
};
|
||||||
|
ThrowCompletionOr<ThisAndCallee> compute_this_and_callee(Interpreter&, Reference const&) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool is_call_expression() const override { return true; }
|
virtual bool is_call_expression() const override { return true; }
|
||||||
|
|
||||||
|
@ -1499,28 +1514,27 @@ protected:
|
||||||
Optional<DeprecatedString> expression_string() const;
|
Optional<DeprecatedString> expression_string() const;
|
||||||
|
|
||||||
NonnullRefPtr<Expression> m_callee;
|
NonnullRefPtr<Expression> m_callee;
|
||||||
Vector<Argument> const m_arguments;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct ThisAndCallee {
|
|
||||||
Value this_value;
|
|
||||||
Value callee;
|
|
||||||
};
|
|
||||||
ThrowCompletionOr<ThisAndCallee> compute_this_and_callee(Interpreter&, Reference const&) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NewExpression final : public CallExpression {
|
class NewExpression final : public CallExpression {
|
||||||
|
friend class ASTNodeWithTailArray;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NewExpression(SourceRange source_range, NonnullRefPtr<Expression> callee, Vector<Argument> arguments = {})
|
static NonnullRefPtr<NewExpression> create(SourceRange, NonnullRefPtr<Expression> callee, Span<Argument const> arguments);
|
||||||
: CallExpression(source_range, move(callee), move(arguments))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Completion execute(Interpreter&) const override;
|
virtual Completion execute(Interpreter&) const override;
|
||||||
|
|
||||||
virtual bool is_new_expression() const override { return true; }
|
virtual bool is_new_expression() const override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
NewExpression(SourceRange source_range, NonnullRefPtr<Expression> callee, Span<Argument const> arguments)
|
||||||
|
: CallExpression(move(source_range), move(callee), arguments)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(NewExpression) == sizeof(CallExpression), "Adding members to NewExpression will break CallExpression memory layout");
|
||||||
|
|
||||||
class SuperCall final : public Expression {
|
class SuperCall final : public Expression {
|
||||||
public:
|
public:
|
||||||
// This is here to be able to make a constructor like
|
// This is here to be able to make a constructor like
|
||||||
|
|
|
@ -1551,7 +1551,7 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
|
||||||
generator.emit<Bytecode::Op::Store>(callee_reg);
|
generator.emit<Bytecode::Op::Store>(callee_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(arguments_to_array_for_call(generator, m_arguments));
|
TRY(arguments_to_array_for_call(generator, arguments()));
|
||||||
|
|
||||||
Bytecode::Op::Call::CallType call_type;
|
Bytecode::Op::Call::CallType call_type;
|
||||||
if (is<NewExpression>(*this)) {
|
if (is<NewExpression>(*this)) {
|
||||||
|
|
|
@ -2350,7 +2350,7 @@ NonnullRefPtr<Expression> Parser::parse_call_expression(NonnullRefPtr<Expression
|
||||||
if (is<SuperExpression>(*lhs))
|
if (is<SuperExpression>(*lhs))
|
||||||
return create_ast_node<SuperCall>({ m_source_code, rule_start.position(), position() }, move(arguments));
|
return create_ast_node<SuperCall>({ m_source_code, rule_start.position(), position() }, move(arguments));
|
||||||
|
|
||||||
return create_ast_node<CallExpression>({ m_source_code, rule_start.position(), position() }, move(lhs), move(arguments));
|
return CallExpression::create({ m_source_code, rule_start.position(), position() }, move(lhs), arguments.span());
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<NewExpression> Parser::parse_new_expression()
|
NonnullRefPtr<NewExpression> Parser::parse_new_expression()
|
||||||
|
@ -2380,7 +2380,7 @@ NonnullRefPtr<NewExpression> Parser::parse_new_expression()
|
||||||
consume(TokenType::ParenClose);
|
consume(TokenType::ParenClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
return create_ast_node<NewExpression>({ m_source_code, rule_start.position(), position() }, move(callee), move(arguments));
|
return NewExpression::create({ m_source_code, rule_start.position(), position() }, move(callee), move(arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<YieldExpression> Parser::parse_yield_expression()
|
NonnullRefPtr<YieldExpression> Parser::parse_yield_expression()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue