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/intrinsifier.h" | 8 #include "vm/intrinsifier.h" |
9 | 9 |
10 #include "vm/assembler.h" | 10 #include "vm/assembler.h" |
11 #include "vm/assembler_macros.h" | |
11 #include "vm/instructions.h" | 12 #include "vm/instructions.h" |
12 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
13 | 14 |
14 namespace dart { | 15 namespace dart { |
15 | 16 |
16 DECLARE_FLAG(bool, enable_type_checks); | 17 DECLARE_FLAG(bool, enable_type_checks); |
17 | 18 |
18 // When entering intrinsics code: | 19 // When entering intrinsics code: |
19 // RBX: IC Data | 20 // RBX: IC Data |
20 // R10: Arguments descriptor | 21 // R10: Arguments descriptor |
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
478 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 479 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
479 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 480 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
480 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | 481 __ movq(RCX, Address(RSP, + 2 * kWordSize)); |
481 __ orq(RCX, RAX); | 482 __ orq(RCX, RAX); |
482 __ testq(RCX, Immediate(kSmiTagMask)); | 483 __ testq(RCX, Immediate(kSmiTagMask)); |
483 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); | 484 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); |
484 } | 485 } |
485 | 486 |
486 | 487 |
487 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 488 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
489 Label fall_through; | |
490 TestBothArgumentsSmis(assembler, &fall_through); | |
491 // RAX contains right argument. | |
492 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | |
493 __ addq(RAX, RCX); | |
regis
2012/07/11 22:14:11
Why not a single instruction?
__ addq(RAX, Address
srdjan
2012/07/11 22:27:13
We don't have such an instruction yet.
| |
494 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | |
495 // Result is in RAX. | |
496 __ ret(); | |
497 __ Bind(&fall_through); | |
488 return false; | 498 return false; |
489 } | 499 } |
490 | 500 |
491 | 501 |
492 bool Intrinsifier::Integer_add(Assembler* assembler) { | 502 bool Intrinsifier::Integer_add(Assembler* assembler) { |
493 return false; | 503 return Integer_addFromInteger(assembler); |
494 } | 504 } |
495 | 505 |
496 | 506 |
497 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { | 507 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
498 Label fall_through; | 508 Label fall_through; |
499 TestBothArgumentsSmis(assembler, &fall_through); | 509 TestBothArgumentsSmis(assembler, &fall_through); |
500 // RAX contains right argument, which is the actual minuend of subtraction. | 510 // RAX contains right argument, which is the actual minuend of subtraction. |
501 __ subq(RAX, Address(RSP, + 2 * kWordSize)); | 511 __ subq(RAX, Address(RSP, + 2 * kWordSize)); |
502 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 512 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
503 // Result is in RAX. | 513 // Result is in RAX. |
504 __ ret(); | 514 __ ret(); |
505 __ Bind(&fall_through); | 515 __ Bind(&fall_through); |
506 return false; | 516 return false; |
507 } | 517 } |
508 | 518 |
509 | 519 |
510 bool Intrinsifier::Integer_sub(Assembler* assembler) { | 520 bool Intrinsifier::Integer_sub(Assembler* assembler) { |
521 Label fall_through; | |
522 TestBothArgumentsSmis(assembler, &fall_through); | |
523 // RAX contains right argument, which is the actual subtrahend of subtraction. | |
524 __ movq(RCX, RAX); | |
525 __ movq(RAX, Address(RSP, + 2 * kWordSize)); | |
526 __ subq(RAX, RCX); | |
527 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | |
528 // Result is in RAX. | |
529 __ ret(); | |
530 __ Bind(&fall_through); | |
511 return false; | 531 return false; |
512 } | 532 } |
513 | 533 |
514 | 534 |
515 | 535 |
516 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { | 536 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
537 Label fall_through; | |
538 TestBothArgumentsSmis(assembler, &fall_through); | |
539 // RAX is the right argument. | |
540 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | |
541 __ SmiUntag(RAX); | |
542 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | |
543 __ imulq(RAX, RCX); | |
regis
2012/07/11 22:14:11
Why not a single instruction?
__ imulq(RAX, Addres
srdjan
2012/07/11 22:27:13
ditto.
| |
544 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | |
545 // Result is in RAX. | |
546 __ ret(); | |
547 __ Bind(&fall_through); | |
517 return false; | 548 return false; |
518 } | 549 } |
519 | 550 |
520 | 551 |
521 bool Intrinsifier::Integer_mul(Assembler* assembler) { | 552 bool Intrinsifier::Integer_mul(Assembler* assembler) { |
522 return false; | 553 return Integer_mulFromInteger(assembler); |
523 } | 554 } |
524 | 555 |
525 | 556 |
526 bool Intrinsifier::Integer_modulo(Assembler* assembler) { | 557 bool Intrinsifier::Integer_modulo(Assembler* assembler) { |
527 Label fall_through, return_zero, try_modulo; | 558 Label fall_through, return_zero, try_modulo; |
528 TestBothArgumentsSmis(assembler, &fall_through); | 559 TestBothArgumentsSmis(assembler, &fall_through); |
529 // RAX: right argument (divisor) | 560 // RAX: right argument (divisor) |
530 // Check if modulo by zero -> exception thrown in main function. | 561 // Check if modulo by zero -> exception thrown in main function. |
531 __ cmpq(RAX, Immediate(0)); | 562 __ cmpq(RAX, Immediate(0)); |
532 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 563 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
(...skipping 18 matching lines...) Expand all Loading... | |
551 __ idivq(RCX); | 582 __ idivq(RCX); |
552 __ movq(RAX, RDX); | 583 __ movq(RAX, RDX); |
553 __ SmiTag(RAX); | 584 __ SmiTag(RAX); |
554 __ ret(); | 585 __ ret(); |
555 __ Bind(&fall_through); | 586 __ Bind(&fall_through); |
556 return false; | 587 return false; |
557 } | 588 } |
558 | 589 |
559 | 590 |
560 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 591 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
592 Label fall_through; | |
593 TestBothArgumentsSmis(assembler, &fall_through); | |
594 // RAX: right argument (divisor) | |
595 __ cmpq(RAX, Immediate(0)); | |
596 __ j(EQUAL, &fall_through, Assembler::kNearJump); | |
597 __ movq(RCX, RAX); | |
598 __ SmiUntag(RCX); | |
599 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | |
600 __ SmiUntag(RAX); | |
601 __ pushq(RDX); // Preserve RDX in case of 'fall_through'. | |
602 __ cqo(); | |
603 __ idivq(RCX); | |
604 __ popq(RDX); | |
605 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | |
606 // cannot tag the result. | |
607 __ cmpq(RAX, Immediate(0x4000000000000000)); | |
608 __ j(EQUAL, &fall_through); | |
609 __ SmiTag(RAX); | |
610 __ ret(); | |
611 __ Bind(&fall_through); | |
561 return false; | 612 return false; |
562 } | 613 } |
563 | 614 |
564 | 615 |
565 bool Intrinsifier::Integer_negate(Assembler* assembler) { | 616 bool Intrinsifier::Integer_negate(Assembler* assembler) { |
617 Label fall_through; | |
618 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | |
619 __ testq(RAX, Immediate(kSmiTagMask)); | |
620 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. | |
621 __ negq(RAX); | |
622 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | |
623 // Result is in RAX. | |
624 __ ret(); | |
625 __ Bind(&fall_through); | |
566 return false; | 626 return false; |
567 } | 627 } |
568 | 628 |
569 | 629 |
570 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 630 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
631 Label fall_through; | |
632 TestBothArgumentsSmis(assembler, &fall_through); | |
633 // RAX is the right argument. | |
634 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | |
635 __ andq(RAX, RCX); | |
regis
2012/07/11 22:14:11
Single instruction?
| |
636 // Result is in RAX. | |
637 __ ret(); | |
638 __ Bind(&fall_through); | |
571 return false; | 639 return false; |
572 } | 640 } |
573 | 641 |
574 | 642 |
575 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { | 643 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { |
576 return false; | 644 return Integer_bitAndFromInteger(assembler); |
577 } | 645 } |
578 | 646 |
579 | 647 |
580 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { | 648 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { |
649 Label fall_through; | |
650 TestBothArgumentsSmis(assembler, &fall_through); | |
651 // RAX is the right argument. | |
652 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | |
653 __ orq(RAX, RCX); | |
regis
2012/07/11 22:14:11
Single instruction?
| |
654 // Result is in RAX. | |
655 __ ret(); | |
656 __ Bind(&fall_through); | |
581 return false; | 657 return false; |
582 } | 658 } |
583 | 659 |
584 | 660 |
585 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { | 661 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { |
586 return false; | 662 return Integer_bitOrFromInteger(assembler); |
587 } | 663 } |
588 | 664 |
589 | 665 |
590 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { | 666 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
667 Label fall_through; | |
668 TestBothArgumentsSmis(assembler, &fall_through); | |
669 // RAX is the right argument. | |
670 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | |
671 __ xorq(RAX, RCX); | |
regis
2012/07/11 22:14:11
ditto
| |
672 // Result is in RAX. | |
673 __ ret(); | |
674 __ Bind(&fall_through); | |
591 return false; | 675 return false; |
592 } | 676 } |
593 | 677 |
594 | 678 |
595 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { | 679 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { |
596 return false; | 680 return Integer_bitXorFromInteger(assembler); |
597 } | 681 } |
598 | 682 |
599 | 683 |
600 bool Intrinsifier::Integer_shl(Assembler* assembler) { | 684 bool Intrinsifier::Integer_shl(Assembler* assembler) { |
601 return false; | 685 return false; |
602 } | 686 } |
603 | 687 |
604 | 688 |
605 static bool CompareIntegers(Assembler* assembler, Condition true_condition) { | 689 static bool CompareIntegers(Assembler* assembler, Condition true_condition) { |
606 Label fall_through, true_label; | 690 Label fall_through, true_label; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
645 return CompareIntegers(assembler, GREATER_EQUAL); | 729 return CompareIntegers(assembler, GREATER_EQUAL); |
646 } | 730 } |
647 | 731 |
648 | 732 |
649 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 733 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
650 return false; | 734 return false; |
651 } | 735 } |
652 | 736 |
653 | 737 |
654 bool Intrinsifier::Integer_equal(Assembler* assembler) { | 738 bool Intrinsifier::Integer_equal(Assembler* assembler) { |
655 return false; | 739 return Integer_equalToInteger(assembler); |
656 } | 740 } |
657 | 741 |
658 | 742 |
659 bool Intrinsifier::Integer_sar(Assembler* assembler) { | 743 bool Intrinsifier::Integer_sar(Assembler* assembler) { |
660 return false; | 744 return false; |
661 } | 745 } |
662 | 746 |
663 | 747 |
664 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 748 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
665 return false; | 749 return false; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
741 __ LoadObject(RAX, bool_false); | 825 __ LoadObject(RAX, bool_false); |
742 __ ret(); | 826 __ ret(); |
743 __ Bind(&is_true); | 827 __ Bind(&is_true); |
744 __ LoadObject(RAX, bool_true); | 828 __ LoadObject(RAX, bool_true); |
745 __ ret(); | 829 __ ret(); |
746 return true; // Method is complete, no slow case. | 830 return true; // Method is complete, no slow case. |
747 } | 831 } |
748 | 832 |
749 | 833 |
750 bool Intrinsifier::Double_isNegative(Assembler* assembler) { | 834 bool Intrinsifier::Double_isNegative(Assembler* assembler) { |
751 return false; | 835 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
836 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | |
837 Label is_false, is_true, is_zero; | |
838 __ movq(RAX, Address(RSP, +1 * kWordSize)); | |
839 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | |
840 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. | |
841 __ comisd(XMM0, XMM1); | |
842 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. | |
843 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. | |
844 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. | |
845 __ Bind(&is_true); | |
846 __ LoadObject(RAX, bool_true); | |
847 __ ret(); | |
848 __ Bind(&is_false); | |
849 __ LoadObject(RAX, bool_false); | |
850 __ ret(); | |
851 __ Bind(&is_zero); | |
852 // Check for negative zero (get the sign bit). | |
853 __ movmskpd(RAX, XMM0); | |
854 __ testq(RAX, Immediate(1)); | |
855 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); | |
856 __ jmp(&is_false, Assembler::kNearJump); | |
857 return true; // Method is complete, no slow case. | |
858 } | |
859 | |
860 | |
861 // Check if the last argument is a double, jump to label 'is_smi' if smi | |
862 // (easy to convert to double), otherwise jump to label 'not_double_smi', | |
863 // Returns the last argument in RAX. | |
864 static void TestLastArgumentIsDouble(Assembler* assembler, | |
865 Label* is_smi, | |
866 Label* not_double_smi) { | |
867 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | |
868 __ testq(RAX, Immediate(kSmiTagMask)); | |
869 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. | |
870 __ CompareClassId(RAX, kDouble); | |
871 __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump); | |
872 // Fall through if double. | |
873 } | |
874 | |
875 | |
876 enum TrigonometricFunctions { | |
877 kSine, | |
878 kCosine, | |
879 }; | |
880 | |
881 static void EmitTrigonometric(Assembler* assembler, | |
882 TrigonometricFunctions kind) { | |
883 Label fall_through, is_smi, double_op; | |
884 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | |
885 // Argument is double and is in EAX. | |
886 __ fldl(FieldAddress(RAX, Double::value_offset())); | |
887 __ Bind(&double_op); | |
888 switch (kind) { | |
889 case kSine: __ fsin(); break; | |
890 case kCosine: __ fcos(); break; | |
891 default: | |
892 UNREACHABLE(); | |
893 } | |
894 const Class& double_class = Class::Handle( | |
895 Isolate::Current()->object_store()->double_class()); | |
896 Label alloc_failed; | |
897 AssemblerMacros::TryAllocate(assembler, | |
898 double_class, | |
899 &alloc_failed, | |
900 RAX); // Result register. | |
901 __ fstpl(FieldAddress(RAX, Double::value_offset())); | |
902 __ ret(); | |
903 | |
904 __ Bind(&is_smi); // smi -> double. | |
905 __ SmiUntag(RAX); | |
906 __ pushq(RAX); | |
907 __ fildl(Address(RSP, 0)); | |
908 __ popq(RAX); | |
909 __ jmp(&double_op); | |
910 | |
911 __ Bind(&alloc_failed); | |
912 __ ffree(0); | |
913 __ fincstp(); | |
914 | |
915 __ Bind(&fall_through); | |
752 } | 916 } |
753 | 917 |
754 | 918 |
755 bool Intrinsifier::Math_sqrt(Assembler* assembler) { | 919 bool Intrinsifier::Math_sqrt(Assembler* assembler) { |
920 Label fall_through, is_smi, double_op; | |
921 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | |
922 // Argument is double and is in RAX. | |
923 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | |
924 __ Bind(&double_op); | |
925 __ sqrtsd(XMM0, XMM1); | |
926 const Class& double_class = Class::Handle( | |
927 Isolate::Current()->object_store()->double_class()); | |
928 AssemblerMacros::TryAllocate(assembler, | |
929 double_class, | |
930 &fall_through, | |
931 RAX); // Result register. | |
932 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | |
933 __ ret(); | |
934 __ Bind(&is_smi); | |
935 __ SmiUntag(RAX); | |
936 __ cvtsi2sd(XMM1, RAX); | |
937 __ jmp(&double_op); | |
938 __ Bind(&fall_through); | |
756 return false; | 939 return false; |
757 } | 940 } |
758 | 941 |
759 | 942 |
760 bool Intrinsifier::Math_sin(Assembler* assembler) { | 943 bool Intrinsifier::Math_sin(Assembler* assembler) { |
761 return false; | 944 EmitTrigonometric(assembler, kSine); |
945 return false; // Compile method for slow case. | |
762 } | 946 } |
763 | 947 |
764 | 948 |
765 bool Intrinsifier::Math_cos(Assembler* assembler) { | 949 bool Intrinsifier::Math_cos(Assembler* assembler) { |
766 return false; | 950 EmitTrigonometric(assembler, kCosine); |
767 } | 951 return false; // Compile method for slow case. |
768 | 952 } |
769 | 953 |
954 | |
955 // Identity comparison. | |
770 bool Intrinsifier::Object_equal(Assembler* assembler) { | 956 bool Intrinsifier::Object_equal(Assembler* assembler) { |
771 return false; | 957 Label is_true; |
772 } | 958 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
773 | 959 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
774 | 960 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
961 __ cmpq(RAX, Address(RSP, + 2 * kWordSize)); | |
962 __ j(EQUAL, &is_true, Assembler::kNearJump); | |
963 __ LoadObject(RAX, bool_false); | |
964 __ ret(); | |
965 __ Bind(&is_true); | |
966 __ LoadObject(RAX, bool_true); | |
967 __ ret(); | |
968 return true; | |
969 } | |
970 | |
971 | |
972 static intptr_t GetOffsetForField(const char* class_name_p, | |
973 const char* field_name_p) { | |
974 const String& class_name = String::Handle(String::NewSymbol(class_name_p)); | |
975 const String& field_name = String::Handle(String::NewSymbol(field_name_p)); | |
976 const Class& cls = Class::Handle(Library::Handle( | |
977 Library::CoreImplLibrary()).LookupClass(class_name)); | |
978 ASSERT(!cls.IsNull()); | |
979 const Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name)); | |
980 ASSERT(!field.IsNull()); | |
981 return field.Offset(); | |
982 } | |
983 | |
984 static const char* kFixedSizeArrayIteratorClassName = "FixedSizeArrayIterator"; | |
985 | |
986 // Class 'FixedSizeArrayIterator': | |
987 // T next() { | |
988 // return _array[_pos++]; | |
989 // } | |
990 // Intrinsify: return _array[_pos++]; | |
991 // TODO(srdjan): Throw a 'NoMoreElementsException' exception if the iterator | |
992 // has no more elements. | |
775 bool Intrinsifier::FixedSizeArrayIterator_next(Assembler* assembler) { | 993 bool Intrinsifier::FixedSizeArrayIterator_next(Assembler* assembler) { |
776 return false; | 994 Label fall_through; |
777 } | 995 const intptr_t array_offset = |
778 | 996 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_array"); |
779 | 997 const intptr_t pos_offset = |
998 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); | |
999 ASSERT((array_offset >= 0) && (pos_offset >= 0)); | |
1000 // Receiver is not NULL. | |
1001 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Receiver. | |
1002 __ movq(RCX, FieldAddress(RAX, pos_offset)); // Field _pos. | |
1003 // '_pos' cannot be greater than array length and therefore is always Smi. | |
1004 #if defined(DEBUG) | |
1005 Label pos_ok; | |
1006 __ testq(RCX, Immediate(kSmiTagMask)); | |
1007 __ j(ZERO, &pos_ok, Assembler::kNearJump); | |
1008 __ Stop("pos must be Smi"); | |
1009 __ Bind(&pos_ok); | |
1010 #endif | |
1011 // Check that we are not trying to call 'next' when 'hasNext' is false. | |
1012 __ movq(RAX, FieldAddress(RAX, array_offset)); // Field _array. | |
1013 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); // Range check. | |
1014 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | |
1015 | |
1016 // RCX is Smi, i.e, times 2. | |
1017 ASSERT(kSmiTagShift == 1); | |
1018 __ movq(RDI, FieldAddress(RAX, RCX, TIMES_4, sizeof(RawArray))); // Result. | |
1019 const Immediate value = Immediate(reinterpret_cast<int64_t>(Smi::New(1))); | |
1020 __ addq(RCX, value); // _pos++. | |
1021 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | |
1022 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Receiver. | |
1023 __ StoreIntoObjectNoBarrier(RAX, | |
1024 FieldAddress(RAX, pos_offset), | |
1025 RCX); // Store _pos. | |
1026 __ movq(RAX, RDI); | |
1027 __ ret(); | |
1028 __ Bind(&fall_through); | |
1029 return false; | |
1030 } | |
1031 | |
1032 | |
1033 // Class 'FixedSizeArrayIterator': | |
1034 // bool hasNext() { | |
1035 // return _length > _pos; | |
1036 // } | |
780 bool Intrinsifier::FixedSizeArrayIterator_hasNext(Assembler* assembler) { | 1037 bool Intrinsifier::FixedSizeArrayIterator_hasNext(Assembler* assembler) { |
1038 Label fall_through, is_true; | |
1039 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | |
1040 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | |
1041 const intptr_t length_offset = | |
1042 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_length"); | |
1043 const intptr_t pos_offset = | |
1044 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); | |
1045 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Receiver. | |
1046 __ movq(RCX, FieldAddress(RAX, length_offset)); // Field _length. | |
1047 __ movq(RAX, FieldAddress(RAX, pos_offset)); // Field _pos. | |
1048 __ movq(RDI, RAX); | |
1049 __ orq(RDI, RCX); | |
1050 __ testq(RDI, Immediate(kSmiTagMask)); | |
1051 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi _length/_pos. | |
1052 __ cmpq(RCX, RAX); // _length > _pos. | |
1053 __ j(GREATER, &is_true, Assembler::kNearJump); | |
1054 __ LoadObject(RAX, bool_false); | |
1055 __ ret(); | |
1056 __ Bind(&is_true); | |
1057 __ LoadObject(RAX, bool_true); | |
1058 __ ret(); | |
1059 __ Bind(&fall_through); | |
781 return false; | 1060 return false; |
782 } | 1061 } |
783 | 1062 |
784 | 1063 |
785 bool Intrinsifier::String_getLength(Assembler* assembler) { | 1064 bool Intrinsifier::String_getLength(Assembler* assembler) { |
786 return false; | 1065 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. |
787 } | 1066 __ movq(RAX, FieldAddress(RAX, String::length_offset())); |
788 | 1067 __ ret(); |
789 | 1068 return true; |
1069 } | |
1070 | |
1071 | |
1072 // TODO(srdjan): Implement for two and four byte strings as well. | |
790 bool Intrinsifier::String_charCodeAt(Assembler* assembler) { | 1073 bool Intrinsifier::String_charCodeAt(Assembler* assembler) { |
1074 Label fall_through; | |
1075 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. | |
1076 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // String. | |
1077 __ testq(RCX, Immediate(kSmiTagMask)); | |
1078 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | |
1079 // Range check. | |
1080 __ cmpq(RCX, FieldAddress(RAX, String::length_offset())); | |
1081 // Runtime throws exception. | |
1082 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | |
1083 __ CompareClassId(RAX, kOneByteString); | |
1084 __ j(NOT_EQUAL, &fall_through); | |
1085 __ SmiUntag(RCX); | |
1086 __ movzxb(RAX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); | |
1087 __ SmiTag(RAX); | |
1088 __ ret(); | |
1089 __ Bind(&fall_through); | |
791 return false; | 1090 return false; |
792 } | 1091 } |
793 | 1092 |
794 | 1093 |
795 bool Intrinsifier::String_hashCode(Assembler* assembler) { | 1094 bool Intrinsifier::String_hashCode(Assembler* assembler) { |
1095 Label fall_through; | |
1096 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. | |
1097 __ movq(RAX, FieldAddress(RAX, String::hash_offset())); | |
1098 __ cmpq(RAX, Immediate(0)); | |
1099 __ j(EQUAL, &fall_through, Assembler::kNearJump); | |
1100 __ ret(); | |
1101 __ Bind(&fall_through); | |
1102 // Hash not yet computed. | |
796 return false; | 1103 return false; |
797 } | 1104 } |
798 | 1105 |
799 | 1106 |
800 bool Intrinsifier::String_isEmpty(Assembler* assembler) { | 1107 bool Intrinsifier::String_isEmpty(Assembler* assembler) { |
801 return false; | 1108 Label is_true; |
1109 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | |
1110 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | |
1111 // Get length. | |
1112 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. | |
1113 __ movq(RAX, FieldAddress(RAX, String::length_offset())); | |
1114 __ cmpq(RAX, Immediate(Smi::RawValue(0))); | |
1115 __ j(EQUAL, &is_true, Assembler::kNearJump); | |
1116 __ LoadObject(RAX, bool_false); | |
1117 __ ret(); | |
1118 __ Bind(&is_true); | |
1119 __ LoadObject(RAX, bool_true); | |
1120 __ ret(); | |
1121 return true; | |
802 } | 1122 } |
803 | 1123 |
804 #undef __ | 1124 #undef __ |
805 | 1125 |
806 } // namespace dart | 1126 } // namespace dart |
807 | 1127 |
808 #endif // defined TARGET_ARCH_X64 | 1128 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |