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 |