Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/interpreter/bytecode-register-optimizer.h" | 5 #include "src/interpreter/bytecode-register-optimizer.h" |
| 6 | 6 |
| 7 namespace v8 { | 7 namespace v8 { |
| 8 namespace internal { | 8 namespace internal { |
| 9 namespace interpreter { | 9 namespace interpreter { |
| 10 | 10 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 41 RegisterInfo* GetMaterializedEquivalentOtherThan(Register reg); | 41 RegisterInfo* GetMaterializedEquivalentOtherThan(Register reg); |
| 42 | 42 |
| 43 // Get a member of this register's equivalence set that is intended | 43 // Get a member of this register's equivalence set that is intended |
| 44 // to be materialized in place of this register (which is currently | 44 // to be materialized in place of this register (which is currently |
| 45 // materialized). The best candidate is deemed to be the register | 45 // materialized). The best candidate is deemed to be the register |
| 46 // with the lowest index as this permits temporary registers to be | 46 // with the lowest index as this permits temporary registers to be |
| 47 // removed from the bytecode stream. Returns nullptr if no candidate | 47 // removed from the bytecode stream. Returns nullptr if no candidate |
| 48 // exists. | 48 // exists. |
| 49 RegisterInfo* GetEquivalentToMaterialize(); | 49 RegisterInfo* GetEquivalentToMaterialize(); |
| 50 | 50 |
| 51 // Get an equivalent register. Returns this if none exists. | |
| 52 RegisterInfo* GetEquivalent(); | |
| 53 | |
| 51 Register register_value() const { return register_; } | 54 Register register_value() const { return register_; } |
| 52 bool materialized() const { return materialized_; } | 55 bool materialized() const { return materialized_; } |
| 53 void set_materialized(bool materialized) { materialized_ = materialized; } | 56 void set_materialized(bool materialized) { materialized_ = materialized; } |
| 54 void set_equivalence_id(uint32_t equivalence_id) { | 57 void set_equivalence_id(uint32_t equivalence_id) { |
| 55 equivalence_id_ = equivalence_id; | 58 equivalence_id_ = equivalence_id; |
| 56 } | 59 } |
| 57 uint32_t equivalence_id() const { return equivalence_id_; } | 60 uint32_t equivalence_id() const { return equivalence_id_; } |
| 58 | 61 |
| 59 private: | 62 private: |
| 60 Register register_; | 63 Register register_; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 } | 157 } |
| 155 if (best_info == nullptr || | 158 if (best_info == nullptr || |
| 156 visitor->register_value() < best_info->register_value()) { | 159 visitor->register_value() < best_info->register_value()) { |
| 157 best_info = visitor; | 160 best_info = visitor; |
| 158 } | 161 } |
| 159 visitor = visitor->next_; | 162 visitor = visitor->next_; |
| 160 } | 163 } |
| 161 return best_info; | 164 return best_info; |
| 162 } | 165 } |
| 163 | 166 |
| 167 BytecodeRegisterOptimizer::RegisterInfo* | |
| 168 BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() { | |
| 169 return next_; | |
| 170 } | |
| 171 | |
| 164 BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( | 172 BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( |
| 165 Zone* zone, TemporaryRegisterAllocator* register_allocator, | 173 Zone* zone, TemporaryRegisterAllocator* register_allocator, |
| 166 int parameter_count, BytecodePipelineStage* next_stage) | 174 int parameter_count, BytecodePipelineStage* next_stage) |
| 167 : accumulator_(Register::virtual_accumulator()), | 175 : accumulator_(Register::virtual_accumulator()), |
| 168 temporary_base_(register_allocator->allocation_base()), | 176 temporary_base_(register_allocator->allocation_base()), |
| 169 register_info_table_(zone), | 177 register_info_table_(zone), |
| 170 equivalence_id_(0), | 178 equivalence_id_(0), |
| 171 next_stage_(next_stage), | 179 next_stage_(next_stage), |
| 172 flushed_(false), | 180 flush_required_(false), |
| 173 zone_(zone) { | 181 zone_(zone) { |
| 174 register_allocator->set_observer(this); | 182 register_allocator->set_observer(this); |
| 175 | 183 |
| 176 // Calculate offset so register index values can be mapped into | 184 // Calculate offset so register index values can be mapped into |
| 177 // a vector of register metadata. | 185 // a vector of register metadata. |
| 178 if (parameter_count != 0) { | 186 if (parameter_count != 0) { |
| 179 register_info_table_offset_ = | 187 register_info_table_offset_ = |
| 180 -Register::FromParameterIndex(0, parameter_count).index(); | 188 -Register::FromParameterIndex(0, parameter_count).index(); |
| 181 } else { | 189 } else { |
| 182 // TODO(oth): This path shouldn't be necessary in bytecode generated | 190 // TODO(oth): This path shouldn't be necessary in bytecode generated |
| 183 // from Javascript, but a set of tests do not include the JS receiver. | 191 // from Javascript, but a set of tests do not include the JS receiver. |
| 184 register_info_table_offset_ = -accumulator_.index(); | 192 register_info_table_offset_ = -accumulator_.index(); |
| 185 } | 193 } |
| 186 | 194 |
| 187 // Initialize register map for parameters, locals, and the | 195 // Initialize register map for parameters, locals, and the |
| 188 // accumulator. | 196 // accumulator. |
| 189 register_info_table_.resize(register_info_table_offset_ + | 197 register_info_table_.resize(register_info_table_offset_ + |
| 190 static_cast<size_t>(temporary_base_.index())); | 198 static_cast<size_t>(temporary_base_.index())); |
| 191 for (size_t i = 0; i < register_info_table_.size(); ++i) { | 199 for (size_t i = 0; i < register_info_table_.size(); ++i) { |
| 192 register_info_table_[i] = new (zone) RegisterInfo( | 200 register_info_table_[i] = new (zone) RegisterInfo( |
| 193 RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true); | 201 RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true); |
| 194 DCHECK_EQ(register_info_table_[i]->register_value().index(), | 202 DCHECK_EQ(register_info_table_[i]->register_value().index(), |
| 195 RegisterFromRegisterInfoTableIndex(i).index()); | 203 RegisterFromRegisterInfoTableIndex(i).index()); |
| 196 } | 204 } |
| 197 accumulator_info_ = GetRegisterInfo(accumulator_); | 205 accumulator_info_ = GetRegisterInfo(accumulator_); |
| 198 DCHECK(accumulator_info_->register_value() == accumulator_); | 206 DCHECK(accumulator_info_->register_value() == accumulator_); |
| 199 } | 207 } |
| 200 | 208 |
| 201 void BytecodeRegisterOptimizer::FlushState() { | 209 void BytecodeRegisterOptimizer::FlushState() { |
| 202 if (flushed_) { | 210 if (!flush_required_) { |
| 203 return; | 211 return; |
| 204 } | 212 } |
| 205 | 213 |
| 206 // Materialize all live registers. | 214 // Materialize all live registers and break equivalences. |
| 207 size_t count = register_info_table_.size(); | 215 size_t count = register_info_table_.size(); |
| 208 for (size_t i = 0; i < count; ++i) { | 216 for (size_t i = 0; i < count; ++i) { |
| 209 RegisterInfo* reg_info = register_info_table_[i]; | 217 RegisterInfo* reg_info = register_info_table_[i]; |
| 210 if (!reg_info->IsOnlyMemberOfEquivalenceSet() && | 218 if (reg_info->IsOnlyMemberOfEquivalenceSet() || !reg_info->materialized()) { |
| 211 !reg_info->materialized()) { | 219 continue; |
|
rmcilroy
2016/06/02 12:51:33
nit - could you add a comment here that you are sk
oth
2016/06/02 14:14:24
Done.
| |
| 212 DCHECK(RegisterIsTemporary(reg_info->register_value()) || | 220 } |
| 213 reg_info->register_value() == accumulator_); | 221 |
| 214 Materialize(reg_info); | 222 // Walk equivalents of this materialized register, materializing |
| 223 // each equivalent if necessary and moving to own equivalent set. | |
| 224 RegisterInfo* equivalent; | |
| 225 while ((equivalent = reg_info->GetEquivalent()) != reg_info) { | |
| 226 if (!equivalent->materialized()) { | |
| 227 OutputRegisterTransfer(reg_info, equivalent); | |
| 228 } | |
| 229 equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true); | |
| 215 } | 230 } |
| 216 } | 231 } |
| 217 | 232 |
| 218 // Break all existing equivalences. | 233 flush_required_ = false; |
| 219 for (size_t i = 0; i < count; ++i) { | |
| 220 RegisterInfo* reg_info = register_info_table_[i]; | |
| 221 if (!reg_info->IsOnlyMemberOfEquivalenceSet()) { | |
| 222 reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true); | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 flushed_ = true; | |
| 227 } | 234 } |
| 228 | 235 |
| 229 // override | 236 // override |
| 230 void BytecodeRegisterOptimizer::FlushBasicBlock() { | 237 void BytecodeRegisterOptimizer::FlushBasicBlock() { |
| 231 FlushState(); | 238 FlushState(); |
| 232 next_stage_->FlushBasicBlock(); | 239 next_stage_->FlushBasicBlock(); |
| 233 } | 240 } |
| 234 | 241 |
| 235 // override | 242 // override |
| 236 size_t BytecodeRegisterOptimizer::FlushForOffset() { | 243 size_t BytecodeRegisterOptimizer::FlushForOffset() { |
| 237 FlushState(); | 244 FlushState(); |
| 238 return next_stage_->FlushForOffset(); | 245 return next_stage_->FlushForOffset(); |
| 239 } | 246 } |
| 240 | 247 |
| 241 // override | 248 // override |
| 242 void BytecodeRegisterOptimizer::Write(BytecodeNode* node) { | 249 void BytecodeRegisterOptimizer::Write(BytecodeNode* node) { |
| 243 flushed_ = false; | |
| 244 | |
| 245 // | 250 // |
| 246 // Transfers with observable registers as the destination will be | 251 // Transfers with observable registers as the destination will be |
| 247 // immediately materialized so the source position information will | 252 // immediately materialized so the source position information will |
| 248 // be ordered correctly. | 253 // be ordered correctly. |
| 249 // | 254 // |
| 250 // Transfers without observable destination registers will initially | 255 // Transfers without observable destination registers will initially |
| 251 // be emitted as Nop's with the source position. They may, or may | 256 // be emitted as Nop's with the source position. They may, or may |
| 252 // not, be materialized by the optimizer. However, the source | 257 // not, be materialized by the optimizer. However, the source |
| 253 // position is not lost and being attached to a Nop is fine as the | 258 // position is not lost and being attached to a Nop is fine as the |
| 254 // destination register is not observable in the debugger. | 259 // destination register is not observable in the debugger. |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 const BytecodeSourceInfo& source_info) { | 368 const BytecodeSourceInfo& source_info) { |
| 364 // Materialize an alternate in the equivalence set that | 369 // Materialize an alternate in the equivalence set that |
| 365 // |output_info| is leaving. | 370 // |output_info| is leaving. |
| 366 if (output_info->materialized()) { | 371 if (output_info->materialized()) { |
| 367 CreateMaterializedEquivalent(output_info); | 372 CreateMaterializedEquivalent(output_info); |
| 368 } | 373 } |
| 369 | 374 |
| 370 // Add |output_info| to new equivalence set. | 375 // Add |output_info| to new equivalence set. |
| 371 if (!output_info->IsInSameEquivalenceSet(input_info)) { | 376 if (!output_info->IsInSameEquivalenceSet(input_info)) { |
| 372 output_info->AddToEquivalenceSetOf(input_info); | 377 output_info->AddToEquivalenceSetOf(input_info); |
| 378 flush_required_ = true; | |
|
rmcilroy
2016/06/02 12:51:34
This scares me a bit since if we add another call
oth
2016/06/02 14:14:24
Done.
If flushes aren't correctly emitted many te
rmcilroy
2016/06/02 15:07:13
Acknowledged, I'm fine with this if you are.
| |
| 373 } | 379 } |
| 374 | 380 |
| 375 bool output_is_observable = | 381 bool output_is_observable = |
| 376 RegisterIsObservable(output_info->register_value()); | 382 RegisterIsObservable(output_info->register_value()); |
| 377 if (output_is_observable) { | 383 if (output_is_observable) { |
| 378 // Force store to be emitted when register is observable. | 384 // Force store to be emitted when register is observable. |
| 379 output_info->set_materialized(false); | 385 output_info->set_materialized(false); |
| 380 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent(); | 386 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent(); |
| 381 OutputRegisterTransfer(materialized_info, output_info, source_info); | 387 OutputRegisterTransfer(materialized_info, output_info, source_info); |
| 382 } else if (source_info.is_valid()) { | 388 } else if (source_info.is_valid()) { |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 597 if (info->materialized()) { | 603 if (info->materialized()) { |
| 598 CreateMaterializedEquivalent(info); | 604 CreateMaterializedEquivalent(info); |
| 599 } | 605 } |
| 600 info->MoveToNewEquivalenceSet(kInvalidEquivalenceId, false); | 606 info->MoveToNewEquivalenceSet(kInvalidEquivalenceId, false); |
| 601 } | 607 } |
| 602 } | 608 } |
| 603 | 609 |
| 604 } // namespace interpreter | 610 } // namespace interpreter |
| 605 } // namespace internal | 611 } // namespace internal |
| 606 } // namespace v8 | 612 } // namespace v8 |
| OLD | NEW |