1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 05:08:13 +00:00

LibJS/Bytecode: Add Call opcode for fixed-argument-count calls

This avoids the overhead of allocating a new Array on every function
call, saving a substantial amount of time and avoiding GC thrash.

This patch only makes use of Op::Call in CallExpression. There are other
places we should codegen this op. We should also do the same for super
expression calls.

~5% speed-up on Kraken/stanford-crypto-ccm.js
This commit is contained in:
Andreas Kling 2023-07-02 16:33:00 +02:00
parent 7eb87dec9f
commit c37b204ce1
5 changed files with 135 additions and 41 deletions

View file

@ -1463,8 +1463,6 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
generator.emit<Bytecode::Op::Store>(callee_reg);
}
TRY(arguments_to_array_for_call(generator, arguments()));
Bytecode::Op::CallType call_type;
if (is<NewExpression>(*this)) {
call_type = Bytecode::Op::CallType::Construct;
@ -1478,7 +1476,26 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
if (auto expression_string = this->expression_string(); expression_string.has_value())
expression_string_index = generator.intern_string(expression_string.release_value());
generator.emit<Bytecode::Op::CallWithArgumentArray>(call_type, callee_reg, this_reg, expression_string_index);
bool has_spread = any_of(arguments(), [](auto& argument) { return argument.is_spread; });
if (has_spread) {
TRY(arguments_to_array_for_call(generator, arguments()));
generator.emit<Bytecode::Op::CallWithArgumentArray>(call_type, callee_reg, this_reg, expression_string_index);
} else {
Optional<Bytecode::Register> first_argument_reg {};
for (size_t i = 0; i < arguments().size(); ++i) {
auto reg = generator.allocate_register();
if (!first_argument_reg.has_value())
first_argument_reg = reg;
}
u32 register_offset = 0;
for (auto const& argument : arguments()) {
TRY(argument.value->generate_bytecode(generator));
generator.emit<Bytecode::Op::Store>(Bytecode::Register { first_argument_reg.value().index() + register_offset });
register_offset += 1;
}
generator.emit<Bytecode::Op::Call>(call_type, callee_reg, this_reg, first_argument_reg.value_or(Bytecode::Register { 0 }), arguments().size(), expression_string_index);
}
return {};
}