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

Side by Side Diff: runtime/vm/intermediate_language_x64.cc

Issue 27307005: Change == into an instance call to allow polymorphic inlining of ==. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: rebased, addressed comments Created 7 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 | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intermediate_language_mips.cc ('k') | runtime/vm/intrinsifier.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 9
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
400 locs->set_in(0, Location::RegisterOrConstant(left())); 400 locs->set_in(0, Location::RegisterOrConstant(left()));
401 // Only one input can be a constant operand. The case of two constant 401 // Only one input can be a constant operand. The case of two constant
402 // operands should be handled by constant propagation. 402 // operands should be handled by constant propagation.
403 // Only right can be a stack slot. 403 // Only right can be a stack slot.
404 locs->set_in(1, locs->in(0).IsConstant() 404 locs->set_in(1, locs->in(0).IsConstant()
405 ? Location::RequiresRegister() 405 ? Location::RequiresRegister()
406 : Location::RegisterOrConstant(right())); 406 : Location::RegisterOrConstant(right()));
407 locs->set_out(Location::RequiresRegister()); 407 locs->set_out(Location::RequiresRegister());
408 return locs; 408 return locs;
409 } 409 }
410 if (IsCheckedStrictEqual()) { 410 UNREACHABLE();
411 const intptr_t kNumTemps = 1; 411 return NULL;
412 LocationSummary* locs =
413 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
414 locs->set_in(0, Location::RequiresRegister());
415 locs->set_in(1, Location::RequiresRegister());
416 locs->set_temp(0, Location::RequiresRegister());
417 locs->set_out(Location::RequiresRegister());
418 return locs;
419 }
420 if (IsPolymorphic()) {
421 const intptr_t kNumTemps = 1;
422 LocationSummary* locs =
423 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
424 locs->set_in(0, Location::RegisterLocation(RCX));
425 locs->set_in(1, Location::RegisterLocation(RDX));
426 locs->set_temp(0, Location::RegisterLocation(RBX));
427 locs->set_out(Location::RegisterLocation(RAX));
428 return locs;
429 }
430 const intptr_t kNumTemps = 1;
431 LocationSummary* locs =
432 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
433 locs->set_in(0, Location::RegisterLocation(RCX));
434 locs->set_in(1, Location::RegisterLocation(RDX));
435 locs->set_temp(0, Location::RegisterLocation(RBX));
436 locs->set_out(Location::RegisterLocation(RAX));
437 return locs;
438 }
439
440
441 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
442 intptr_t deopt_id,
443 intptr_t token_pos,
444 Token::Kind kind,
445 LocationSummary* locs,
446 const ICData& original_ic_data) {
447 if (!compiler->is_optimizing()) {
448 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
449 deopt_id,
450 token_pos);
451 }
452 const int kNumberOfArguments = 2;
453 const Array& kNoArgumentNames = Object::null_array();
454 const int kNumArgumentsChecked = 2;
455
456 ICData& equality_ic_data = ICData::ZoneHandle(original_ic_data.raw());
457 if (compiler->is_optimizing() && FLAG_propagate_ic_data) {
458 ASSERT(!original_ic_data.IsNull());
459 if (original_ic_data.NumberOfChecks() == 0) {
460 // IC call for reoptimization populates original ICData.
461 equality_ic_data = original_ic_data.raw();
462 } else {
463 // Megamorphic call.
464 equality_ic_data = original_ic_data.AsUnaryClassChecks();
465 }
466 } else {
467 const Array& arguments_descriptor =
468 Array::Handle(ArgumentsDescriptor::New(kNumberOfArguments,
469 kNoArgumentNames));
470 equality_ic_data = ICData::New(compiler->parsed_function().function(),
471 Symbols::EqualOperator(),
472 arguments_descriptor,
473 deopt_id,
474 kNumArgumentsChecked);
475 }
476 compiler->GenerateInstanceCall(deopt_id,
477 token_pos,
478 kNumberOfArguments,
479 kNoArgumentNames,
480 locs,
481 equality_ic_data);
482 if (kind == Token::kNE) {
483 Label true_label, done;
484 // Negate the condition: true label returns false and vice versa.
485 __ CompareObject(RAX, Bool::True(), PP);
486 __ j(EQUAL, &true_label, Assembler::kNearJump);
487 __ LoadObject(RAX, Bool::True(), PP);
488 __ jmp(&done, Assembler::kNearJump);
489 __ Bind(&true_label);
490 __ LoadObject(RAX, Bool::False(), PP);
491 __ Bind(&done);
492 }
493 } 412 }
494 413
495 414
496 static void LoadValueCid(FlowGraphCompiler* compiler, 415 static void LoadValueCid(FlowGraphCompiler* compiler,
497 Register value_cid_reg, 416 Register value_cid_reg,
498 Register value_reg, 417 Register value_reg,
499 Label* value_is_smi = NULL) { 418 Label* value_is_smi = NULL) {
500 Label done; 419 Label done;
501 if (value_is_smi == NULL) { 420 if (value_is_smi == NULL) {
502 __ LoadImmediate(value_cid_reg, Immediate(kSmiCid), PP); 421 __ LoadImmediate(value_cid_reg, Immediate(kSmiCid), PP);
503 } 422 }
504 __ testq(value_reg, Immediate(kSmiTagMask)); 423 __ testq(value_reg, Immediate(kSmiTagMask));
505 if (value_is_smi == NULL) { 424 if (value_is_smi == NULL) {
506 __ j(ZERO, &done, Assembler::kNearJump); 425 __ j(ZERO, &done, Assembler::kNearJump);
507 } else { 426 } else {
508 __ j(ZERO, value_is_smi); 427 __ j(ZERO, value_is_smi);
509 } 428 }
510 __ LoadClassId(value_cid_reg, value_reg); 429 __ LoadClassId(value_cid_reg, value_reg);
511 __ Bind(&done); 430 __ Bind(&done);
512 } 431 }
513 432
514 433
515 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
516 const ICData& orig_ic_data,
517 LocationSummary* locs,
518 BranchInstr* branch,
519 Token::Kind kind,
520 intptr_t deopt_id,
521 intptr_t token_pos) {
522 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
523 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
524 ASSERT(ic_data.NumberOfChecks() > 0);
525 ASSERT(ic_data.num_args_tested() == 1);
526 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
527 Register left = locs->in(0).reg();
528 Register right = locs->in(1).reg();
529 Register temp = locs->temp(0).reg();
530 LoadValueCid(compiler, temp, left,
531 (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
532 // 'temp' contains class-id of the left argument.
533 ObjectStore* object_store = Isolate::Current()->object_store();
534 Condition cond = TokenKindToSmiCondition(kind);
535 Label done;
536 const intptr_t len = ic_data.NumberOfChecks();
537 for (intptr_t i = 0; i < len; i++) {
538 // Assert that the Smi is at position 0, if at all.
539 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
540 Label next_test;
541 __ CompareImmediate(temp, Immediate(ic_data.GetReceiverClassIdAt(i)), PP);
542 if (i < len - 1) {
543 __ j(NOT_EQUAL, &next_test);
544 } else {
545 __ j(NOT_EQUAL, deopt);
546 }
547 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
548 if (target.Owner() == object_store->object_class()) {
549 // Object.== is same as ===.
550 __ Drop(2);
551 __ cmpq(left, right);
552 if (branch != NULL) {
553 branch->EmitBranchOnCondition(compiler, cond);
554 } else {
555 // This case should be rare.
556 Register result = locs->out().reg();
557 Label load_true;
558 __ j(cond, &load_true, Assembler::kNearJump);
559 __ LoadObject(result, Bool::False(), PP);
560 __ jmp(&done);
561 __ Bind(&load_true);
562 __ LoadObject(result, Bool::True(), PP);
563 }
564 } else {
565 const int kNumberOfArguments = 2;
566 const Array& kNoArgumentNames = Object::null_array();
567 compiler->GenerateStaticCall(deopt_id,
568 token_pos,
569 target,
570 kNumberOfArguments,
571 kNoArgumentNames,
572 locs);
573 if (branch == NULL) {
574 if (kind == Token::kNE) {
575 Label false_label;
576 __ CompareObject(RAX, Bool::True(), PP);
577 __ j(EQUAL, &false_label, Assembler::kNearJump);
578 __ LoadObject(RAX, Bool::True(), PP);
579 __ jmp(&done);
580 __ Bind(&false_label);
581 __ LoadObject(RAX, Bool::False(), PP);
582 }
583 } else {
584 if (branch->is_checked()) {
585 EmitAssertBoolean(RAX, token_pos, deopt_id, locs, compiler);
586 }
587 __ CompareObject(RAX, Bool::True(), PP);
588 branch->EmitBranchOnCondition(compiler, cond);
589 }
590 }
591 if (i < len - 1) {
592 __ jmp(&done);
593 __ Bind(&next_test);
594 }
595 }
596 __ Bind(&done);
597 }
598
599
600 // Emit code when ICData's targets are all Object == (which is ===).
601 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
602 const ICData& orig_ic_data,
603 const LocationSummary& locs,
604 Token::Kind kind,
605 BranchInstr* branch,
606 intptr_t deopt_id) {
607 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
608 Register left = locs.in(0).reg();
609 Register right = locs.in(1).reg();
610 Register temp = locs.temp(0).reg();
611 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
612 __ testq(left, Immediate(kSmiTagMask));
613 __ j(ZERO, deopt);
614 // 'left' is not Smi.
615
616 Label identity_compare;
617 __ CompareObject(right, Object::null_object(), PP);
618 __ j(EQUAL, &identity_compare);
619 __ CompareObject(left, Object::null_object(), PP);
620 __ j(EQUAL, &identity_compare);
621
622 __ LoadClassId(temp, left);
623 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
624 const intptr_t len = ic_data.NumberOfChecks();
625 for (intptr_t i = 0; i < len; i++) {
626 __ CompareImmediate(temp, Immediate(ic_data.GetReceiverClassIdAt(i)), PP);
627 if (i == (len - 1)) {
628 __ j(NOT_EQUAL, deopt);
629 } else {
630 __ j(EQUAL, &identity_compare);
631 }
632 }
633 __ Bind(&identity_compare);
634 __ cmpq(left, right);
635 if (branch == NULL) {
636 Label done, is_equal;
637 Register result = locs.out().reg();
638 __ j(EQUAL, &is_equal, Assembler::kNearJump);
639 // Not equal.
640 __ LoadObject(result, Bool::Get(kind != Token::kEQ), PP);
641 __ jmp(&done, Assembler::kNearJump);
642 __ Bind(&is_equal);
643 __ LoadObject(result, Bool::Get(kind == Token::kEQ), PP);
644 __ Bind(&done);
645 } else {
646 Condition cond = TokenKindToSmiCondition(kind);
647 branch->EmitBranchOnCondition(compiler, cond);
648 }
649 }
650
651
652 // First test if receiver is NULL, in which case === is applied.
653 // If type feedback was provided (lists of <class-id, target>), do a
654 // type by type check (either === or static call to the operator.
655 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
656 LocationSummary* locs,
657 Token::Kind kind,
658 BranchInstr* branch,
659 const ICData& ic_data,
660 intptr_t deopt_id,
661 intptr_t token_pos) {
662 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
663 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0));
664 Register left = locs->in(0).reg();
665 Register right = locs->in(1).reg();
666 __ pushq(left);
667 __ pushq(right);
668 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind,
669 deopt_id, token_pos);
670 }
671
672
673 static Condition FlipCondition(Condition condition) { 434 static Condition FlipCondition(Condition condition) {
674 switch (condition) { 435 switch (condition) {
675 case EQUAL: return EQUAL; 436 case EQUAL: return EQUAL;
676 case NOT_EQUAL: return NOT_EQUAL; 437 case NOT_EQUAL: return NOT_EQUAL;
677 case LESS: return GREATER; 438 case LESS: return GREATER;
678 case LESS_EQUAL: return GREATER_EQUAL; 439 case LESS_EQUAL: return GREATER_EQUAL;
679 case GREATER: return LESS; 440 case GREATER: return LESS;
680 case GREATER_EQUAL: return LESS_EQUAL; 441 case GREATER_EQUAL: return LESS_EQUAL;
681 case BELOW: return ABOVE; 442 case BELOW: return ABOVE;
682 case BELOW_EQUAL: return ABOVE_EQUAL; 443 case BELOW_EQUAL: return ABOVE_EQUAL;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
764 if (operation_cid() == kSmiCid) { 525 if (operation_cid() == kSmiCid) {
765 // Deoptimizes if both arguments not Smi. 526 // Deoptimizes if both arguments not Smi.
766 EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch); 527 EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch);
767 return; 528 return;
768 } 529 }
769 if (operation_cid() == kDoubleCid) { 530 if (operation_cid() == kDoubleCid) {
770 // Deoptimizes if both arguments are Smi, or if none is Double or Smi. 531 // Deoptimizes if both arguments are Smi, or if none is Double or Smi.
771 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); 532 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
772 return; 533 return;
773 } 534 }
774 if (IsCheckedStrictEqual()) { 535 UNREACHABLE();
775 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
776 deopt_id());
777 return;
778 }
779 if (IsPolymorphic()) {
780 EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(),
781 deopt_id(), token_pos());
782 return;
783 }
784 Register left = locs()->in(0).reg();
785 Register right = locs()->in(1).reg();
786 __ pushq(left);
787 __ pushq(right);
788 EmitEqualityAsInstanceCall(compiler,
789 deopt_id(),
790 token_pos(),
791 kind(),
792 locs(),
793 *ic_data());
794 ASSERT(locs()->out().reg() == RAX);
795 } 536 }
796 537
797 538
798 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, 539 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
799 BranchInstr* branch) { 540 BranchInstr* branch) {
800 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); 541 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
801 if (operation_cid() == kSmiCid) { 542 if (operation_cid() == kSmiCid) {
802 // Deoptimizes if both arguments not Smi. 543 // Deoptimizes if both arguments not Smi.
803 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); 544 EmitSmiComparisonOp(compiler, *locs(), kind(), branch);
804 return; 545 return;
805 } 546 }
806 if (operation_cid() == kDoubleCid) { 547 if (operation_cid() == kDoubleCid) {
807 // Deoptimizes if both arguments are Smi, or if none is Double or Smi. 548 // Deoptimizes if both arguments are Smi, or if none is Double or Smi.
808 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); 549 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
809 return; 550 return;
810 } 551 }
811 if (IsCheckedStrictEqual()) { 552 UNREACHABLE();
812 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
813 deopt_id());
814 return;
815 }
816 if (IsPolymorphic()) {
817 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(),
818 deopt_id(), token_pos());
819 return;
820 }
821 Register left = locs()->in(0).reg();
822 Register right = locs()->in(1).reg();
823 __ pushq(left);
824 __ pushq(right);
825 EmitEqualityAsInstanceCall(compiler,
826 deopt_id(),
827 token_pos(),
828 Token::kEQ, // kNE reverse occurs at branch.
829 locs(),
830 *ic_data());
831 if (branch->is_checked()) {
832 EmitAssertBoolean(RAX, token_pos(), deopt_id(), locs(), compiler);
833 }
834 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
835 __ CompareObject(RAX, Bool::True(), PP);
836 branch->EmitBranchOnCondition(compiler, branch_condition);
837 } 553 }
838 554
839 555
840 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { 556 LocationSummary* RelationalOpInstr::MakeLocationSummary() const {
841 const intptr_t kNumInputs = 2; 557 const intptr_t kNumInputs = 2;
842 const intptr_t kNumTemps = 0; 558 const intptr_t kNumTemps = 0;
843 if (operation_cid() == kDoubleCid) { 559 if (operation_cid() == kDoubleCid) {
844 LocationSummary* summary = 560 LocationSummary* summary =
845 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 561 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
846 summary->set_in(0, Location::RequiresFpuRegister()); 562 summary->set_in(0, Location::RequiresFpuRegister());
(...skipping 3960 matching lines...) Expand 10 before | Expand all | Expand 10 after
4807 PcDescriptors::kOther, 4523 PcDescriptors::kOther,
4808 locs()); 4524 locs());
4809 __ Drop(2); // Discard type arguments and receiver. 4525 __ Drop(2); // Discard type arguments and receiver.
4810 } 4526 }
4811 4527
4812 } // namespace dart 4528 } // namespace dart
4813 4529
4814 #undef __ 4530 #undef __
4815 4531
4816 #endif // defined TARGET_ARCH_X64 4532 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language_mips.cc ('k') | runtime/vm/intrinsifier.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698