| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 | 210 |
| 211 | 211 |
| 212 static void EmitAssertBoolean(Register reg, | 212 static void EmitAssertBoolean(Register reg, |
| 213 intptr_t token_pos, | 213 intptr_t token_pos, |
| 214 LocationSummary* locs, | 214 LocationSummary* locs, |
| 215 FlowGraphCompiler* compiler) { | 215 FlowGraphCompiler* compiler) { |
| 216 // Check that the type of the value is allowed in conditional context. | 216 // Check that the type of the value is allowed in conditional context. |
| 217 // Call the runtime if the object is not bool::true or bool::false. | 217 // Call the runtime if the object is not bool::true or bool::false. |
| 218 ASSERT(locs->always_calls()); | 218 ASSERT(locs->always_calls()); |
| 219 Label done; | 219 Label done; |
| 220 __ CompareObject(reg, compiler->bool_true()); | 220 __ CompareObject(reg, Bool::True()); |
| 221 __ j(EQUAL, &done, Assembler::kNearJump); | 221 __ j(EQUAL, &done, Assembler::kNearJump); |
| 222 __ CompareObject(reg, compiler->bool_false()); | 222 __ CompareObject(reg, Bool::False()); |
| 223 __ j(EQUAL, &done, Assembler::kNearJump); | 223 __ j(EQUAL, &done, Assembler::kNearJump); |
| 224 | 224 |
| 225 __ pushq(reg); // Push the source object. | 225 __ pushq(reg); // Push the source object. |
| 226 compiler->GenerateCallRuntime(token_pos, | 226 compiler->GenerateCallRuntime(token_pos, |
| 227 kConditionTypeErrorRuntimeEntry, | 227 kConditionTypeErrorRuntimeEntry, |
| 228 locs); | 228 locs); |
| 229 // We should never return here. | 229 // We should never return here. |
| 230 __ int3(); | 230 __ int3(); |
| 231 __ Bind(&done); | 231 __ Bind(&done); |
| 232 } | 232 } |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 | 393 |
| 394 __ Bind(&check_identity); | 394 __ Bind(&check_identity); |
| 395 Label equality_done; | 395 Label equality_done; |
| 396 if (compiler->is_optimizing()) { | 396 if (compiler->is_optimizing()) { |
| 397 // No need to update IC data. | 397 // No need to update IC data. |
| 398 Label is_true; | 398 Label is_true; |
| 399 __ popq(RAX); | 399 __ popq(RAX); |
| 400 __ popq(RDX); | 400 __ popq(RDX); |
| 401 __ cmpq(RAX, RDX); | 401 __ cmpq(RAX, RDX); |
| 402 __ j(EQUAL, &is_true); | 402 __ j(EQUAL, &is_true); |
| 403 __ LoadObject(RAX, (kind == Token::kEQ) ? compiler->bool_false() | 403 __ LoadObject(RAX, (kind == Token::kEQ) ? Bool::False() : Bool::True()); |
| 404 : compiler->bool_true()); | |
| 405 __ jmp(&equality_done); | 404 __ jmp(&equality_done); |
| 406 __ Bind(&is_true); | 405 __ Bind(&is_true); |
| 407 __ LoadObject(RAX, (kind == Token::kEQ) ? compiler->bool_true() | 406 __ LoadObject(RAX, (kind == Token::kEQ) ? Bool::True() : Bool::False()); |
| 408 : compiler->bool_false()); | |
| 409 if (kind == Token::kNE) { | 407 if (kind == Token::kNE) { |
| 410 // Skip not-equal result conversion. | 408 // Skip not-equal result conversion. |
| 411 __ jmp(&equality_done); | 409 __ jmp(&equality_done); |
| 412 } | 410 } |
| 413 } else { | 411 } else { |
| 414 // Call stub, load IC data in register. The stub will update ICData if | 412 // Call stub, load IC data in register. The stub will update ICData if |
| 415 // necessary. | 413 // necessary. |
| 416 Register ic_data_reg = locs->temp(0).reg(); | 414 Register ic_data_reg = locs->temp(0).reg(); |
| 417 ASSERT(ic_data_reg == RBX); // Stub depends on it. | 415 ASSERT(ic_data_reg == RBX); // Stub depends on it. |
| 418 __ LoadObject(ic_data_reg, equality_ic_data); | 416 __ LoadObject(ic_data_reg, equality_ic_data); |
| 419 compiler->GenerateCall(token_pos, | 417 compiler->GenerateCall(token_pos, |
| 420 &StubCode::EqualityWithNullArgLabel(), | 418 &StubCode::EqualityWithNullArgLabel(), |
| 421 PcDescriptors::kOther, | 419 PcDescriptors::kOther, |
| 422 locs); | 420 locs); |
| 423 __ Drop(2); | 421 __ Drop(2); |
| 424 } | 422 } |
| 425 __ Bind(&check_ne); | 423 __ Bind(&check_ne); |
| 426 if (kind == Token::kNE) { | 424 if (kind == Token::kNE) { |
| 427 Label false_label, true_label, done; | 425 Label false_label, true_label, done; |
| 428 // Negate the condition: true label returns false and vice versa. | 426 // Negate the condition: true label returns false and vice versa. |
| 429 __ CompareObject(RAX, compiler->bool_true()); | 427 __ CompareObject(RAX, Bool::True()); |
| 430 __ j(EQUAL, &true_label, Assembler::kNearJump); | 428 __ j(EQUAL, &true_label, Assembler::kNearJump); |
| 431 __ Bind(&false_label); | 429 __ Bind(&false_label); |
| 432 __ LoadObject(RAX, compiler->bool_true()); | 430 __ LoadObject(RAX, Bool::True()); |
| 433 __ jmp(&done, Assembler::kNearJump); | 431 __ jmp(&done, Assembler::kNearJump); |
| 434 __ Bind(&true_label); | 432 __ Bind(&true_label); |
| 435 __ LoadObject(RAX, compiler->bool_false()); | 433 __ LoadObject(RAX, Bool::False()); |
| 436 __ Bind(&done); | 434 __ Bind(&done); |
| 437 } | 435 } |
| 438 __ Bind(&equality_done); | 436 __ Bind(&equality_done); |
| 439 } | 437 } |
| 440 | 438 |
| 441 | 439 |
| 442 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | 440 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
| 443 const ICData& orig_ic_data, | 441 const ICData& orig_ic_data, |
| 444 LocationSummary* locs, | 442 LocationSummary* locs, |
| 445 BranchInstr* branch, | 443 BranchInstr* branch, |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 // Object.== is same as ===. | 481 // Object.== is same as ===. |
| 484 __ Drop(2); | 482 __ Drop(2); |
| 485 __ cmpq(left, right); | 483 __ cmpq(left, right); |
| 486 if (branch != NULL) { | 484 if (branch != NULL) { |
| 487 branch->EmitBranchOnCondition(compiler, cond); | 485 branch->EmitBranchOnCondition(compiler, cond); |
| 488 } else { | 486 } else { |
| 489 // This case should be rare. | 487 // This case should be rare. |
| 490 Register result = locs->out().reg(); | 488 Register result = locs->out().reg(); |
| 491 Label load_true; | 489 Label load_true; |
| 492 __ j(cond, &load_true, Assembler::kNearJump); | 490 __ j(cond, &load_true, Assembler::kNearJump); |
| 493 __ LoadObject(result, compiler->bool_false()); | 491 __ LoadObject(result, Bool::False()); |
| 494 __ jmp(&done); | 492 __ jmp(&done); |
| 495 __ Bind(&load_true); | 493 __ Bind(&load_true); |
| 496 __ LoadObject(result, compiler->bool_true()); | 494 __ LoadObject(result, Bool::True()); |
| 497 } | 495 } |
| 498 } else { | 496 } else { |
| 499 const int kNumberOfArguments = 2; | 497 const int kNumberOfArguments = 2; |
| 500 const Array& kNoArgumentNames = Array::Handle(); | 498 const Array& kNoArgumentNames = Array::Handle(); |
| 501 compiler->GenerateStaticCall(deopt_id, | 499 compiler->GenerateStaticCall(deopt_id, |
| 502 token_pos, | 500 token_pos, |
| 503 target, | 501 target, |
| 504 kNumberOfArguments, | 502 kNumberOfArguments, |
| 505 kNoArgumentNames, | 503 kNoArgumentNames, |
| 506 locs); | 504 locs); |
| 507 if (branch == NULL) { | 505 if (branch == NULL) { |
| 508 if (kind == Token::kNE) { | 506 if (kind == Token::kNE) { |
| 509 Label false_label; | 507 Label false_label; |
| 510 __ CompareObject(RAX, compiler->bool_true()); | 508 __ CompareObject(RAX, Bool::True()); |
| 511 __ j(EQUAL, &false_label, Assembler::kNearJump); | 509 __ j(EQUAL, &false_label, Assembler::kNearJump); |
| 512 __ LoadObject(RAX, compiler->bool_true()); | 510 __ LoadObject(RAX, Bool::True()); |
| 513 __ jmp(&done); | 511 __ jmp(&done); |
| 514 __ Bind(&false_label); | 512 __ Bind(&false_label); |
| 515 __ LoadObject(RAX, compiler->bool_false()); | 513 __ LoadObject(RAX, Bool::False()); |
| 516 __ jmp(&done); | 514 __ jmp(&done); |
| 517 } | 515 } |
| 518 } else { | 516 } else { |
| 519 if (branch->is_checked()) { | 517 if (branch->is_checked()) { |
| 520 EmitAssertBoolean(RAX, token_pos, locs, compiler); | 518 EmitAssertBoolean(RAX, token_pos, locs, compiler); |
| 521 } | 519 } |
| 522 __ CompareObject(RAX, compiler->bool_true()); | 520 __ CompareObject(RAX, Bool::True()); |
| 523 branch->EmitBranchOnCondition(compiler, cond); | 521 branch->EmitBranchOnCondition(compiler, cond); |
| 524 } | 522 } |
| 525 } | 523 } |
| 526 __ jmp(&done); | 524 __ jmp(&done); |
| 527 __ Bind(&next_test); | 525 __ Bind(&next_test); |
| 528 } | 526 } |
| 529 // Fall through leads to deoptimization | 527 // Fall through leads to deoptimization |
| 530 __ jmp(deopt); | 528 __ jmp(deopt); |
| 531 __ Bind(&done); | 529 __ Bind(&done); |
| 532 } | 530 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 __ j(EQUAL, &identity_compare); | 563 __ j(EQUAL, &identity_compare); |
| 566 } | 564 } |
| 567 } | 565 } |
| 568 __ Bind(&identity_compare); | 566 __ Bind(&identity_compare); |
| 569 __ cmpq(left, right); | 567 __ cmpq(left, right); |
| 570 if (branch == NULL) { | 568 if (branch == NULL) { |
| 571 Label done, is_equal; | 569 Label done, is_equal; |
| 572 Register result = locs.out().reg(); | 570 Register result = locs.out().reg(); |
| 573 __ j(EQUAL, &is_equal, Assembler::kNearJump); | 571 __ j(EQUAL, &is_equal, Assembler::kNearJump); |
| 574 // Not equal. | 572 // Not equal. |
| 575 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_false() | 573 __ LoadObject(result, (kind == Token::kEQ) ? Bool::False() : Bool::True()); |
| 576 : compiler->bool_true()); | |
| 577 __ jmp(&done, Assembler::kNearJump); | 574 __ jmp(&done, Assembler::kNearJump); |
| 578 __ Bind(&is_equal); | 575 __ Bind(&is_equal); |
| 579 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_true() | 576 __ LoadObject(result, (kind == Token::kEQ) ? Bool::True() : Bool::False()); |
| 580 : compiler->bool_false()); | |
| 581 __ Bind(&done); | 577 __ Bind(&done); |
| 582 } else { | 578 } else { |
| 583 Condition cond = TokenKindToSmiCondition(kind); | 579 Condition cond = TokenKindToSmiCondition(kind); |
| 584 branch->EmitBranchOnCondition(compiler, cond); | 580 branch->EmitBranchOnCondition(compiler, cond); |
| 585 } | 581 } |
| 586 } | 582 } |
| 587 | 583 |
| 588 | 584 |
| 589 // First test if receiver is NULL, in which case === is applied. | 585 // First test if receiver is NULL, in which case === is applied. |
| 590 // If type feedback was provided (lists of <class-id, target>), do a | 586 // If type feedback was provided (lists of <class-id, target>), do a |
| (...skipping 19 matching lines...) Expand all Loading... |
| 610 // Comparison with NULL is "===". | 606 // Comparison with NULL is "===". |
| 611 __ Bind(&identity_compare); | 607 __ Bind(&identity_compare); |
| 612 __ cmpq(left, right); | 608 __ cmpq(left, right); |
| 613 Condition cond = TokenKindToSmiCondition(kind); | 609 Condition cond = TokenKindToSmiCondition(kind); |
| 614 if (branch != NULL) { | 610 if (branch != NULL) { |
| 615 branch->EmitBranchOnCondition(compiler, cond); | 611 branch->EmitBranchOnCondition(compiler, cond); |
| 616 } else { | 612 } else { |
| 617 Register result = locs->out().reg(); | 613 Register result = locs->out().reg(); |
| 618 Label load_true; | 614 Label load_true; |
| 619 __ j(cond, &load_true, Assembler::kNearJump); | 615 __ j(cond, &load_true, Assembler::kNearJump); |
| 620 __ LoadObject(result, compiler->bool_false()); | 616 __ LoadObject(result, Bool::False()); |
| 621 __ jmp(&done); | 617 __ jmp(&done); |
| 622 __ Bind(&load_true); | 618 __ Bind(&load_true); |
| 623 __ LoadObject(result, compiler->bool_true()); | 619 __ LoadObject(result, Bool::True()); |
| 624 } | 620 } |
| 625 __ jmp(&done); | 621 __ jmp(&done); |
| 626 __ Bind(&non_null_compare); // Receiver is not null. | 622 __ Bind(&non_null_compare); // Receiver is not null. |
| 627 __ pushq(left); | 623 __ pushq(left); |
| 628 __ pushq(right); | 624 __ pushq(right); |
| 629 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, | 625 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, |
| 630 deopt_id, token_pos); | 626 deopt_id, token_pos); |
| 631 __ Bind(&done); | 627 __ Bind(&done); |
| 632 } | 628 } |
| 633 | 629 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 650 } else { | 646 } else { |
| 651 __ cmpq(left.reg(), right.reg()); | 647 __ cmpq(left.reg(), right.reg()); |
| 652 } | 648 } |
| 653 | 649 |
| 654 if (branch != NULL) { | 650 if (branch != NULL) { |
| 655 branch->EmitBranchOnCondition(compiler, true_condition); | 651 branch->EmitBranchOnCondition(compiler, true_condition); |
| 656 } else { | 652 } else { |
| 657 Register result = locs.out().reg(); | 653 Register result = locs.out().reg(); |
| 658 Label done, is_true; | 654 Label done, is_true; |
| 659 __ j(true_condition, &is_true); | 655 __ j(true_condition, &is_true); |
| 660 __ LoadObject(result, compiler->bool_false()); | 656 __ LoadObject(result, Bool::False()); |
| 661 __ jmp(&done); | 657 __ jmp(&done); |
| 662 __ Bind(&is_true); | 658 __ Bind(&is_true); |
| 663 __ LoadObject(result, compiler->bool_true()); | 659 __ LoadObject(result, Bool::True()); |
| 664 __ Bind(&done); | 660 __ Bind(&done); |
| 665 } | 661 } |
| 666 } | 662 } |
| 667 | 663 |
| 668 | 664 |
| 669 static Condition TokenKindToDoubleCondition(Token::Kind kind) { | 665 static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| 670 switch (kind) { | 666 switch (kind) { |
| 671 case Token::kEQ: return EQUAL; | 667 case Token::kEQ: return EQUAL; |
| 672 case Token::kNE: return NOT_EQUAL; | 668 case Token::kNE: return NOT_EQUAL; |
| 673 case Token::kLT: return BELOW; | 669 case Token::kLT: return BELOW; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 EmitEqualityAsInstanceCall(compiler, | 766 EmitEqualityAsInstanceCall(compiler, |
| 771 deopt_id(), | 767 deopt_id(), |
| 772 token_pos(), | 768 token_pos(), |
| 773 Token::kEQ, // kNE reverse occurs at branch. | 769 Token::kEQ, // kNE reverse occurs at branch. |
| 774 locs(), | 770 locs(), |
| 775 *ic_data()); | 771 *ic_data()); |
| 776 if (branch->is_checked()) { | 772 if (branch->is_checked()) { |
| 777 EmitAssertBoolean(RAX, token_pos(), locs(), compiler); | 773 EmitAssertBoolean(RAX, token_pos(), locs(), compiler); |
| 778 } | 774 } |
| 779 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; | 775 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; |
| 780 __ CompareObject(RAX, compiler->bool_true()); | 776 __ CompareObject(RAX, Bool::True()); |
| 781 branch->EmitBranchOnCondition(compiler, branch_condition); | 777 branch->EmitBranchOnCondition(compiler, branch_condition); |
| 782 } | 778 } |
| 783 | 779 |
| 784 | 780 |
| 785 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { | 781 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { |
| 786 const intptr_t kNumInputs = 2; | 782 const intptr_t kNumInputs = 2; |
| 787 const intptr_t kNumTemps = 0; | 783 const intptr_t kNumTemps = 0; |
| 788 if (operands_class_id() == kDoubleCid) { | 784 if (operands_class_id() == kDoubleCid) { |
| 789 LocationSummary* summary = | 785 LocationSummary* summary = |
| 790 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 786 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 BranchInstr* branch) { | 888 BranchInstr* branch) { |
| 893 if (operands_class_id() == kSmiCid) { | 889 if (operands_class_id() == kSmiCid) { |
| 894 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); | 890 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); |
| 895 return; | 891 return; |
| 896 } | 892 } |
| 897 if (operands_class_id() == kDoubleCid) { | 893 if (operands_class_id() == kDoubleCid) { |
| 898 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); | 894 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); |
| 899 return; | 895 return; |
| 900 } | 896 } |
| 901 EmitNativeCode(compiler); | 897 EmitNativeCode(compiler); |
| 902 __ CompareObject(RAX, compiler->bool_true()); | 898 __ CompareObject(RAX, Bool::True()); |
| 903 branch->EmitBranchOnCondition(compiler, EQUAL); | 899 branch->EmitBranchOnCondition(compiler, EQUAL); |
| 904 } | 900 } |
| 905 | 901 |
| 906 | 902 |
| 907 LocationSummary* NativeCallInstr::MakeLocationSummary() const { | 903 LocationSummary* NativeCallInstr::MakeLocationSummary() const { |
| 908 const intptr_t kNumInputs = 0; | 904 const intptr_t kNumInputs = 0; |
| 909 const intptr_t kNumTemps = 3; | 905 const intptr_t kNumTemps = 3; |
| 910 LocationSummary* locs = | 906 LocationSummary* locs = |
| 911 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 907 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 912 locs->set_temp(0, Location::RegisterLocation(RAX)); | 908 locs->set_temp(0, Location::RegisterLocation(RAX)); |
| (...skipping 1551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2464 | 2460 |
| 2465 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2461 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2466 UNIMPLEMENTED(); | 2462 UNIMPLEMENTED(); |
| 2467 } | 2463 } |
| 2468 | 2464 |
| 2469 } // namespace dart | 2465 } // namespace dart |
| 2470 | 2466 |
| 2471 #undef __ | 2467 #undef __ |
| 2472 | 2468 |
| 2473 #endif // defined TARGET_ARCH_X64 | 2469 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |