Commit 8edef78d authored by Alexandre Talon's avatar Alexandre Talon Committed by Commit Bot

[ignition] Fix register flushing performance issue

In some codes flushing the registers was costly: we processed each
register whereas all the registers alone in their equivalence class need
not to be processed. We now overapproximate easily which classes are of
size 2 so as to save many iterations in the Flush() loop in some cases.

Bug: v8:6432
Change-Id: I945e151736e8a515263ac76312127d930fd20d74
Reviewed-on: https://chromium-review.googlesource.com/525795
Commit-Queue: Alexandre Talon <alexandret@google.com>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45805}
parent 5c82f3bd
......@@ -21,6 +21,7 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
equivalence_id_(equivalence_id),
materialized_(materialized),
allocated_(allocated),
needs_flush_(false),
next_(this),
prev_(this) {}
......@@ -30,6 +31,11 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
bool IsOnlyMaterializedMemberOfEquivalenceSet() const;
bool IsInSameEquivalenceSet(RegisterInfo* info) const;
// Get a member of the register's equivalence set that is allocated.
// Returns itself if allocated, and nullptr if there is no unallocated
// equivalent register.
RegisterInfo* GetAllocatedEquivalent();
// Get a member of this register's equivalence set that is
// materialized. The materialized equivalent will be this register
// if it is materialized. Returns nullptr if no materialized
......@@ -65,12 +71,16 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
equivalence_id_ = equivalence_id;
}
uint32_t equivalence_id() const { return equivalence_id_; }
// Indicates if a register should be processed when calling Flush().
bool needs_flush() const { return needs_flush_; }
void set_needs_flush(bool needs_flush) { needs_flush_ = needs_flush; }
private:
Register register_;
uint32_t equivalence_id_;
bool materialized_;
bool allocated_;
bool needs_flush_;
// Equivalence set pointers.
RegisterInfo* next_;
......@@ -127,6 +137,19 @@ bool BytecodeRegisterOptimizer::RegisterInfo::IsInSameEquivalenceSet(
return equivalence_id() == info->equivalence_id();
}
BytecodeRegisterOptimizer::RegisterInfo*
BytecodeRegisterOptimizer::RegisterInfo::GetAllocatedEquivalent() {
RegisterInfo* visitor = this;
do {
if (visitor->allocated()) {
return visitor;
}
visitor = visitor->next_;
} while (visitor != this);
return nullptr;
}
BytecodeRegisterOptimizer::RegisterInfo*
BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalent() {
RegisterInfo* visitor = this;
......@@ -199,6 +222,7 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
temporary_base_(fixed_registers_count),
max_register_index_(fixed_registers_count - 1),
register_info_table_(zone),
registers_needing_flushed_(zone),
equivalence_id_(0),
bytecode_writer_(bytecode_writer),
flush_required_(false),
......@@ -226,29 +250,62 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
DCHECK(accumulator_info_->register_value() == accumulator_);
}
void BytecodeRegisterOptimizer::PushToRegistersNeedingFlush(RegisterInfo* reg) {
if (!reg->needs_flush()) {
reg->set_needs_flush(true);
registers_needing_flushed_.push_back(reg);
}
}
bool BytecodeRegisterOptimizer::EnsureAllRegistersAreFlushed() const {
for (RegisterInfo* reg_info : register_info_table_) {
if (reg_info->needs_flush()) {
return false;
} else if (!reg_info->IsOnlyMemberOfEquivalenceSet()) {
return false;
} else if (reg_info->allocated() && !reg_info->materialized()) {
return false;
}
}
return true;
}
void BytecodeRegisterOptimizer::Flush() {
if (!flush_required_) {
return;
}
// Materialize all live registers and break equivalences.
size_t count = register_info_table_.size();
for (size_t i = 0; i < count; ++i) {
RegisterInfo* reg_info = register_info_table_[i];
if (reg_info->materialized()) {
for (RegisterInfo* reg_info : registers_needing_flushed_) {
if (!reg_info->needs_flush()) continue;
reg_info->set_needs_flush(false);
RegisterInfo* materialized = reg_info->materialized()
? reg_info
: reg_info->GetMaterializedEquivalent();
if (materialized != nullptr) {
// Walk equivalents of materialized registers, materializing
// each equivalent register as necessary and placing in their
// own equivalence set.
RegisterInfo* equivalent;
while ((equivalent = reg_info->GetEquivalent()) != reg_info) {
while ((equivalent = materialized->GetEquivalent()) != materialized) {
if (equivalent->allocated() && !equivalent->materialized()) {
OutputRegisterTransfer(reg_info, equivalent);
OutputRegisterTransfer(materialized, equivalent);
}
equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
equivalent->set_needs_flush(false);
}
} else {
// Equivalernce class containing only unallocated registers.
DCHECK(reg_info->GetAllocatedEquivalent() == nullptr);
reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), false);
}
}
registers_needing_flushed_.clear();
DCHECK(EnsureAllRegistersAreFlushed());
flush_required_ = false;
}
......@@ -311,6 +368,8 @@ void BytecodeRegisterOptimizer::Materialize(RegisterInfo* info) {
void BytecodeRegisterOptimizer::AddToEquivalenceSet(
RegisterInfo* set_member, RegisterInfo* non_set_member) {
// Equivalence class is now of size >= 2, so we make sure it will be flushed.
PushToRegistersNeedingFlush(non_set_member);
non_set_member->AddToEquivalenceSetOf(set_member);
// Flushing is only required when two or more registers are placed
// in the same equivalence set.
......
......@@ -131,6 +131,9 @@ class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final
void AddToEquivalenceSet(RegisterInfo* set_member,
RegisterInfo* non_set_member);
void PushToRegistersNeedingFlush(RegisterInfo* reg);
bool EnsureAllRegistersAreFlushed() const;
// Methods for finding and creating metadata for each register.
RegisterInfo* GetRegisterInfo(Register reg) {
size_t index = GetRegisterInfoTableIndex(reg);
......@@ -191,6 +194,8 @@ class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final
ZoneVector<RegisterInfo*> register_info_table_;
int register_info_table_offset_;
ZoneDeque<RegisterInfo*> registers_needing_flushed_;
// Counter for equivalence sets identifiers.
int equivalence_id_;
......
......@@ -115,7 +115,7 @@ bytecodes: [
/* 53 S> */ B(LdaSmi), I8(10),
/* 53 E> */ B(StaCurrentContextSlot), U8(4),
B(Mov), R(0), R(1),
B(Ldar), R(0),
B(Ldar), R(1),
/* 88 S> */ B(Jump), U8(2),
B(PopContext), R(2),
B(LdaUndefined),
......
......@@ -110,7 +110,7 @@ bytecode array length: 45
bytecodes: [
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(new_target),
B(Ldar), R(0),
/* 113 E> */ B(StackCheck),
/* 118 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(2),
......@@ -155,7 +155,7 @@ bytecode array length: 41
bytecodes: [
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(new_target),
B(Ldar), R(0),
/* 112 E> */ B(StackCheck),
/* 117 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(2),
......
......@@ -40,8 +40,8 @@ bytecodes: [
B(Star), R(13),
B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1),
B(Star), R(7),
B(Mov), R(context), R(15),
B(Mov), R(2), R(11),
B(Mov), R(context), R(15),
B(Mov), R(context), R(16),
B(LdaZero),
B(Star), R(6),
......@@ -371,8 +371,8 @@ bytecodes: [
B(Star), R(13),
B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1),
B(Star), R(7),
B(Mov), R(context), R(15),
B(Mov), R(2), R(11),
B(Mov), R(context), R(15),
B(Mov), R(context), R(16),
B(LdaZero),
B(Star), R(6),
......@@ -444,7 +444,7 @@ bytecodes: [
B(Mov), R(3), R(0),
/* 56 S> */ B(LdaSmi), I8(1),
B(Star), R(17),
B(Mov), R(0), R(18),
B(Mov), R(8), R(18),
B(Jump), U8(54),
B(Jump), U8(40),
B(Star), R(21),
......@@ -719,8 +719,8 @@ bytecodes: [
B(Star), R(13),
B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1),
B(Star), R(7),
B(Mov), R(context), R(15),
B(Mov), R(2), R(11),
B(Mov), R(context), R(15),
B(Mov), R(context), R(16),
B(LdaZero),
B(Star), R(6),
......
......@@ -184,7 +184,7 @@ bytecodes: [
B(Mov), R(1), R(2),
/* 73 S> */ B(LdaZero),
B(Star), R(9),
B(Mov), R(1), R(10),
B(Mov), R(6), R(10),
B(Jump), U8(50),
B(Jump), U8(36),
B(Star), R(13),
......
......@@ -517,7 +517,7 @@ bytecodes: [
B(Mov), R(10), R(5),
/* 20 E> */ B(StackCheck),
B(Mov), R(5), R(6),
B(Ldar), R(5),
B(Ldar), R(6),
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
......@@ -1290,8 +1290,8 @@ bytecodes: [
B(Star), R(14),
B(CallJSRuntime), U8(%async_function_promise_create), R(14), U8(1),
B(Star), R(3),
B(Mov), R(context), R(16),
B(Mov), R(2), R(11),
B(Mov), R(context), R(16),
B(Mov), R(context), R(17),
B(LdaZero),
B(Star), R(7),
......
......@@ -14,7 +14,7 @@ parameter count: 1
bytecode array length: 9
bytecodes: [
B(Mov), R(new_target), R(0),
B(Ldar), R(new_target),
B(Ldar), R(0),
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(Ldar), R(0),
/* 53 S> */ B(Return),
......@@ -33,7 +33,7 @@ parameter count: 1
bytecode array length: 8
bytecodes: [
B(Mov), R(new_target), R(0),
B(Ldar), R(new_target),
B(Ldar), R(0),
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaUndefined),
/* 46 S> */ B(Return),
......
......@@ -342,7 +342,7 @@ bytecodes: [
B(LdaZero),
B(Star), R(6),
B(Mov), R(0), R(4),
B(Ldar), R(0),
B(Ldar), R(4),
B(JumpLoop), U8(19), I8(1),
B(LdaSmi), I8(1),
/* 60 E> */ B(TestEqual), R(6), U8(7),
......@@ -476,7 +476,7 @@ bytecodes: [
B(LdaZero),
B(Star), R(5),
B(Mov), R(0), R(3),
B(Ldar), R(0),
B(Ldar), R(3),
B(JumpLoop), U8(90), I8(1),
B(LdaSmi), I8(1),
/* 54 E> */ B(TestEqual), R(5), U8(7),
......@@ -551,7 +551,7 @@ bytecodes: [
B(LdaZero),
B(Star), R(6),
B(Mov), R(0), R(4),
B(Ldar), R(0),
B(Ldar), R(4),
B(JumpLoop), U8(19), I8(1),
B(LdaSmi), I8(1),
/* 65 E> */ B(TestEqual), R(6), U8(7),
......@@ -659,8 +659,8 @@ bytecodes: [
B(Star), R(9),
B(CallJSRuntime), U8(%async_function_promise_create), R(9), U8(1),
B(Star), R(3),
B(Mov), R(context), R(11),
B(Mov), R(2), R(7),
B(Mov), R(context), R(11),
B(Mov), R(context), R(12),
/* 36 S> */ B(LdaZero),
B(Star), R(1),
......@@ -732,7 +732,7 @@ bytecodes: [
B(LdaZero),
B(Star), R(6),
B(Mov), R(0), R(4),
B(Ldar), R(0),
B(Ldar), R(4),
B(JumpLoop), U8(98), I8(1),
B(LdaSmi), I8(1),
/* 59 E> */ B(TestEqual), R(6), U8(7),
......
......@@ -25,7 +25,7 @@ bytecodes: [
B(Star), R(2),
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(new_target),
B(Ldar), R(0),
/* 93 E> */ B(StackCheck),
/* 93 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(3),
......@@ -59,7 +59,7 @@ bytecodes: [
B(Star), R(2),
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(new_target),
B(Ldar), R(0),
/* 128 E> */ B(StackCheck),
B(Mov), R(2), R(3),
/* 140 S> */ B(Ldar), R(1),
......@@ -103,7 +103,7 @@ bytecodes: [
B(Star), R(2),
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(new_target),
B(Ldar), R(0),
/* 128 E> */ B(StackCheck),
B(Mov), R(2), R(3),
/* 140 S> */ B(LdaUndefined),
......
......@@ -703,16 +703,16 @@ snippet: "
"
frame size: 157
parameter count: 1
bytecode array length: 37
bytecode array length: 39
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 1503 S> */ B(LdaZero),
B(Star), R(0),
/* 1506 S> */ B(LdaSmi), I8(3),
/* 1515 E> */ B(Wide), B(TestEqual), R16(129), U16(3),
B(JumpIfFalse), U8(10),
B(JumpIfFalse), U8(12),
/* 1534 S> */ B(Wide), B(Mov), R16(0), R16(129),
B(Ldar), R(0),
B(Wide), B(Ldar), R16(129),
/* 1540 S> */ B(LdaSmi), I8(3),
/* 1547 E> */ B(TestGreaterThan), R(2), U8(4),
B(JumpIfFalse), U8(5),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment