| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |