Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: src/interpreter/bytecode-register-optimizer.cc

Issue 2393683004: [Interpreter] Optimize the Register Optimizer. (Closed)
Patch Set: Rebase Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 for (size_t i = 0; i < register_info_table_.size(); ++i) { 223 for (size_t i = 0; i < register_info_table_.size(); ++i) {
224 register_info_table_[i] = new (zone) RegisterInfo( 224 register_info_table_[i] = new (zone) RegisterInfo(
225 RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true, true); 225 RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true, true);
226 DCHECK_EQ(register_info_table_[i]->register_value().index(), 226 DCHECK_EQ(register_info_table_[i]->register_value().index(),
227 RegisterFromRegisterInfoTableIndex(i).index()); 227 RegisterFromRegisterInfoTableIndex(i).index());
228 } 228 }
229 accumulator_info_ = GetRegisterInfo(accumulator_); 229 accumulator_info_ = GetRegisterInfo(accumulator_);
230 DCHECK(accumulator_info_->register_value() == accumulator_); 230 DCHECK(accumulator_info_->register_value() == accumulator_);
231 } 231 }
232 232
233 // override 233 void BytecodeRegisterOptimizer::Flush() {
234 Handle<BytecodeArray> BytecodeRegisterOptimizer::ToBytecodeArray(
235 Isolate* isolate, int register_count, int parameter_count,
236 Handle<FixedArray> handler_table) {
237 FlushState();
238 return next_stage_->ToBytecodeArray(isolate, max_register_index_ + 1,
239 parameter_count, handler_table);
240 }
241
242 // override
243 void BytecodeRegisterOptimizer::Write(BytecodeNode* node) {
244 // Jumps are handled by WriteJump.
245 DCHECK(!Bytecodes::IsJump(node->bytecode()));
246 //
247 // Transfers with observable registers as the destination will be
248 // immediately materialized so the source position information will
249 // be ordered correctly.
250 //
251 // Transfers without observable destination registers will initially
252 // be emitted as Nop's with the source position. They may, or may
253 // not, be materialized by the optimizer. However, the source
254 // position is not lost and being attached to a Nop is fine as the
255 // destination register is not observable in the debugger.
256 //
257 switch (node->bytecode()) {
258 case Bytecode::kLdar: {
259 DoLdar(node);
260 return;
261 }
262 case Bytecode::kStar: {
263 DoStar(node);
264 return;
265 }
266 case Bytecode::kMov: {
267 DoMov(node);
268 return;
269 }
270 default:
271 break;
272 }
273
274 if (node->bytecode() == Bytecode::kDebugger ||
275 node->bytecode() == Bytecode::kSuspendGenerator) {
276 // All state must be flushed before emitting
277 // - a call to the debugger (as it can manipulate locals and parameters),
278 // - a generator suspend (as this involves saving all registers).
279 FlushState();
280 }
281
282 PrepareOperands(node);
283 next_stage_->Write(node);
284 }
285
286 // override
287 void BytecodeRegisterOptimizer::WriteJump(BytecodeNode* node,
288 BytecodeLabel* label) {
289 FlushState();
290 next_stage_->WriteJump(node, label);
291 }
292
293 // override
294 void BytecodeRegisterOptimizer::BindLabel(BytecodeLabel* label) {
295 FlushState();
296 next_stage_->BindLabel(label);
297 }
298
299 // override
300 void BytecodeRegisterOptimizer::BindLabel(const BytecodeLabel& target,
301 BytecodeLabel* label) {
302 // There is no need to flush here, it will have been flushed when |target|
303 // was bound.
304 next_stage_->BindLabel(target, label);
305 }
306
307 void BytecodeRegisterOptimizer::FlushState() {
308 if (!flush_required_) { 234 if (!flush_required_) {
309 return; 235 return;
310 } 236 }
311 237
312 // Materialize all live registers and break equivalences. 238 // Materialize all live registers and break equivalences.
313 size_t count = register_info_table_.size(); 239 size_t count = register_info_table_.size();
314 for (size_t i = 0; i < count; ++i) { 240 for (size_t i = 0; i < count; ++i) {
315 RegisterInfo* reg_info = register_info_table_[i]; 241 RegisterInfo* reg_info = register_info_table_[i];
316 if (reg_info->materialized()) { 242 if (reg_info->materialized()) {
317 // Walk equivalents of materialized registers, materializing 243 // Walk equivalents of materialized registers, materializing
318 // each equivalent register as necessary and placing in their 244 // each equivalent register as necessary and placing in their
319 // own equivalence set. 245 // own equivalence set.
320 RegisterInfo* equivalent; 246 RegisterInfo* equivalent;
321 while ((equivalent = reg_info->GetEquivalent()) != reg_info) { 247 while ((equivalent = reg_info->GetEquivalent()) != reg_info) {
322 if (equivalent->allocated() && !equivalent->materialized()) { 248 if (equivalent->allocated() && !equivalent->materialized()) {
323 OutputRegisterTransfer(reg_info, equivalent); 249 OutputRegisterTransfer(reg_info, equivalent);
324 } 250 }
325 equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true); 251 equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
326 } 252 }
327 } 253 }
328 } 254 }
329 255
330 flush_required_ = false; 256 flush_required_ = false;
331 } 257 }
332 258
333 void BytecodeRegisterOptimizer::OutputRegisterTransfer( 259 void BytecodeRegisterOptimizer::OutputRegisterTransfer(
334 RegisterInfo* input_info, RegisterInfo* output_info, 260 RegisterInfo* input_info, RegisterInfo* output_info,
335 BytecodeSourceInfo* source_info) { 261 BytecodeSourceInfo source_info) {
336 Register input = input_info->register_value(); 262 Register input = input_info->register_value();
337 Register output = output_info->register_value(); 263 Register output = output_info->register_value();
338 DCHECK_NE(input.index(), output.index()); 264 DCHECK_NE(input.index(), output.index());
339 265
340 if (input == accumulator_) { 266 if (input == accumulator_) {
341 uint32_t operand = static_cast<uint32_t>(output.ToOperand()); 267 uint32_t operand = static_cast<uint32_t>(output.ToOperand());
342 BytecodeNode node(Bytecode::kStar, operand, source_info); 268 BytecodeNode node(Bytecode::kStar, operand, source_info);
343 next_stage_->Write(&node); 269 next_stage_->Write(&node);
344 } else if (output == accumulator_) { 270 } else if (output == accumulator_) {
345 uint32_t operand = static_cast<uint32_t>(input.ToOperand()); 271 uint32_t operand = static_cast<uint32_t>(input.ToOperand());
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 void BytecodeRegisterOptimizer::AddToEquivalenceSet( 323 void BytecodeRegisterOptimizer::AddToEquivalenceSet(
398 RegisterInfo* set_member, RegisterInfo* non_set_member) { 324 RegisterInfo* set_member, RegisterInfo* non_set_member) {
399 non_set_member->AddToEquivalenceSetOf(set_member); 325 non_set_member->AddToEquivalenceSetOf(set_member);
400 // Flushing is only required when two or more registers are placed 326 // Flushing is only required when two or more registers are placed
401 // in the same equivalence set. 327 // in the same equivalence set.
402 flush_required_ = true; 328 flush_required_ = true;
403 } 329 }
404 330
405 void BytecodeRegisterOptimizer::RegisterTransfer( 331 void BytecodeRegisterOptimizer::RegisterTransfer(
406 RegisterInfo* input_info, RegisterInfo* output_info, 332 RegisterInfo* input_info, RegisterInfo* output_info,
407 BytecodeSourceInfo* source_info) { 333 BytecodeSourceInfo source_info) {
408 // Materialize an alternate in the equivalence set that 334 // Materialize an alternate in the equivalence set that
409 // |output_info| is leaving. 335 // |output_info| is leaving.
410 if (output_info->materialized()) { 336 if (output_info->materialized()) {
411 CreateMaterializedEquivalent(output_info); 337 CreateMaterializedEquivalent(output_info);
412 } 338 }
413 339
414 // Add |output_info| to new equivalence set. 340 // Add |output_info| to new equivalence set.
415 if (!output_info->IsInSameEquivalenceSet(input_info)) { 341 if (!output_info->IsInSameEquivalenceSet(input_info)) {
416 AddToEquivalenceSet(input_info, output_info); 342 AddToEquivalenceSet(input_info, output_info);
417 } 343 }
418 344
419 bool output_is_observable = 345 bool output_is_observable =
420 RegisterIsObservable(output_info->register_value()); 346 RegisterIsObservable(output_info->register_value());
421 if (output_is_observable) { 347 if (output_is_observable) {
422 // Force store to be emitted when register is observable. 348 // Force store to be emitted when register is observable.
423 output_info->set_materialized(false); 349 output_info->set_materialized(false);
424 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent(); 350 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent();
425 OutputRegisterTransfer(materialized_info, output_info, source_info); 351 OutputRegisterTransfer(materialized_info, output_info, source_info);
426 } else if (source_info->is_valid()) { 352 } else if (source_info.is_valid()) {
427 // Emit a placeholder nop to maintain source position info. 353 // Emit a placeholder nop to maintain source position info.
428 EmitNopForSourceInfo(source_info); 354 EmitNopForSourceInfo(source_info);
429 } 355 }
430 356
431 bool input_is_observable = RegisterIsObservable(input_info->register_value()); 357 bool input_is_observable = RegisterIsObservable(input_info->register_value());
432 if (input_is_observable) { 358 if (input_is_observable) {
433 // If input is observable by the debugger, mark all other temporaries 359 // If input is observable by the debugger, mark all other temporaries
434 // registers as unmaterialized so that this register is used in preference. 360 // registers as unmaterialized so that this register is used in preference.
435 input_info->MarkTemporariesAsUnmaterialized(temporary_base_); 361 input_info->MarkTemporariesAsUnmaterialized(temporary_base_);
436 } 362 }
437 } 363 }
438 364
439 void BytecodeRegisterOptimizer::EmitNopForSourceInfo( 365 void BytecodeRegisterOptimizer::EmitNopForSourceInfo(
440 BytecodeSourceInfo* source_info) const { 366 BytecodeSourceInfo source_info) const {
441 DCHECK(source_info->is_valid()); 367 DCHECK(source_info.is_valid());
442 BytecodeNode nop(Bytecode::kNop, source_info); 368 BytecodeNode nop(Bytecode::kNop, source_info);
443 next_stage_->Write(&nop); 369 next_stage_->Write(&nop);
444 } 370 }
445 371
446 void BytecodeRegisterOptimizer::DoLdar(BytecodeNode* node) { 372 void BytecodeRegisterOptimizer::PrepareOutputRegister(Register reg) {
447 Register input = GetRegisterInputOperand( 373 RegisterInfo* reg_info = GetRegisterInfo(reg);
448 0, node->bytecode(), node->operands(), node->operand_count());
449 RegisterInfo* input_info = GetRegisterInfo(input);
450 RegisterTransfer(input_info, accumulator_info_, node->source_info_ptr());
451 }
452
453 void BytecodeRegisterOptimizer::DoMov(BytecodeNode* node) {
454 Register input = GetRegisterInputOperand(
455 0, node->bytecode(), node->operands(), node->operand_count());
456 RegisterInfo* input_info = GetRegisterInfo(input);
457 Register output = GetRegisterOutputOperand(
458 1, node->bytecode(), node->operands(), node->operand_count());
459 RegisterInfo* output_info = GetRegisterInfo(output);
460 RegisterTransfer(input_info, output_info, node->source_info_ptr());
461 }
462
463 void BytecodeRegisterOptimizer::DoStar(BytecodeNode* node) {
464 Register output = GetRegisterOutputOperand(
465 0, node->bytecode(), node->operands(), node->operand_count());
466 RegisterInfo* output_info = GetRegisterInfo(output);
467 RegisterTransfer(accumulator_info_, output_info, node->source_info_ptr());
468 }
469
470 void BytecodeRegisterOptimizer::PrepareRegisterOutputOperand(
471 RegisterInfo* reg_info) {
472 if (reg_info->materialized()) { 374 if (reg_info->materialized()) {
473 CreateMaterializedEquivalent(reg_info); 375 CreateMaterializedEquivalent(reg_info);
474 } 376 }
377 reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
475 max_register_index_ = 378 max_register_index_ =
476 std::max(max_register_index_, reg_info->register_value().index()); 379 std::max(max_register_index_, reg_info->register_value().index());
477 reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
478 } 380 }
479 381
480 void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand( 382 void BytecodeRegisterOptimizer::PrepareOutputRegisterList(
481 Register start, int count) { 383 RegisterList reg_list) {
482 for (int i = 0; i < count; ++i) { 384 int start_index = reg_list.first_register().index();
483 Register reg(start.index() + i); 385 for (int i = 0; i < reg_list.register_count(); ++i) {
484 RegisterInfo* reg_info = GetRegisterInfo(reg); 386 Register current(start_index + i);
485 PrepareRegisterOutputOperand(reg_info); 387 PrepareOutputRegister(current);
486 } 388 }
487 } 389 }
488 390
489 Register BytecodeRegisterOptimizer::GetEquivalentRegisterForInputOperand( 391 Register BytecodeRegisterOptimizer::GetInputRegister(Register reg) {
490 Register reg) {
491 // For a temporary register, RegInfo state may need be created. For
492 // locals and parameters, the RegInfo state is created in the
493 // BytecodeRegisterOptimizer constructor.
494 RegisterInfo* reg_info = GetRegisterInfo(reg); 392 RegisterInfo* reg_info = GetRegisterInfo(reg);
495 if (reg_info->materialized()) { 393 if (reg_info->materialized()) {
496 return reg; 394 return reg;
497 } else { 395 } else {
498 RegisterInfo* equivalent_info = 396 RegisterInfo* equivalent_info =
499 GetMaterializedEquivalentNotAccumulator(reg_info); 397 GetMaterializedEquivalentNotAccumulator(reg_info);
500 return equivalent_info->register_value(); 398 return equivalent_info->register_value();
501 } 399 }
502 } 400 }
503 401
504 void BytecodeRegisterOptimizer::PrepareRegisterInputOperand( 402 RegisterList BytecodeRegisterOptimizer::GetInputRegisterList(
505 BytecodeNode* const node, Register reg, int operand_index) { 403 RegisterList reg_list) {
506 Register equivalent = GetEquivalentRegisterForInputOperand(reg); 404 if (reg_list.register_count() == 1) {
507 node->UpdateOperand(operand_index, 405 // If there is only a single register, treat it as a normal input register.
508 static_cast<uint32_t>(equivalent.ToOperand())); 406 Register reg(GetInputRegister(reg_list.first_register()));
509 } 407 return RegisterList(reg.index(), 1);
510 408 } else {
511 void BytecodeRegisterOptimizer::PrepareRegisterRangeInputOperand(Register start, 409 int start_index = reg_list.first_register().index();
512 int count) { 410 for (int i = 0; i < reg_list.register_count(); ++i) {
513 for (int i = 0; i < count; ++i) { 411 Register current(start_index + i);
514 Register current(start.index() + i); 412 RegisterInfo* input_info = GetRegisterInfo(current);
515 RegisterInfo* input_info = GetRegisterInfo(current); 413 Materialize(input_info);
516 Materialize(input_info); 414 }
415 return reg_list;
517 } 416 }
518 } 417 }
519 418
520 void BytecodeRegisterOptimizer::PrepareRegisterOperands( 419 void BytecodeRegisterOptimizer::PrepareForBytecode(Bytecode bytecode) {
521 BytecodeNode* const node) { 420 if (Bytecodes::IsJump(bytecode) || bytecode == Bytecode::kDebugger ||
522 // 421 bytecode == Bytecode::kSuspendGenerator) {
523 // For each input operand, get a materialized equivalent if it is 422 // All state must be flushed before emitting
524 // just a single register, otherwise materialize register range. 423 // - a jump bytecode (as the register equivalents at the jump target aren't
525 // Update operand_scale if necessary. 424 // known.
526 // 425 // - a call to the debugger (as it can manipulate locals and parameters),
527 // For each output register about to be clobbered, materialize an 426 // - a generator suspend (as this involves saving all registers).
528 // equivalent if it exists. Put each register in it's own equivalence set. 427 Flush();
529 // 428 }
530 const uint32_t* operands = node->operands();
531 int operand_count = node->operand_count();
532 const OperandType* operand_types =
533 Bytecodes::GetOperandTypes(node->bytecode());
534 for (int i = 0; i < operand_count; ++i) {
535 int count;
536 if (operand_types[i] == OperandType::kRegList) {
537 DCHECK_LT(i, operand_count - 1);
538 DCHECK(operand_types[i + 1] == OperandType::kRegCount);
539 count = static_cast<int>(operands[i + 1]);
540 } else {
541 count = Bytecodes::GetNumberOfRegistersRepresentedBy(operand_types[i]);
542 }
543 429
544 if (count == 0) {
545 continue;
546 }
547
548 Register reg = Register::FromOperand(static_cast<int32_t>(operands[i]));
549 if (Bytecodes::IsRegisterInputOperandType(operand_types[i])) {
550 if (count == 1) {
551 PrepareRegisterInputOperand(node, reg, i);
552 } else if (count > 1) {
553 PrepareRegisterRangeInputOperand(reg, count);
554 }
555 } else if (Bytecodes::IsRegisterOutputOperandType(operand_types[i])) {
556 PrepareRegisterRangeOutputOperand(reg, count);
557 }
558 }
559 }
560
561 void BytecodeRegisterOptimizer::PrepareAccumulator(BytecodeNode* const node) {
562 // Materialize the accumulator if it is read by the bytecode. The 430 // Materialize the accumulator if it is read by the bytecode. The
563 // accumulator is special and no other register can be materialized 431 // accumulator is special and no other register can be materialized
564 // in it's place. 432 // in it's place.
565 if (Bytecodes::ReadsAccumulator(node->bytecode()) && 433 if (Bytecodes::ReadsAccumulator(bytecode) &&
566 !accumulator_info_->materialized()) { 434 !accumulator_info_->materialized()) {
567 Materialize(accumulator_info_); 435 Materialize(accumulator_info_);
568 } 436 }
569 437
570 // Materialize an equivalent to the accumulator if it will be 438 // Materialize an equivalent to the accumulator if it will be
571 // clobbered when the bytecode is dispatched. 439 // clobbered when the bytecode is dispatched.
572 if (Bytecodes::WritesAccumulator(node->bytecode())) { 440 if (Bytecodes::WritesAccumulator(bytecode)) {
573 PrepareRegisterOutputOperand(accumulator_info_); 441 PrepareOutputRegister(accumulator_);
574 } 442 }
575 } 443 }
576 444
577 void BytecodeRegisterOptimizer::PrepareOperands(BytecodeNode* const node) {
578 PrepareAccumulator(node);
579 PrepareRegisterOperands(node);
580 }
581
582 // static
583 Register BytecodeRegisterOptimizer::GetRegisterInputOperand(
584 int index, Bytecode bytecode, const uint32_t* operands, int operand_count) {
585 DCHECK_LT(index, operand_count);
586 DCHECK(Bytecodes::IsRegisterInputOperandType(
587 Bytecodes::GetOperandType(bytecode, index)));
588 return OperandToRegister(operands[index]);
589 }
590
591 // static
592 Register BytecodeRegisterOptimizer::GetRegisterOutputOperand(
593 int index, Bytecode bytecode, const uint32_t* operands, int operand_count) {
594 DCHECK_LT(index, operand_count);
595 DCHECK(Bytecodes::IsRegisterOutputOperandType(
596 Bytecodes::GetOperandType(bytecode, index)));
597 return OperandToRegister(operands[index]);
598 }
599
600 BytecodeRegisterOptimizer::RegisterInfo*
601 BytecodeRegisterOptimizer::GetRegisterInfo(Register reg) {
602 size_t index = GetRegisterInfoTableIndex(reg);
603 DCHECK_LT(index, register_info_table_.size());
604 return register_info_table_[index];
605 }
606
607 BytecodeRegisterOptimizer::RegisterInfo*
608 BytecodeRegisterOptimizer::GetOrCreateRegisterInfo(Register reg) {
609 size_t index = GetRegisterInfoTableIndex(reg);
610 return index < register_info_table_.size() ? register_info_table_[index]
611 : NewRegisterInfo(reg);
612 }
613
614 BytecodeRegisterOptimizer::RegisterInfo*
615 BytecodeRegisterOptimizer::NewRegisterInfo(Register reg) {
616 size_t index = GetRegisterInfoTableIndex(reg);
617 DCHECK_GE(index, register_info_table_.size());
618 GrowRegisterMap(reg);
619 return register_info_table_[index];
620 }
621
622 void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) { 445 void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) {
623 DCHECK(RegisterIsTemporary(reg)); 446 DCHECK(RegisterIsTemporary(reg));
624 size_t index = GetRegisterInfoTableIndex(reg); 447 size_t index = GetRegisterInfoTableIndex(reg);
625 if (index >= register_info_table_.size()) { 448 if (index >= register_info_table_.size()) {
626 size_t new_size = index + 1; 449 size_t new_size = index + 1;
627 size_t old_size = register_info_table_.size(); 450 size_t old_size = register_info_table_.size();
628 register_info_table_.resize(new_size); 451 register_info_table_.resize(new_size);
629 for (size_t i = old_size; i < new_size; ++i) { 452 for (size_t i = old_size; i < new_size; ++i) {
630 register_info_table_[i] = 453 register_info_table_[i] =
631 new (zone()) RegisterInfo(RegisterFromRegisterInfoTableIndex(i), 454 new (zone()) RegisterInfo(RegisterFromRegisterInfoTableIndex(i),
(...skipping 20 matching lines...) Expand all
652 void BytecodeRegisterOptimizer::RegisterListFreeEvent(RegisterList reg_list) { 475 void BytecodeRegisterOptimizer::RegisterListFreeEvent(RegisterList reg_list) {
653 int first_index = reg_list.first_register().index(); 476 int first_index = reg_list.first_register().index();
654 for (int i = 0; i < reg_list.register_count(); i++) { 477 for (int i = 0; i < reg_list.register_count(); i++) {
655 GetRegisterInfo(Register(first_index + i))->set_allocated(false); 478 GetRegisterInfo(Register(first_index + i))->set_allocated(false);
656 } 479 }
657 } 480 }
658 481
659 } // namespace interpreter 482 } // namespace interpreter
660 } // namespace internal 483 } // namespace internal
661 } // namespace v8 484 } // namespace v8
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-register-optimizer.h ('k') | test/unittests/interpreter/bytecode-array-writer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698