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 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 BytecodeRegisterOptimizer::RegisterInfo* | 167 BytecodeRegisterOptimizer::RegisterInfo* |
168 BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() { | 168 BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() { |
169 return next_; | 169 return next_; |
170 } | 170 } |
171 | 171 |
172 BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( | 172 BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( |
173 Zone* zone, TemporaryRegisterAllocator* register_allocator, | 173 Zone* zone, TemporaryRegisterAllocator* register_allocator, |
174 int parameter_count, BytecodePipelineStage* next_stage) | 174 int parameter_count, BytecodePipelineStage* next_stage) |
175 : accumulator_(Register::virtual_accumulator()), | 175 : accumulator_(Register::virtual_accumulator()), |
176 temporary_base_(register_allocator->allocation_base()), | 176 temporary_base_(register_allocator->allocation_base()), |
| 177 max_register_index_(register_allocator->allocation_base() - 1), |
177 register_info_table_(zone), | 178 register_info_table_(zone), |
178 equivalence_id_(0), | 179 equivalence_id_(0), |
179 next_stage_(next_stage), | 180 next_stage_(next_stage), |
180 flush_required_(false), | 181 flush_required_(false), |
181 zone_(zone) { | 182 zone_(zone) { |
182 register_allocator->set_observer(this); | 183 register_allocator->set_observer(this); |
183 | 184 |
184 // Calculate offset so register index values can be mapped into | 185 // Calculate offset so register index values can be mapped into |
185 // a vector of register metadata. | 186 // a vector of register metadata. |
186 if (parameter_count != 0) { | 187 if (parameter_count != 0) { |
(...skipping 14 matching lines...) Expand all Loading... |
201 RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true); | 202 RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true); |
202 DCHECK_EQ(register_info_table_[i]->register_value().index(), | 203 DCHECK_EQ(register_info_table_[i]->register_value().index(), |
203 RegisterFromRegisterInfoTableIndex(i).index()); | 204 RegisterFromRegisterInfoTableIndex(i).index()); |
204 } | 205 } |
205 accumulator_info_ = GetRegisterInfo(accumulator_); | 206 accumulator_info_ = GetRegisterInfo(accumulator_); |
206 DCHECK(accumulator_info_->register_value() == accumulator_); | 207 DCHECK(accumulator_info_->register_value() == accumulator_); |
207 } | 208 } |
208 | 209 |
209 // override | 210 // override |
210 Handle<BytecodeArray> BytecodeRegisterOptimizer::ToBytecodeArray( | 211 Handle<BytecodeArray> BytecodeRegisterOptimizer::ToBytecodeArray( |
211 Isolate* isolate, int fixed_register_count, int parameter_count, | 212 Isolate* isolate, int register_count, int parameter_count, |
212 Handle<FixedArray> handler_table) { | 213 Handle<FixedArray> handler_table) { |
213 FlushState(); | 214 FlushState(); |
214 return next_stage_->ToBytecodeArray(isolate, fixed_register_count, | 215 return next_stage_->ToBytecodeArray(isolate, max_register_index_ + 1, |
215 parameter_count, handler_table); | 216 parameter_count, handler_table); |
216 } | 217 } |
217 | 218 |
218 // override | 219 // override |
219 void BytecodeRegisterOptimizer::Write(BytecodeNode* node) { | 220 void BytecodeRegisterOptimizer::Write(BytecodeNode* node) { |
| 221 // Jumps are handled by WriteJump. |
| 222 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
220 // | 223 // |
221 // Transfers with observable registers as the destination will be | 224 // Transfers with observable registers as the destination will be |
222 // immediately materialized so the source position information will | 225 // immediately materialized so the source position information will |
223 // be ordered correctly. | 226 // be ordered correctly. |
224 // | 227 // |
225 // Transfers without observable destination registers will initially | 228 // Transfers without observable destination registers will initially |
226 // be emitted as Nop's with the source position. They may, or may | 229 // be emitted as Nop's with the source position. They may, or may |
227 // not, be materialized by the optimizer. However, the source | 230 // not, be materialized by the optimizer. However, the source |
228 // position is not lost and being attached to a Nop is fine as the | 231 // position is not lost and being attached to a Nop is fine as the |
229 // destination register is not observable in the debugger. | 232 // destination register is not observable in the debugger. |
230 // | 233 // |
231 switch (node->bytecode()) { | 234 switch (node->bytecode()) { |
232 case Bytecode::kLdar: { | 235 case Bytecode::kLdar: { |
233 DoLdar(node); | 236 DoLdar(node); |
234 return; | 237 return; |
235 } | 238 } |
236 case Bytecode::kStar: { | 239 case Bytecode::kStar: { |
237 DoStar(node); | 240 DoStar(node); |
238 return; | 241 return; |
239 } | 242 } |
240 case Bytecode::kMov: { | 243 case Bytecode::kMov: { |
241 DoMov(node); | 244 DoMov(node); |
242 return; | 245 return; |
243 } | 246 } |
244 default: | 247 default: |
245 break; | 248 break; |
246 } | 249 } |
247 | 250 |
248 if (Bytecodes::IsJump(node->bytecode()) || | 251 if (node->bytecode() == Bytecode::kDebugger || |
249 node->bytecode() == Bytecode::kDebugger || | |
250 node->bytecode() == Bytecode::kSuspendGenerator) { | 252 node->bytecode() == Bytecode::kSuspendGenerator) { |
251 // All state must be flushed before emitting | 253 // All state must be flushed before emitting |
252 // - a jump (due to how bytecode offsets for jumps are evaluated), | |
253 // - a call to the debugger (as it can manipulate locals and parameters), | 254 // - a call to the debugger (as it can manipulate locals and parameters), |
254 // - a generator suspend (as this involves saving all registers). | 255 // - a generator suspend (as this involves saving all registers). |
255 FlushState(); | 256 FlushState(); |
256 } | 257 } |
257 | 258 |
258 PrepareOperands(node); | 259 PrepareOperands(node); |
259 WriteToNextStage(node); | 260 next_stage_->Write(node); |
260 } | 261 } |
261 | 262 |
262 // override | 263 // override |
263 void BytecodeRegisterOptimizer::WriteJump(BytecodeNode* node, | 264 void BytecodeRegisterOptimizer::WriteJump(BytecodeNode* node, |
264 BytecodeLabel* label) { | 265 BytecodeLabel* label) { |
265 FlushState(); | 266 FlushState(); |
266 next_stage_->WriteJump(node, label); | 267 next_stage_->WriteJump(node, label); |
267 } | 268 } |
268 | 269 |
269 // override | 270 // override |
(...skipping 29 matching lines...) Expand all Loading... |
299 OutputRegisterTransfer(reg_info, equivalent); | 300 OutputRegisterTransfer(reg_info, equivalent); |
300 } | 301 } |
301 equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true); | 302 equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true); |
302 } | 303 } |
303 } | 304 } |
304 } | 305 } |
305 | 306 |
306 flush_required_ = false; | 307 flush_required_ = false; |
307 } | 308 } |
308 | 309 |
309 void BytecodeRegisterOptimizer::WriteToNextStage(BytecodeNode* node) const { | |
310 next_stage_->Write(node); | |
311 } | |
312 | |
313 void BytecodeRegisterOptimizer::WriteToNextStage( | |
314 BytecodeNode* node, const BytecodeSourceInfo& source_info) const { | |
315 if (source_info.is_valid()) { | |
316 node->source_info().Clone(source_info); | |
317 } | |
318 next_stage_->Write(node); | |
319 } | |
320 | |
321 void BytecodeRegisterOptimizer::OutputRegisterTransfer( | 310 void BytecodeRegisterOptimizer::OutputRegisterTransfer( |
322 RegisterInfo* input_info, RegisterInfo* output_info, | 311 RegisterInfo* input_info, RegisterInfo* output_info, |
323 const BytecodeSourceInfo& source_info) { | 312 BytecodeSourceInfo* source_info) { |
324 Register input = input_info->register_value(); | 313 Register input = input_info->register_value(); |
325 Register output = output_info->register_value(); | 314 Register output = output_info->register_value(); |
326 DCHECK_NE(input.index(), output.index()); | 315 DCHECK_NE(input.index(), output.index()); |
327 | 316 |
328 if (input == accumulator_) { | 317 if (input == accumulator_) { |
329 uint32_t operand = static_cast<uint32_t>(output.ToOperand()); | 318 uint32_t operand = static_cast<uint32_t>(output.ToOperand()); |
330 BytecodeNode node(Bytecode::kStar, operand); | 319 BytecodeNode node(Bytecode::kStar, operand, source_info); |
331 WriteToNextStage(&node, source_info); | 320 next_stage_->Write(&node); |
332 } else if (output == accumulator_) { | 321 } else if (output == accumulator_) { |
333 uint32_t operand = static_cast<uint32_t>(input.ToOperand()); | 322 uint32_t operand = static_cast<uint32_t>(input.ToOperand()); |
334 BytecodeNode node(Bytecode::kLdar, operand); | 323 BytecodeNode node(Bytecode::kLdar, operand, source_info); |
335 WriteToNextStage(&node, source_info); | 324 next_stage_->Write(&node); |
336 } else { | 325 } else { |
337 uint32_t operand0 = static_cast<uint32_t>(input.ToOperand()); | 326 uint32_t operand0 = static_cast<uint32_t>(input.ToOperand()); |
338 uint32_t operand1 = static_cast<uint32_t>(output.ToOperand()); | 327 uint32_t operand1 = static_cast<uint32_t>(output.ToOperand()); |
339 BytecodeNode node(Bytecode::kMov, operand0, operand1); | 328 BytecodeNode node(Bytecode::kMov, operand0, operand1, source_info); |
340 WriteToNextStage(&node, source_info); | 329 next_stage_->Write(&node); |
| 330 } |
| 331 if (output != accumulator_) { |
| 332 max_register_index_ = std::max(max_register_index_, output.index()); |
341 } | 333 } |
342 output_info->set_materialized(true); | 334 output_info->set_materialized(true); |
343 } | 335 } |
344 | 336 |
345 void BytecodeRegisterOptimizer::CreateMaterializedEquivalent( | 337 void BytecodeRegisterOptimizer::CreateMaterializedEquivalent( |
346 RegisterInfo* info) { | 338 RegisterInfo* info) { |
347 DCHECK(info->materialized()); | 339 DCHECK(info->materialized()); |
348 RegisterInfo* unmaterialized = info->GetEquivalentToMaterialize(); | 340 RegisterInfo* unmaterialized = info->GetEquivalentToMaterialize(); |
349 if (unmaterialized) { | 341 if (unmaterialized) { |
350 OutputRegisterTransfer(info, unmaterialized); | 342 OutputRegisterTransfer(info, unmaterialized); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 void BytecodeRegisterOptimizer::AddToEquivalenceSet( | 374 void BytecodeRegisterOptimizer::AddToEquivalenceSet( |
383 RegisterInfo* set_member, RegisterInfo* non_set_member) { | 375 RegisterInfo* set_member, RegisterInfo* non_set_member) { |
384 non_set_member->AddToEquivalenceSetOf(set_member); | 376 non_set_member->AddToEquivalenceSetOf(set_member); |
385 // Flushing is only required when two or more registers are placed | 377 // Flushing is only required when two or more registers are placed |
386 // in the same equivalence set. | 378 // in the same equivalence set. |
387 flush_required_ = true; | 379 flush_required_ = true; |
388 } | 380 } |
389 | 381 |
390 void BytecodeRegisterOptimizer::RegisterTransfer( | 382 void BytecodeRegisterOptimizer::RegisterTransfer( |
391 RegisterInfo* input_info, RegisterInfo* output_info, | 383 RegisterInfo* input_info, RegisterInfo* output_info, |
392 const BytecodeSourceInfo& source_info) { | 384 BytecodeSourceInfo* source_info) { |
393 // Materialize an alternate in the equivalence set that | 385 // Materialize an alternate in the equivalence set that |
394 // |output_info| is leaving. | 386 // |output_info| is leaving. |
395 if (output_info->materialized()) { | 387 if (output_info->materialized()) { |
396 CreateMaterializedEquivalent(output_info); | 388 CreateMaterializedEquivalent(output_info); |
397 } | 389 } |
398 | 390 |
399 // Add |output_info| to new equivalence set. | 391 // Add |output_info| to new equivalence set. |
400 if (!output_info->IsInSameEquivalenceSet(input_info)) { | 392 if (!output_info->IsInSameEquivalenceSet(input_info)) { |
401 AddToEquivalenceSet(input_info, output_info); | 393 AddToEquivalenceSet(input_info, output_info); |
402 } | 394 } |
403 | 395 |
404 bool output_is_observable = | 396 bool output_is_observable = |
405 RegisterIsObservable(output_info->register_value()); | 397 RegisterIsObservable(output_info->register_value()); |
406 if (output_is_observable) { | 398 if (output_is_observable) { |
407 // Force store to be emitted when register is observable. | 399 // Force store to be emitted when register is observable. |
408 output_info->set_materialized(false); | 400 output_info->set_materialized(false); |
409 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent(); | 401 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent(); |
410 OutputRegisterTransfer(materialized_info, output_info, source_info); | 402 OutputRegisterTransfer(materialized_info, output_info, source_info); |
411 } else if (source_info.is_valid()) { | 403 } else if (source_info->is_valid()) { |
412 // Emit a placeholder nop to maintain source position info. | 404 // Emit a placeholder nop to maintain source position info. |
413 EmitNopForSourceInfo(source_info); | 405 EmitNopForSourceInfo(source_info); |
414 } | 406 } |
415 } | 407 } |
416 | 408 |
417 void BytecodeRegisterOptimizer::EmitNopForSourceInfo( | 409 void BytecodeRegisterOptimizer::EmitNopForSourceInfo( |
418 const BytecodeSourceInfo& source_info) const { | 410 BytecodeSourceInfo* source_info) const { |
419 DCHECK(source_info.is_valid()); | 411 DCHECK(source_info->is_valid()); |
420 BytecodeNode nop(Bytecode::kNop); | 412 BytecodeNode nop(Bytecode::kNop, source_info); |
421 nop.source_info().Clone(source_info); | 413 next_stage_->Write(&nop); |
422 WriteToNextStage(&nop); | |
423 } | 414 } |
424 | 415 |
425 void BytecodeRegisterOptimizer::DoLdar(const BytecodeNode* const node) { | 416 void BytecodeRegisterOptimizer::DoLdar(BytecodeNode* node) { |
426 Register input = GetRegisterInputOperand( | 417 Register input = GetRegisterInputOperand( |
427 0, node->bytecode(), node->operands(), node->operand_count()); | 418 0, node->bytecode(), node->operands(), node->operand_count()); |
428 RegisterInfo* input_info = GetRegisterInfo(input); | 419 RegisterInfo* input_info = GetRegisterInfo(input); |
429 RegisterTransfer(input_info, accumulator_info_, node->source_info()); | 420 RegisterTransfer(input_info, accumulator_info_, node->source_info_ptr()); |
430 } | 421 } |
431 | 422 |
432 void BytecodeRegisterOptimizer::DoMov(const BytecodeNode* const node) { | 423 void BytecodeRegisterOptimizer::DoMov(BytecodeNode* node) { |
433 Register input = GetRegisterInputOperand( | 424 Register input = GetRegisterInputOperand( |
434 0, node->bytecode(), node->operands(), node->operand_count()); | 425 0, node->bytecode(), node->operands(), node->operand_count()); |
435 RegisterInfo* input_info = GetRegisterInfo(input); | 426 RegisterInfo* input_info = GetRegisterInfo(input); |
436 Register output = GetRegisterOutputOperand( | 427 Register output = GetRegisterOutputOperand( |
437 1, node->bytecode(), node->operands(), node->operand_count()); | 428 1, node->bytecode(), node->operands(), node->operand_count()); |
438 RegisterInfo* output_info = GetOrCreateRegisterInfo(output); | 429 RegisterInfo* output_info = GetOrCreateRegisterInfo(output); |
439 RegisterTransfer(input_info, output_info, node->source_info()); | 430 RegisterTransfer(input_info, output_info, node->source_info_ptr()); |
440 } | 431 } |
441 | 432 |
442 void BytecodeRegisterOptimizer::DoStar(const BytecodeNode* const node) { | 433 void BytecodeRegisterOptimizer::DoStar(BytecodeNode* node) { |
443 Register output = GetRegisterOutputOperand( | 434 Register output = GetRegisterOutputOperand( |
444 0, node->bytecode(), node->operands(), node->operand_count()); | 435 0, node->bytecode(), node->operands(), node->operand_count()); |
445 RegisterInfo* output_info = GetOrCreateRegisterInfo(output); | 436 RegisterInfo* output_info = GetOrCreateRegisterInfo(output); |
446 RegisterTransfer(accumulator_info_, output_info, node->source_info()); | 437 RegisterTransfer(accumulator_info_, output_info, node->source_info_ptr()); |
447 } | 438 } |
448 | 439 |
449 void BytecodeRegisterOptimizer::PrepareRegisterOutputOperand( | 440 void BytecodeRegisterOptimizer::PrepareRegisterOutputOperand( |
450 RegisterInfo* reg_info) { | 441 RegisterInfo* reg_info) { |
451 if (reg_info->materialized()) { | 442 if (reg_info->materialized()) { |
452 CreateMaterializedEquivalent(reg_info); | 443 CreateMaterializedEquivalent(reg_info); |
453 } | 444 } |
| 445 max_register_index_ = |
| 446 std::max(max_register_index_, reg_info->register_value().index()); |
454 reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true); | 447 reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true); |
455 } | 448 } |
456 | 449 |
457 void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand( | 450 void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand( |
458 Register start, int count) { | 451 Register start, int count) { |
459 for (int i = 0; i < count; ++i) { | 452 for (int i = 0; i < count; ++i) { |
460 Register reg(start.index() + i); | 453 Register reg(start.index() + i); |
461 RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); | 454 RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); |
462 PrepareRegisterOutputOperand(reg_info); | 455 PrepareRegisterOutputOperand(reg_info); |
463 } | 456 } |
(...skipping 10 matching lines...) Expand all Loading... |
474 } else { | 467 } else { |
475 RegisterInfo* equivalent_info = | 468 RegisterInfo* equivalent_info = |
476 GetMaterializedEquivalentNotAccumulator(reg_info); | 469 GetMaterializedEquivalentNotAccumulator(reg_info); |
477 return equivalent_info->register_value(); | 470 return equivalent_info->register_value(); |
478 } | 471 } |
479 } | 472 } |
480 | 473 |
481 void BytecodeRegisterOptimizer::PrepareRegisterInputOperand( | 474 void BytecodeRegisterOptimizer::PrepareRegisterInputOperand( |
482 BytecodeNode* const node, Register reg, int operand_index) { | 475 BytecodeNode* const node, Register reg, int operand_index) { |
483 Register equivalent = GetEquivalentRegisterForInputOperand(reg); | 476 Register equivalent = GetEquivalentRegisterForInputOperand(reg); |
484 node->operands()[operand_index] = | 477 node->UpdateOperand(operand_index, |
485 static_cast<uint32_t>(equivalent.ToOperand()); | 478 static_cast<uint32_t>(equivalent.ToOperand())); |
486 } | 479 } |
487 | 480 |
488 void BytecodeRegisterOptimizer::PrepareRegisterRangeInputOperand(Register start, | 481 void BytecodeRegisterOptimizer::PrepareRegisterRangeInputOperand(Register start, |
489 int count) { | 482 int count) { |
490 for (int i = 0; i < count; ++i) { | 483 for (int i = 0; i < count; ++i) { |
491 Register current(start.index() + i); | 484 Register current(start.index() + i); |
492 RegisterInfo* input_info = GetRegisterInfo(current); | 485 RegisterInfo* input_info = GetRegisterInfo(current); |
493 Materialize(input_info); | 486 Materialize(input_info); |
494 } | 487 } |
495 } | 488 } |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 if (info->materialized()) { | 611 if (info->materialized()) { |
619 CreateMaterializedEquivalent(info); | 612 CreateMaterializedEquivalent(info); |
620 } | 613 } |
621 info->MoveToNewEquivalenceSet(kInvalidEquivalenceId, false); | 614 info->MoveToNewEquivalenceSet(kInvalidEquivalenceId, false); |
622 } | 615 } |
623 } | 616 } |
624 | 617 |
625 } // namespace interpreter | 618 } // namespace interpreter |
626 } // namespace internal | 619 } // namespace internal |
627 } // namespace v8 | 620 } // namespace v8 |
OLD | NEW |