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 |