LibJS: Join locals, constants and registers into single vector

Merging registers, constants and locals into single vector means:
- Better data locality
- No need to check type in Interpreter::get() and Interpreter::set()
  which are very hot functions

Performance improvement is visible in almost all Octane and Kraken
tests.
This commit is contained in:
Aliaksandr Kalenik 2024-05-12 18:49:03 +02:00 committed by Andreas Kling
commit d79438a2a6
Notes: sideshowbarker 2024-07-17 05:19:06 +09:00
11 changed files with 478 additions and 57 deletions

View file

@ -266,6 +266,19 @@ CodeGenerationErrorOr<NonnullGCPtr<Executable>> Generator::emit_function_body_by
HashMap<size_t, SourceRecord> source_map;
for (auto& block : generator.m_root_basic_blocks) {
if (!block->is_terminated()) {
// NOTE: We must ensure that the "undefined" constant, which will be used by the not yet
// emitted End instruction, is taken into account while shifting local operands by the
// number of constants.
(void)generator.add_constant(js_undefined());
break;
}
}
auto number_of_registers = generator.m_next_register;
auto number_of_constants = generator.m_constants.size();
for (auto& block : generator.m_root_basic_blocks) {
basic_block_start_offsets.append(bytecode.size());
if (block->handler() || block->finalizer()) {
@ -287,6 +300,21 @@ CodeGenerationErrorOr<NonnullGCPtr<Executable>> Generator::emit_function_body_by
while (!it.at_end()) {
auto& instruction = const_cast<Instruction&>(*it);
instruction.visit_operands([number_of_registers, number_of_constants](Operand& operand) {
switch (operand.type()) {
case Operand::Type::Register:
break;
case Operand::Type::Local:
operand.offset_index_by(number_of_registers + number_of_constants);
break;
case Operand::Type::Constant:
operand.offset_index_by(number_of_registers);
break;
default:
VERIFY_NOT_REACHED();
}
});
// OPTIMIZATION: Don't emit jumps that just jump to the next block.
if (instruction.type() == Instruction::Type::Jump) {
auto& jump = static_cast<Bytecode::Op::Jump&>(instruction);
@ -333,6 +361,20 @@ CodeGenerationErrorOr<NonnullGCPtr<Executable>> Generator::emit_function_body_by
}
if (!block->is_terminated()) {
Op::End end(generator.add_constant(js_undefined()));
end.visit_operands([number_of_registers, number_of_constants](Operand& operand) {
switch (operand.type()) {
case Operand::Type::Register:
break;
case Operand::Type::Local:
operand.offset_index_by(number_of_registers + number_of_constants);
break;
case Operand::Type::Constant:
operand.offset_index_by(number_of_registers);
break;
default:
VERIFY_NOT_REACHED();
}
});
bytecode.append(reinterpret_cast<u8 const*>(&end), end.length());
}
if (block->handler() || block->finalizer()) {