OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 the V8 project authors. All rights reserved. | |
rmcilroy
2016/05/26 10:24:53
2016
oth
2016/05/26 21:26:51
Done.
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "src/interpreter/bytecode-register-optimizer.h" | |
6 | |
7 namespace v8 { | |
8 namespace internal { | |
9 namespace interpreter { | |
10 | |
11 // A class for tracking the state of a register. In particular, it | |
12 // tracks whether one register is valuewise equivalent to another, and | |
13 // also whether a register is materialized in the bytecode stream. | |
14 class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { | |
15 public: | |
16 RegisterInfo(Register reg, int equivalence_id, bool materialized) | |
17 : register_(reg), | |
18 equivalence_id_(equivalence_id), | |
19 materialized_(materialized), | |
20 next_(this), | |
21 prev_(this) {} | |
22 | |
23 void AddToEquivalenceSetOf(RegisterInfo* info); | |
24 void RemoveFromEquivalenceSet(); | |
25 bool IsOnlyEquivalent() const; | |
26 bool IsOnlyMaterializedEquivalent() const; | |
27 bool IsEquivalent(RegisterInfo* info) const; | |
28 | |
29 RegisterInfo* GetMaterializedEquivalent(); | |
30 RegisterInfo* GetMaterializedEquivalentOtherThan(Register reg); | |
31 RegisterInfo* GetMaterializationCandidate(); | |
rmcilroy
2016/05/26 10:24:52
I think these functions deserve a comment, particu
oth
2016/05/26 21:26:51
Done.
| |
32 | |
33 Register register_value() const { return register_; } | |
34 bool materialized() const { return materialized_; } | |
35 void set_materialized(bool materialized) { materialized_ = materialized; } | |
36 void set_equivalence_id(int equivalence_id) { | |
37 equivalence_id_ = equivalence_id; | |
38 } | |
39 int equivalence_id() const { return equivalence_id_; } | |
40 RegisterInfo* next() const { return next_; } | |
41 | |
42 private: | |
43 Register register_; | |
44 int equivalence_id_; | |
rmcilroy
2016/05/26 10:24:53
This should probably be an unsigned long, and mayb
oth
2016/05/26 21:26:50
Done.
| |
45 bool materialized_; | |
46 | |
47 // Equivalence set pointers. | |
48 RegisterInfo* next_; | |
49 RegisterInfo* prev_; | |
50 | |
51 DISALLOW_COPY_AND_ASSIGN(RegisterInfo); | |
52 }; | |
53 | |
54 void BytecodeRegisterOptimizer::RegisterInfo::AddToEquivalenceSetOf( | |
55 RegisterInfo* info) { | |
56 DCHECK(!IsEquivalent(info) && IsOnlyEquivalent()); | |
57 this->next_ = info->next_; | |
58 this->prev_ = info; | |
59 this->prev_->next_ = this; | |
60 this->next_->prev_ = this; | |
61 set_equivalence_id(info->equivalence_id()); | |
62 } | |
63 | |
64 void BytecodeRegisterOptimizer::RegisterInfo::RemoveFromEquivalenceSet() { | |
65 this->next_->prev_ = this->prev_; | |
66 this->prev_->next_ = this->next_; | |
67 this->next_ = this->prev_ = this; | |
68 } | |
69 | |
70 bool BytecodeRegisterOptimizer::RegisterInfo::IsOnlyEquivalent() const { | |
rmcilroy
2016/05/26 10:24:53
This name is a bit confusing to me, how about IsUn
oth
2016/05/26 21:26:51
Agreed. For readability, perhaps IsOnlyMemberOfEqu
rmcilroy
2016/05/27 09:18:58
SGTM, thanks.
| |
71 return this->next_ == this; | |
72 } | |
73 | |
74 bool BytecodeRegisterOptimizer::RegisterInfo::IsOnlyMaterializedEquivalent() | |
75 const { | |
76 DCHECK(materialized()); | |
77 | |
78 const RegisterInfo* visitor = this->next_; | |
79 while (visitor != this) { | |
80 if (visitor->materialized()) { | |
81 return false; | |
82 } | |
83 visitor = visitor->next_; | |
84 } | |
85 return true; | |
86 } | |
87 | |
88 bool BytecodeRegisterOptimizer::RegisterInfo::IsEquivalent( | |
89 RegisterInfo* info) const { | |
90 return equivalence_id() == info->equivalence_id(); | |
91 } | |
92 | |
93 BytecodeRegisterOptimizer::RegisterInfo* | |
94 BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalent() { | |
95 RegisterInfo* visitor = this; | |
96 do { | |
97 if (visitor->materialized()) { | |
98 return visitor; | |
99 } | |
100 visitor = visitor->next_; | |
101 } while (visitor != this); | |
102 | |
103 return nullptr; | |
104 } | |
105 | |
106 BytecodeRegisterOptimizer::RegisterInfo* | |
107 BytecodeRegisterOptimizer::RegisterInfo::GetMaterializationCandidate() { | |
rmcilroy
2016/05/26 10:24:53
It is difficult to figure out what this function d
oth
2016/05/26 21:26:50
GetEquivalentToMaterialize()?
rmcilroy
2016/05/27 09:18:58
SGTM, thanks.
| |
108 DCHECK(this->materialized()); | |
109 RegisterInfo* visitor = this->next_; | |
110 Register best_reg; | |
rmcilroy
2016/05/26 10:24:53
unused
oth
2016/05/26 21:26:51
Done.
| |
111 RegisterInfo* best_info = nullptr; | |
112 while (visitor != this) { | |
113 if (visitor->materialized()) { | |
114 return nullptr; | |
115 } | |
116 if (best_info == nullptr || | |
117 visitor->register_value() < best_info->register_value()) { | |
118 best_info = visitor; | |
119 } | |
120 visitor = visitor->next_; | |
121 } | |
122 return best_info; | |
123 } | |
124 | |
125 BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( | |
126 Zone* zone, TemporaryRegisterAllocator* register_allocator, | |
127 int parameter_count, int fixed_register_count, | |
128 BytecodePipelineStage* next_stage) | |
129 : accumulator_(Register::bytecode_array()), | |
rmcilroy
2016/05/26 10:24:52
We don't use bytecode_array in bytecode, but I won
oth
2016/05/26 21:26:51
Done.
It was implemented in this way to keep the
| |
130 temporary_base_(register_allocator->allocation_base()), | |
131 register_map_(zone), | |
132 equivalence_id_(0), | |
133 next_stage_(next_stage), | |
134 flushed_(false), | |
135 zone_(zone) { | |
136 register_allocator->set_observer(this); | |
137 | |
138 // Calculate offset so register index values can be mapped into | |
139 // a vector of register metadata. | |
140 if (parameter_count != 0) { | |
141 map_index_offset_ = | |
142 -Register::FromParameterIndex(0, parameter_count).index(); | |
143 } else { | |
144 map_index_offset_ = -accumulator_.index(); | |
rmcilroy
2016/05/26 10:24:53
Does this side ever get hit? We should always have
oth
2016/05/26 21:26:50
Yes, it gets hit in tests that craft bytecode.
Th
rmcilroy
2016/05/27 09:18:58
SG, thanks
| |
145 } | |
146 | |
147 // Initialize register map for parameters, locals, and the | |
148 // accumulator. | |
149 register_map_.resize(map_index_offset_ + | |
150 static_cast<size_t>(fixed_register_count)); | |
rmcilroy
2016/05/26 10:24:53
Isn't fixed_register_count the same (or less than)
oth
2016/05/26 21:26:50
Done.
| |
151 for (size_t i = 0; i < register_map_.size(); ++i) { | |
152 register_map_[i] = new (zone) | |
153 RegisterInfo(RegisterFromMapIndex(i), equivalence_id_++, true); | |
154 DCHECK_EQ(register_map_[i]->register_value().index(), | |
155 RegisterFromMapIndex(i).index()); | |
156 } | |
157 accumulator_info_ = GetRegisterInfo(accumulator_); | |
158 DCHECK(accumulator_info_->register_value() == accumulator_); | |
159 } | |
160 | |
161 void BytecodeRegisterOptimizer::FlushState() { | |
162 if (flushed_) { | |
163 return; | |
164 } | |
165 | |
166 // Materialize all live registers. | |
167 size_t count = register_map_.size(); | |
168 for (size_t i = 0; i < count; ++i) { | |
169 RegisterInfo* reg_info = register_map_[i]; | |
170 if (!reg_info->materialized() && !reg_info->IsOnlyEquivalent()) { | |
171 DCHECK(RegisterIsTemporary(reg_info->register_value()) || | |
172 reg_info->register_value() == accumulator_); | |
173 Materialize(reg_info); | |
174 } | |
175 } | |
176 | |
177 // Break all existing equivalences. | |
178 for (size_t i = 0; i < count; ++i) { | |
179 RegisterInfo* reg_info = register_map_[i]; | |
180 if (!reg_info->IsOnlyEquivalent()) { | |
181 reg_info->RemoveFromEquivalenceSet(); | |
182 reg_info->set_equivalence_id(equivalence_id_++); | |
rmcilroy
2016/05/26 10:24:53
nit - move the setting of equivalence_id into Remo
oth
2016/05/26 21:26:50
Done.
| |
183 } | |
184 } | |
185 flushed_ = true; | |
186 } | |
187 | |
188 // override | |
189 void BytecodeRegisterOptimizer::FlushBasicBlock() { | |
190 FlushState(); | |
191 next_stage_->FlushBasicBlock(); | |
192 } | |
193 | |
194 // override | |
195 size_t BytecodeRegisterOptimizer::FlushForOffset() { | |
196 FlushState(); | |
197 return next_stage_->FlushForOffset(); | |
198 } | |
199 | |
200 void BytecodeRegisterOptimizer::EmitNopTakingSourcePosition( | |
201 BytecodeNode* node) { | |
202 BytecodeNode nop(Bytecode::kNop); | |
203 nop.source_info().Update(node->source_info()); | |
204 WriteToNextStage(&nop); | |
205 node->source_info().set_invalid(); | |
206 } | |
207 | |
208 // override | |
209 void BytecodeRegisterOptimizer::Write(BytecodeNode* node) { | |
210 flushed_ = false; | |
211 | |
212 // | |
213 // The logic for register to register transfer here emits Nops with the | |
214 // current source position. | |
rmcilroy
2016/05/26 10:24:53
I'm not sure what this adds anything beyond the tw
oth
2016/05/26 21:26:50
Done.
| |
215 // | |
216 // Transfers with observable registers as the destination will be | |
217 // immediately materialized so the source position information will | |
218 // be ordered correctly. | |
219 // | |
220 // Transfers without observable destination registers will initially | |
221 // be emitted as Nop's with the source position. They may, or may | |
222 // not, be materialized by the optimizer. However, the source | |
223 // position is not lost and being attachd to a Nop is fine as the | |
rmcilroy
2016/05/26 10:24:53
attached
oth
2016/05/26 21:26:51
Done.
| |
224 // destination register is not observable in the debugger. | |
225 // | |
226 switch (node->bytecode()) { | |
227 case Bytecode::kLdar: { | |
228 EmitNopTakingSourcePosition(node); | |
rmcilroy
2016/05/26 10:24:53
nit - move into DoLdar / DoStar / DoMov.
Optional
oth
2016/05/26 21:26:50
Done. Tried the experiment with the source positio
| |
229 DoLdar(node); | |
230 return; | |
231 } | |
232 case Bytecode::kStar: { | |
233 EmitNopTakingSourcePosition(node); | |
234 DoStar(node); | |
235 return; | |
236 } | |
237 case Bytecode::kMov: { | |
238 EmitNopTakingSourcePosition(node); | |
239 DoMov(node); | |
240 return; | |
241 } | |
242 default: | |
243 break; | |
244 } | |
245 | |
246 if (Bytecodes::IsJump(node->bytecode()) || | |
247 node->bytecode() == Bytecode::kDebugger) { | |
248 // The debugger can manipulate locals and parameters, flush | |
249 // everything before handing over to it. Similarly, all state must | |
250 // be flushed before emitting a jump due to how bytecode offsets | |
251 // for jumps are evaluated. | |
252 FlushState(); | |
253 WriteToNextStage(node); | |
254 return; | |
rmcilroy
2016/05/26 10:24:53
nit - just do the FlushState here and fall-through
oth
2016/05/26 21:26:51
Done.
| |
255 } | |
256 | |
257 PrepareOperands(node); | |
258 WriteToNextStage(node); | |
259 } | |
260 | |
261 void BytecodeRegisterOptimizer::WriteToNextStage(BytecodeNode* node) { | |
262 next_stage_->Write(node); | |
263 } | |
264 | |
265 void BytecodeRegisterOptimizer::OutputRegisterTransfer( | |
266 RegisterInfo* input_info, RegisterInfo* output_info) { | |
267 Register input = input_info->register_value(); | |
268 Register output = output_info->register_value(); | |
269 DCHECK_NE(input.index(), output.index()); | |
270 | |
271 if (input == accumulator_) { | |
272 uint32_t operand = static_cast<uint32_t>(output.ToOperand()); | |
273 OperandScale scale = Bytecodes::OperandSizesToScale(output.SizeOfOperand()); | |
274 BytecodeNode node(Bytecode::kStar, operand, scale); | |
275 WriteToNextStage(&node); | |
276 } else if (output == accumulator_) { | |
277 uint32_t operand = static_cast<uint32_t>(input.ToOperand()); | |
278 OperandScale scale = Bytecodes::OperandSizesToScale(input.SizeOfOperand()); | |
279 BytecodeNode node(Bytecode::kLdar, operand, scale); | |
280 WriteToNextStage(&node); | |
281 } else { | |
282 uint32_t operand0 = static_cast<uint32_t>(input.ToOperand()); | |
283 uint32_t operand1 = static_cast<uint32_t>(output.ToOperand()); | |
284 OperandScale scale = Bytecodes::OperandSizesToScale(input.SizeOfOperand(), | |
285 output.SizeOfOperand()); | |
286 BytecodeNode node(Bytecode::kMov, operand0, operand1, scale); | |
287 WriteToNextStage(&node); | |
288 } | |
289 } | |
290 | |
291 void BytecodeRegisterOptimizer::CreateMaterializedEquivalentIfRequired( | |
292 RegisterInfo* info) { | |
293 if (info->materialized()) { | |
294 RegisterInfo* unmaterialized = info->GetMaterializationCandidate(); | |
295 if (unmaterialized) { | |
296 OutputRegisterTransfer(info, unmaterialized); | |
297 unmaterialized->set_materialized(true); | |
298 } | |
299 } | |
300 } | |
301 | |
302 BytecodeRegisterOptimizer::RegisterInfo* | |
303 BytecodeRegisterOptimizer::GetMaterializedEquivalent(RegisterInfo* info) { | |
304 return info->materialized() ? info : info->GetMaterializedEquivalent(); | |
305 } | |
306 | |
307 BytecodeRegisterOptimizer::RegisterInfo* | |
308 BytecodeRegisterOptimizer::GetMaterializedEquivalentNotAccumulator( | |
309 RegisterInfo* info) { | |
310 if (info->materialized()) { | |
311 return info; | |
312 } | |
313 | |
314 RegisterInfo* result = info->GetMaterializedEquivalent(); | |
rmcilroy
2016/05/26 10:24:53
Maybe just add an option to GetMaterializedEquival
oth
2016/05/26 21:26:51
Done.
| |
315 if (result->register_value() == accumulator_) { | |
316 result = result->next()->GetMaterializedEquivalent(); | |
317 if (result->register_value() == accumulator_) { | |
318 Materialize(info); | |
319 result = info; | |
320 } | |
321 } | |
322 return result; | |
323 } | |
324 | |
325 void BytecodeRegisterOptimizer::Materialize(RegisterInfo* info) { | |
326 if (!info->materialized()) { | |
327 RegisterInfo* materialized = info->GetMaterializedEquivalent(); | |
328 OutputRegisterTransfer(materialized, info); | |
329 info->set_materialized(true); | |
330 } | |
331 } | |
332 | |
333 void BytecodeRegisterOptimizer::RegisterTransfer(RegisterInfo* input_info, | |
334 RegisterInfo* output_info) { | |
335 // Ensure value associated with output is materialized into a | |
336 // different register if necessary. | |
337 CreateMaterializedEquivalentIfRequired(output_info); | |
338 bool output_is_observable = | |
339 RegisterIsObservable(output_info->register_value()); | |
340 | |
341 // If the output and input are not equivalent or the output is | |
342 // visible to the user/debugger, update equivalence set and | |
343 // potentially emit store if the transfer is observable. | |
344 if (!output_info->IsEquivalent(input_info) || output_is_observable) { | |
345 // Remove from current set and invalidate equivalence id. | |
346 output_info->RemoveFromEquivalenceSet(); | |
347 output_info->set_equivalence_id(equivalence_id_++); | |
348 | |
349 // Add to the equivalence set of |input_info|. | |
350 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent(); | |
351 output_info->AddToEquivalenceSetOf(materialized_info); | |
352 output_info->set_materialized(output_is_observable); | |
353 if (output_is_observable) { | |
354 OutputRegisterTransfer(materialized_info, output_info); | |
rmcilroy
2016/05/26 10:24:53
output_info should be set_materialized(true) shoul
oth
2016/05/26 21:26:51
Re-worked hopefully easier to reason about now ?
rmcilroy
2016/05/27 09:18:58
Looks good, thanks
| |
355 } | |
356 } | |
357 } | |
358 | |
359 void BytecodeRegisterOptimizer::DoLdar(const BytecodeNode* const node) { | |
360 Register input = GetRegisterInputOperand( | |
361 0, node->bytecode(), node->operands(), node->operand_count()); | |
362 RegisterInfo* input_info = GetRegisterInfo(input); | |
363 RegisterTransfer(input_info, accumulator_info_); | |
364 } | |
365 | |
366 void BytecodeRegisterOptimizer::DoMov(const BytecodeNode* const node) { | |
367 Register input = GetRegisterInputOperand( | |
368 0, node->bytecode(), node->operands(), node->operand_count()); | |
369 RegisterInfo* input_info = GetRegisterInfo(input); | |
370 Register output = GetRegisterOutputOperand( | |
371 1, node->bytecode(), node->operands(), node->operand_count()); | |
372 RegisterInfo* output_info = GetOrCreateRegisterInfo(output); | |
373 RegisterTransfer(input_info, output_info); | |
374 } | |
375 | |
376 void BytecodeRegisterOptimizer::DoStar(const BytecodeNode* const node) { | |
377 Register output = GetRegisterOutputOperand( | |
378 0, node->bytecode(), node->operands(), node->operand_count()); | |
379 RegisterInfo* output_info = GetOrCreateRegisterInfo(output); | |
380 RegisterTransfer(accumulator_info_, output_info); | |
381 } | |
382 | |
383 void BytecodeRegisterOptimizer::PrepareRegisterOutputOperand( | |
384 RegisterInfo* reg_info) { | |
385 CreateMaterializedEquivalentIfRequired(reg_info); | |
386 | |
387 // Put register in it's own equivalence set. | |
388 reg_info->RemoveFromEquivalenceSet(); | |
389 reg_info->set_materialized(true); | |
390 reg_info->set_equivalence_id(equivalence_id_++); | |
391 } | |
392 | |
393 void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand( | |
394 Register start, int count) { | |
395 for (int i = 0; i < count; ++i) { | |
396 Register reg(start.index() + i); | |
397 RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); | |
398 PrepareRegisterOutputOperand(reg_info); | |
399 } | |
400 } | |
401 | |
402 Register BytecodeRegisterOptimizer::PrepareRegisterInputOperand(Register reg) { | |
403 RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); | |
rmcilroy
2016/05/26 10:24:53
Reginfo should be create here shouldn't it? Just G
oth
2016/05/26 21:26:51
Comment added. The create case is for the first ti
| |
404 if (reg_info->materialized()) { | |
405 return reg; | |
406 } else { | |
407 RegisterInfo* equivalent_info = | |
408 GetMaterializedEquivalentNotAccumulator(reg_info); | |
409 return equivalent_info->register_value(); | |
410 } | |
411 } | |
412 | |
413 void BytecodeRegisterOptimizer::PrepareRegisterRangeInputOperand(Register start, | |
414 int count) { | |
415 for (int i = 0; i < count; ++i) { | |
416 Register current(start.index() + i); | |
417 RegisterInfo* input_info = GetRegisterInfo(current); | |
418 Materialize(input_info); | |
419 } | |
420 } | |
421 | |
422 void BytecodeRegisterOptimizer::PrepareRegisterOperands( | |
423 BytecodeNode* const node) { | |
424 // | |
425 // For each input operand, get a materialized equivalent if it is | |
426 // just a single register, otherwise materialize register range. | |
427 // Update operand_scale if necessary. | |
428 // | |
429 // For each output register about to be clobbered, materialize an | |
430 // equivalent if it exists. Put each register in it's own equivalence set. | |
431 // | |
432 int register_operand_bitmap = | |
433 Bytecodes::GetRegisterOperandBitmap(node->bytecode()); | |
434 const OperandType* operand_types = | |
435 Bytecodes::GetOperandTypes(node->bytecode()); | |
436 uint32_t* operands = node->operands(); | |
437 for (int i = 0; register_operand_bitmap != 0; | |
438 ++i, register_operand_bitmap >>= 1) { | |
439 if ((register_operand_bitmap & 1) == 0) { | |
440 continue; | |
441 } | |
442 OperandType operand_type = operand_types[i]; | |
443 int count = 0; | |
444 if (operand_types[i + 1] == OperandType::kRegCount) { | |
rmcilroy
2016/05/26 10:24:53
This is repeated in a bunch of places (e.g., bytec
oth
2016/05/26 21:26:51
This is a little bit raw. If it's a helper, it'll
| |
445 count = static_cast<int>(operands[i + 1]); | |
446 if (count == 0) { | |
447 continue; | |
448 } | |
449 } else { | |
450 count = Bytecodes::GetNumberOfRegistersRepresentedBy(operand_type); | |
451 } | |
452 | |
453 Register reg = Register::FromOperand(static_cast<int32_t>(operands[i])); | |
454 if (Bytecodes::IsRegisterInputOperandType(operand_type)) { | |
455 if (count == 1) { | |
456 Register equivalent = PrepareRegisterInputOperand(reg); | |
rmcilroy
2016/05/26 10:24:53
PrepareRegisterInputOperand does something differe
oth
2016/05/26 21:26:50
Done.
| |
457 operands[i] = static_cast<uint32_t>(equivalent.ToOperand()); | |
458 // Update operand scale as equivalent may be different. | |
459 OperandScale operand_scale = | |
460 Bytecodes::OperandSizesToScale(equivalent.SizeOfOperand()); | |
461 if (operand_scale > node->operand_scale()) { | |
462 node->set_operand_scale(operand_scale); | |
463 } | |
464 } else if (count > 1) { | |
465 PrepareRegisterRangeInputOperand(reg, count); | |
466 } | |
467 } else if (Bytecodes::IsRegisterOutputOperandType(operand_type)) { | |
468 PrepareRegisterRangeOutputOperand(reg, count); | |
469 } | |
470 } | |
471 } | |
472 | |
473 void BytecodeRegisterOptimizer::PrepareAccumulator(BytecodeNode* const node) { | |
474 // Materialize the accumulator if it is read by the bytecode. The | |
475 // accumulator is special and no other register can be materialized | |
476 // in it's place. | |
477 if (Bytecodes::ReadsAccumulator(node->bytecode()) && | |
478 !accumulator_info_->materialized()) { | |
479 Materialize(accumulator_info_); | |
480 } | |
481 | |
482 // Materialize an equivalent to the accumulator if it will be | |
483 // clobbered when the bytecode is dispatched. | |
484 if (Bytecodes::WritesAccumulator(node->bytecode())) { | |
485 PrepareRegisterOutputOperand(accumulator_info_); | |
486 } | |
487 } | |
488 | |
489 void BytecodeRegisterOptimizer::PrepareOperands(BytecodeNode* const node) { | |
490 PrepareAccumulator(node); | |
491 PrepareRegisterOperands(node); | |
492 } | |
493 | |
494 // static | |
495 Register BytecodeRegisterOptimizer::GetRegisterInputOperand( | |
496 int index, Bytecode bytecode, const uint32_t* operands, int operand_count) { | |
497 DCHECK_LT(index, operand_count); | |
498 DCHECK(Bytecodes::IsRegisterInputOperandType( | |
499 Bytecodes::GetOperandType(bytecode, index))); | |
500 return OperandToRegister(operands[index]); | |
501 } | |
502 | |
503 // static | |
504 Register BytecodeRegisterOptimizer::GetRegisterOutputOperand( | |
505 int index, Bytecode bytecode, const uint32_t* operands, int operand_count) { | |
506 DCHECK_LT(index, operand_count); | |
507 DCHECK(Bytecodes::IsRegisterOutputOperandType( | |
508 Bytecodes::GetOperandType(bytecode, index))); | |
509 return OperandToRegister(operands[index]); | |
510 } | |
511 | |
512 BytecodeRegisterOptimizer::RegisterInfo* | |
513 BytecodeRegisterOptimizer::GetRegisterInfo(Register reg) { | |
514 size_t index = GetMapIndex(reg); | |
515 return (index < register_map_.size()) ? register_map_[index] : nullptr; | |
rmcilroy
2016/05/26 10:24:53
it looks like we always depend on this returning n
oth
2016/05/26 21:26:50
This can be called from TemporaryRegisterFreeEvent
rmcilroy
2016/05/27 09:18:58
OK sounds good, thanks.
| |
516 } | |
517 | |
518 BytecodeRegisterOptimizer::RegisterInfo* | |
519 BytecodeRegisterOptimizer::GetOrCreateRegisterInfo(Register reg) { | |
520 size_t index = GetMapIndex(reg); | |
521 return index < register_map_.size() ? register_map_[index] | |
522 : NewRegisterInfo(reg); | |
523 } | |
524 | |
525 BytecodeRegisterOptimizer::RegisterInfo* | |
526 BytecodeRegisterOptimizer::NewRegisterInfo(Register reg) { | |
527 size_t index = GetMapIndex(reg); | |
528 DCHECK_GE(index, register_map_.size()); | |
529 GrowRegisterMap(reg); | |
530 return register_map_[index]; | |
531 } | |
532 | |
533 void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) { | |
534 DCHECK(RegisterIsTemporary(reg)); | |
535 size_t index = GetMapIndex(reg); | |
536 DCHECK_GE(index, register_map_.size()); | |
537 size_t new_size = index + 1; | |
538 size_t old_size = register_map_.size(); | |
539 register_map_.resize(new_size); | |
540 for (size_t i = old_size; i < new_size; ++i) { | |
541 register_map_[i] = new (zone()) | |
542 RegisterInfo(RegisterFromMapIndex(i), equivalence_id_++, false); | |
543 } | |
544 } | |
545 | |
546 void BytecodeRegisterOptimizer::TemporaryRegisterFreeEvent(Register reg) { | |
547 RegisterInfo* info = GetRegisterInfo(reg); | |
548 if (info != nullptr) { | |
549 // If register is materialized and part of equivalence set, make | |
550 // sure another member of the set holds the value before the | |
551 // temporary register is removed. | |
552 CreateMaterializedEquivalentIfRequired(info); | |
553 info->RemoveFromEquivalenceSet(); | |
554 info->set_materialized(false); | |
555 info->set_equivalence_id(-1); | |
556 } | |
557 } | |
558 | |
559 } // namespace interpreter | |
560 } // namespace internal | |
561 } // namespace v8 | |
OLD | NEW |