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 { ...@@ -21,6 +21,7 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
equivalence_id_(equivalence_id), equivalence_id_(equivalence_id),
materialized_(materialized), materialized_(materialized),
allocated_(allocated), allocated_(allocated),
needs_flush_(false),
next_(this), next_(this),
prev_(this) {} prev_(this) {}
...@@ -30,6 +31,11 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { ...@@ -30,6 +31,11 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
bool IsOnlyMaterializedMemberOfEquivalenceSet() const; bool IsOnlyMaterializedMemberOfEquivalenceSet() const;
bool IsInSameEquivalenceSet(RegisterInfo* info) 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 // Get a member of this register's equivalence set that is
// materialized. The materialized equivalent will be this register // materialized. The materialized equivalent will be this register
// if it is materialized. Returns nullptr if no materialized // if it is materialized. Returns nullptr if no materialized
...@@ -65,12 +71,16 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { ...@@ -65,12 +71,16 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
equivalence_id_ = equivalence_id; equivalence_id_ = equivalence_id;
} }
uint32_t equivalence_id() const { return 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: private:
Register register_; Register register_;
uint32_t equivalence_id_; uint32_t equivalence_id_;
bool materialized_; bool materialized_;
bool allocated_; bool allocated_;
bool needs_flush_;
// Equivalence set pointers. // Equivalence set pointers.
RegisterInfo* next_; RegisterInfo* next_;
...@@ -127,6 +137,19 @@ bool BytecodeRegisterOptimizer::RegisterInfo::IsInSameEquivalenceSet( ...@@ -127,6 +137,19 @@ bool BytecodeRegisterOptimizer::RegisterInfo::IsInSameEquivalenceSet(
return equivalence_id() == info->equivalence_id(); 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*
BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalent() { BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalent() {
RegisterInfo* visitor = this; RegisterInfo* visitor = this;
...@@ -199,6 +222,7 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( ...@@ -199,6 +222,7 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
temporary_base_(fixed_registers_count), temporary_base_(fixed_registers_count),
max_register_index_(fixed_registers_count - 1), max_register_index_(fixed_registers_count - 1),
register_info_table_(zone), register_info_table_(zone),
registers_needing_flushed_(zone),
equivalence_id_(0), equivalence_id_(0),
bytecode_writer_(bytecode_writer), bytecode_writer_(bytecode_writer),
flush_required_(false), flush_required_(false),
...@@ -226,29 +250,62 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( ...@@ -226,29 +250,62 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
DCHECK(accumulator_info_->register_value() == accumulator_); 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() { void BytecodeRegisterOptimizer::Flush() {
if (!flush_required_) { if (!flush_required_) {
return; return;
} }
// Materialize all live registers and break equivalences. // Materialize all live registers and break equivalences.
size_t count = register_info_table_.size(); for (RegisterInfo* reg_info : registers_needing_flushed_) {
for (size_t i = 0; i < count; ++i) { if (!reg_info->needs_flush()) continue;
RegisterInfo* reg_info = register_info_table_[i]; reg_info->set_needs_flush(false);
if (reg_info->materialized()) {
RegisterInfo* materialized = reg_info->materialized()
? reg_info
: reg_info->GetMaterializedEquivalent();
if (materialized != nullptr) {
// Walk equivalents of materialized registers, materializing // Walk equivalents of materialized registers, materializing
// each equivalent register as necessary and placing in their // each equivalent register as necessary and placing in their
// own equivalence set. // own equivalence set.
RegisterInfo* equivalent; RegisterInfo* equivalent;
while ((equivalent = reg_info->GetEquivalent()) != reg_info) { while ((equivalent = materialized->GetEquivalent()) != materialized) {
if (equivalent->allocated() && !equivalent->materialized()) { if (equivalent->allocated() && !equivalent->materialized()) {
OutputRegisterTransfer(reg_info, equivalent); OutputRegisterTransfer(materialized, equivalent);
} }
equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true); 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; flush_required_ = false;
} }
...@@ -311,6 +368,8 @@ void BytecodeRegisterOptimizer::Materialize(RegisterInfo* info) { ...@@ -311,6 +368,8 @@ void BytecodeRegisterOptimizer::Materialize(RegisterInfo* info) {
void BytecodeRegisterOptimizer::AddToEquivalenceSet( void BytecodeRegisterOptimizer::AddToEquivalenceSet(
RegisterInfo* set_member, RegisterInfo* non_set_member) { 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); non_set_member->AddToEquivalenceSetOf(set_member);
// Flushing is only required when two or more registers are placed // Flushing is only required when two or more registers are placed
// in the same equivalence set. // in the same equivalence set.
......
...@@ -131,6 +131,9 @@ class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final ...@@ -131,6 +131,9 @@ class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final
void AddToEquivalenceSet(RegisterInfo* set_member, void AddToEquivalenceSet(RegisterInfo* set_member,
RegisterInfo* non_set_member); RegisterInfo* non_set_member);
void PushToRegistersNeedingFlush(RegisterInfo* reg);
bool EnsureAllRegistersAreFlushed() const;
// Methods for finding and creating metadata for each register. // Methods for finding and creating metadata for each register.
RegisterInfo* GetRegisterInfo(Register reg) { RegisterInfo* GetRegisterInfo(Register reg) {
size_t index = GetRegisterInfoTableIndex(reg); size_t index = GetRegisterInfoTableIndex(reg);
...@@ -191,6 +194,8 @@ class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final ...@@ -191,6 +194,8 @@ class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final
ZoneVector<RegisterInfo*> register_info_table_; ZoneVector<RegisterInfo*> register_info_table_;
int register_info_table_offset_; int register_info_table_offset_;
ZoneDeque<RegisterInfo*> registers_needing_flushed_;
// Counter for equivalence sets identifiers. // Counter for equivalence sets identifiers.
int equivalence_id_; int equivalence_id_;
......
...@@ -115,7 +115,7 @@ bytecodes: [ ...@@ -115,7 +115,7 @@ bytecodes: [
/* 53 S> */ B(LdaSmi), I8(10), /* 53 S> */ B(LdaSmi), I8(10),
/* 53 E> */ B(StaCurrentContextSlot), U8(4), /* 53 E> */ B(StaCurrentContextSlot), U8(4),
B(Mov), R(0), R(1), B(Mov), R(0), R(1),
B(Ldar), R(0), B(Ldar), R(1),
/* 88 S> */ B(Jump), U8(2), /* 88 S> */ B(Jump), U8(2),
B(PopContext), R(2), B(PopContext), R(2),
B(LdaUndefined), B(LdaUndefined),
......
...@@ -110,7 +110,7 @@ bytecode array length: 45 ...@@ -110,7 +110,7 @@ bytecode array length: 45
bytecodes: [ bytecodes: [
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
B(Ldar), R(new_target), B(Ldar), R(0),
/* 113 E> */ B(StackCheck), /* 113 E> */ B(StackCheck),
/* 118 S> */ B(Ldar), R(1), /* 118 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(2), B(GetSuperConstructor), R(2),
...@@ -155,7 +155,7 @@ bytecode array length: 41 ...@@ -155,7 +155,7 @@ bytecode array length: 41
bytecodes: [ bytecodes: [
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
B(Ldar), R(new_target), B(Ldar), R(0),
/* 112 E> */ B(StackCheck), /* 112 E> */ B(StackCheck),
/* 117 S> */ B(Ldar), R(1), /* 117 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(2), B(GetSuperConstructor), R(2),
......
...@@ -40,8 +40,8 @@ bytecodes: [ ...@@ -40,8 +40,8 @@ bytecodes: [
B(Star), R(13), B(Star), R(13),
B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1), B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1),
B(Star), R(7), B(Star), R(7),
B(Mov), R(context), R(15),
B(Mov), R(2), R(11), B(Mov), R(2), R(11),
B(Mov), R(context), R(15),
B(Mov), R(context), R(16), B(Mov), R(context), R(16),
B(LdaZero), B(LdaZero),
B(Star), R(6), B(Star), R(6),
...@@ -371,8 +371,8 @@ bytecodes: [ ...@@ -371,8 +371,8 @@ bytecodes: [
B(Star), R(13), B(Star), R(13),
B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1), B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1),
B(Star), R(7), B(Star), R(7),
B(Mov), R(context), R(15),
B(Mov), R(2), R(11), B(Mov), R(2), R(11),
B(Mov), R(context), R(15),
B(Mov), R(context), R(16), B(Mov), R(context), R(16),
B(LdaZero), B(LdaZero),
B(Star), R(6), B(Star), R(6),
...@@ -444,7 +444,7 @@ bytecodes: [ ...@@ -444,7 +444,7 @@ bytecodes: [
B(Mov), R(3), R(0), B(Mov), R(3), R(0),
/* 56 S> */ B(LdaSmi), I8(1), /* 56 S> */ B(LdaSmi), I8(1),
B(Star), R(17), B(Star), R(17),
B(Mov), R(0), R(18), B(Mov), R(8), R(18),
B(Jump), U8(54), B(Jump), U8(54),
B(Jump), U8(40), B(Jump), U8(40),
B(Star), R(21), B(Star), R(21),
...@@ -719,8 +719,8 @@ bytecodes: [ ...@@ -719,8 +719,8 @@ bytecodes: [
B(Star), R(13), B(Star), R(13),
B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1), B(CallJSRuntime), U8(%async_function_promise_create), R(13), U8(1),
B(Star), R(7), B(Star), R(7),
B(Mov), R(context), R(15),
B(Mov), R(2), R(11), B(Mov), R(2), R(11),
B(Mov), R(context), R(15),
B(Mov), R(context), R(16), B(Mov), R(context), R(16),
B(LdaZero), B(LdaZero),
B(Star), R(6), B(Star), R(6),
......
...@@ -184,7 +184,7 @@ bytecodes: [ ...@@ -184,7 +184,7 @@ bytecodes: [
B(Mov), R(1), R(2), B(Mov), R(1), R(2),
/* 73 S> */ B(LdaZero), /* 73 S> */ B(LdaZero),
B(Star), R(9), B(Star), R(9),
B(Mov), R(1), R(10), B(Mov), R(6), R(10),
B(Jump), U8(50), B(Jump), U8(50),
B(Jump), U8(36), B(Jump), U8(36),
B(Star), R(13), B(Star), R(13),
......
...@@ -517,7 +517,7 @@ bytecodes: [ ...@@ -517,7 +517,7 @@ bytecodes: [
B(Mov), R(10), R(5), B(Mov), R(10), R(5),
/* 20 E> */ B(StackCheck), /* 20 E> */ B(StackCheck),
B(Mov), R(5), R(6), B(Mov), R(5), R(6),
B(Ldar), R(5), B(Ldar), R(6),
B(JumpIfUndefined), U8(6), B(JumpIfUndefined), U8(6),
B(Ldar), R(6), B(Ldar), R(6),
B(JumpIfNotNull), U8(16), B(JumpIfNotNull), U8(16),
...@@ -1290,8 +1290,8 @@ bytecodes: [ ...@@ -1290,8 +1290,8 @@ bytecodes: [
B(Star), R(14), B(Star), R(14),
B(CallJSRuntime), U8(%async_function_promise_create), R(14), U8(1), B(CallJSRuntime), U8(%async_function_promise_create), R(14), U8(1),
B(Star), R(3), B(Star), R(3),
B(Mov), R(context), R(16),
B(Mov), R(2), R(11), B(Mov), R(2), R(11),
B(Mov), R(context), R(16),
B(Mov), R(context), R(17), B(Mov), R(context), R(17),
B(LdaZero), B(LdaZero),
B(Star), R(7), B(Star), R(7),
......
...@@ -14,7 +14,7 @@ parameter count: 1 ...@@ -14,7 +14,7 @@ parameter count: 1
bytecode array length: 9 bytecode array length: 9
bytecodes: [ bytecodes: [
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
B(Ldar), R(new_target), B(Ldar), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(Ldar), R(0), /* 34 S> */ B(Ldar), R(0),
/* 53 S> */ B(Return), /* 53 S> */ B(Return),
...@@ -33,7 +33,7 @@ parameter count: 1 ...@@ -33,7 +33,7 @@ parameter count: 1
bytecode array length: 8 bytecode array length: 8
bytecodes: [ bytecodes: [
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
B(Ldar), R(new_target), B(Ldar), R(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaUndefined), /* 34 S> */ B(LdaUndefined),
/* 46 S> */ B(Return), /* 46 S> */ B(Return),
......
...@@ -342,7 +342,7 @@ bytecodes: [ ...@@ -342,7 +342,7 @@ bytecodes: [
B(LdaZero), B(LdaZero),
B(Star), R(6), B(Star), R(6),
B(Mov), R(0), R(4), B(Mov), R(0), R(4),
B(Ldar), R(0), B(Ldar), R(4),
B(JumpLoop), U8(19), I8(1), B(JumpLoop), U8(19), I8(1),
B(LdaSmi), I8(1), B(LdaSmi), I8(1),
/* 60 E> */ B(TestEqual), R(6), U8(7), /* 60 E> */ B(TestEqual), R(6), U8(7),
...@@ -476,7 +476,7 @@ bytecodes: [ ...@@ -476,7 +476,7 @@ bytecodes: [
B(LdaZero), B(LdaZero),
B(Star), R(5), B(Star), R(5),
B(Mov), R(0), R(3), B(Mov), R(0), R(3),
B(Ldar), R(0), B(Ldar), R(3),
B(JumpLoop), U8(90), I8(1), B(JumpLoop), U8(90), I8(1),
B(LdaSmi), I8(1), B(LdaSmi), I8(1),
/* 54 E> */ B(TestEqual), R(5), U8(7), /* 54 E> */ B(TestEqual), R(5), U8(7),
...@@ -551,7 +551,7 @@ bytecodes: [ ...@@ -551,7 +551,7 @@ bytecodes: [
B(LdaZero), B(LdaZero),
B(Star), R(6), B(Star), R(6),
B(Mov), R(0), R(4), B(Mov), R(0), R(4),
B(Ldar), R(0), B(Ldar), R(4),
B(JumpLoop), U8(19), I8(1), B(JumpLoop), U8(19), I8(1),
B(LdaSmi), I8(1), B(LdaSmi), I8(1),
/* 65 E> */ B(TestEqual), R(6), U8(7), /* 65 E> */ B(TestEqual), R(6), U8(7),
...@@ -659,8 +659,8 @@ bytecodes: [ ...@@ -659,8 +659,8 @@ bytecodes: [
B(Star), R(9), B(Star), R(9),
B(CallJSRuntime), U8(%async_function_promise_create), R(9), U8(1), B(CallJSRuntime), U8(%async_function_promise_create), R(9), U8(1),
B(Star), R(3), B(Star), R(3),
B(Mov), R(context), R(11),
B(Mov), R(2), R(7), B(Mov), R(2), R(7),
B(Mov), R(context), R(11),
B(Mov), R(context), R(12), B(Mov), R(context), R(12),
/* 36 S> */ B(LdaZero), /* 36 S> */ B(LdaZero),
B(Star), R(1), B(Star), R(1),
...@@ -732,7 +732,7 @@ bytecodes: [ ...@@ -732,7 +732,7 @@ bytecodes: [
B(LdaZero), B(LdaZero),
B(Star), R(6), B(Star), R(6),
B(Mov), R(0), R(4), B(Mov), R(0), R(4),
B(Ldar), R(0), B(Ldar), R(4),
B(JumpLoop), U8(98), I8(1), B(JumpLoop), U8(98), I8(1),
B(LdaSmi), I8(1), B(LdaSmi), I8(1),
/* 59 E> */ B(TestEqual), R(6), U8(7), /* 59 E> */ B(TestEqual), R(6), U8(7),
......
...@@ -25,7 +25,7 @@ bytecodes: [ ...@@ -25,7 +25,7 @@ bytecodes: [
B(Star), R(2), B(Star), R(2),
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
B(Ldar), R(new_target), B(Ldar), R(0),
/* 93 E> */ B(StackCheck), /* 93 E> */ B(StackCheck),
/* 93 S> */ B(Ldar), R(1), /* 93 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(3), B(GetSuperConstructor), R(3),
...@@ -59,7 +59,7 @@ bytecodes: [ ...@@ -59,7 +59,7 @@ bytecodes: [
B(Star), R(2), B(Star), R(2),
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
B(Ldar), R(new_target), B(Ldar), R(0),
/* 128 E> */ B(StackCheck), /* 128 E> */ B(StackCheck),
B(Mov), R(2), R(3), B(Mov), R(2), R(3),
/* 140 S> */ B(Ldar), R(1), /* 140 S> */ B(Ldar), R(1),
...@@ -103,7 +103,7 @@ bytecodes: [ ...@@ -103,7 +103,7 @@ bytecodes: [
B(Star), R(2), B(Star), R(2),
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
B(Ldar), R(new_target), B(Ldar), R(0),
/* 128 E> */ B(StackCheck), /* 128 E> */ B(StackCheck),
B(Mov), R(2), R(3), B(Mov), R(2), R(3),
/* 140 S> */ B(LdaUndefined), /* 140 S> */ B(LdaUndefined),
......
...@@ -703,16 +703,16 @@ snippet: " ...@@ -703,16 +703,16 @@ snippet: "
" "
frame size: 157 frame size: 157
parameter count: 1 parameter count: 1
bytecode array length: 37 bytecode array length: 39
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 1503 S> */ B(LdaZero), /* 1503 S> */ B(LdaZero),
B(Star), R(0), B(Star), R(0),
/* 1506 S> */ B(LdaSmi), I8(3), /* 1506 S> */ B(LdaSmi), I8(3),
/* 1515 E> */ B(Wide), B(TestEqual), R16(129), U16(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), /* 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), /* 1540 S> */ B(LdaSmi), I8(3),
/* 1547 E> */ B(TestGreaterThan), R(2), U8(4), /* 1547 E> */ B(TestGreaterThan), R(2), U8(4),
B(JumpIfFalse), U8(5), 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