OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), | 616 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), |
617 masm->isolate()), | 617 masm->isolate()), |
618 2, | 618 2, |
619 1); | 619 1); |
620 | 620 |
621 __ bind(&slow); | 621 __ bind(&slow); |
622 GenerateMiss(masm, false); | 622 GenerateMiss(masm, false); |
623 } | 623 } |
624 | 624 |
625 | 625 |
626 static void KeyedStoreGenerateGenericHelper( | |
627 MacroAssembler* masm, | |
628 Label* fast_object, | |
629 Label* fast_double, | |
630 Label* slow, | |
631 KeyedStoreCheckMap check_map, | |
632 KeyedStoreIncrementLength increment_length) { | |
633 Label transition_smi_elements; | |
634 Label finish_object_store, non_double_value, transition_double_elements; | |
635 Label fast_double_without_map_check; | |
636 // Fast case: Do the store, could be either Object or double. | |
637 __ bind(fast_object); | |
638 // rax: value | |
639 // rbx: receiver's elements array (a FixedArray) | |
640 // rcx: index | |
641 // rdx: receiver (a JSArray) | |
642 // r9: map of receiver | |
643 if (check_map == kCheckMap) { | |
644 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); | |
645 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); | |
646 __ j(not_equal, fast_double); | |
647 } | |
648 // Smi stores don't require further checks. | |
649 Label non_smi_value; | |
650 __ JumpIfNotSmi(rax, &non_smi_value); | |
651 if (increment_length == kIncrementLength) { | |
652 // Add 1 to receiver->length. | |
653 __ leal(rdi, Operand(rcx, 1)); | |
654 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); | |
655 } | |
656 // It's irrelevant whether array is smi-only or not when writing a smi. | |
657 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), | |
658 rax); | |
659 __ ret(0); | |
660 | |
661 __ bind(&non_smi_value); | |
662 // Writing a non-smi, check whether array allows non-smi elements. | |
663 // r9: receiver's map | |
664 __ CheckFastObjectElements(r9, &transition_smi_elements); | |
665 | |
666 __ bind(&finish_object_store); | |
667 if (increment_length == kIncrementLength) { | |
668 // Add 1 to receiver->length. | |
669 __ leal(rdi, Operand(rcx, 1)); | |
670 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); | |
671 } | |
672 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), | |
673 rax); | |
674 __ movq(rdx, rax); // Preserve the value which is returned. | |
675 __ RecordWriteArray( | |
676 rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | |
677 __ ret(0); | |
678 | |
679 __ bind(fast_double); | |
680 if (check_map == kCheckMap) { | |
681 // Check for fast double array case. If this fails, call through to the | |
682 // runtime. | |
683 // rdi: elements array's map | |
684 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); | |
685 __ j(not_equal, slow); | |
686 } | |
687 __ bind(&fast_double_without_map_check); | |
688 __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0, | |
689 &transition_double_elements); | |
690 if (increment_length == kIncrementLength) { | |
691 // Add 1 to receiver->length. | |
692 __ leal(rdi, Operand(rcx, 1)); | |
693 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); | |
694 } | |
695 __ ret(0); | |
696 | |
697 __ bind(&transition_smi_elements); | |
698 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | |
699 | |
700 // Transition the array appropriately depending on the value type. | |
701 __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset)); | |
702 __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex); | |
703 __ j(not_equal, &non_double_value); | |
704 | |
705 // Value is a double. Transition FAST_SMI_ELEMENTS -> | |
706 // FAST_DOUBLE_ELEMENTS and complete the store. | |
707 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | |
708 FAST_DOUBLE_ELEMENTS, | |
709 rbx, | |
710 rdi, | |
711 slow); | |
712 ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow); | |
713 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
714 __ jmp(&fast_double_without_map_check); | |
715 | |
716 __ bind(&non_double_value); | |
717 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS | |
718 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | |
719 FAST_ELEMENTS, | |
720 rbx, | |
721 rdi, | |
722 slow); | |
723 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); | |
724 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
725 __ jmp(&finish_object_store); | |
726 | |
727 __ bind(&transition_double_elements); | |
728 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a | |
729 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and | |
730 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS | |
731 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | |
732 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, | |
733 FAST_ELEMENTS, | |
734 rbx, | |
735 rdi, | |
736 slow); | |
737 ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow); | |
738 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
739 __ jmp(&finish_object_store); | |
740 } | |
741 | |
742 | |
743 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, | 626 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, |
744 StrictModeFlag strict_mode) { | 627 StrictModeFlag strict_mode) { |
745 // ----------- S t a t e ------------- | 628 // ----------- S t a t e ------------- |
746 // -- rax : value | 629 // -- rax : value |
747 // -- rcx : key | 630 // -- rcx : key |
748 // -- rdx : receiver | 631 // -- rdx : receiver |
749 // -- rsp[0] : return address | 632 // -- rsp[0] : return address |
750 // ----------------------------------- | 633 // ----------------------------------- |
751 Label slow, slow_with_tagged_index, fast_object, fast_object_grow; | 634 Label slow, slow_with_tagged_index, fast, array, extra, check_extra_double; |
752 Label fast_double, fast_double_grow; | 635 Label fast_object_with_map_check, fast_object_without_map_check; |
753 Label array, extra, check_if_double_array; | 636 Label fast_double_with_map_check, fast_double_without_map_check; |
| 637 Label transition_smi_elements, finish_object_store, non_double_value; |
| 638 Label transition_double_elements; |
754 | 639 |
755 // Check that the object isn't a smi. | 640 // Check that the object isn't a smi. |
756 __ JumpIfSmi(rdx, &slow_with_tagged_index); | 641 __ JumpIfSmi(rdx, &slow_with_tagged_index); |
757 // Get the map from the receiver. | 642 // Get the map from the receiver. |
758 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | 643 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
759 // Check that the receiver does not require access checks. We need | 644 // Check that the receiver does not require access checks. We need |
760 // to do this because this generic stub does not perform map checks. | 645 // to do this because this generic stub does not perform map checks. |
761 __ testb(FieldOperand(r9, Map::kBitFieldOffset), | 646 __ testb(FieldOperand(r9, Map::kBitFieldOffset), |
762 Immediate(1 << Map::kIsAccessCheckNeeded)); | 647 Immediate(1 << Map::kIsAccessCheckNeeded)); |
763 __ j(not_zero, &slow_with_tagged_index); | 648 __ j(not_zero, &slow_with_tagged_index); |
(...skipping 10 matching lines...) Expand all Loading... |
774 // Object case: Check key against length in the elements array. | 659 // Object case: Check key against length in the elements array. |
775 // rax: value | 660 // rax: value |
776 // rdx: JSObject | 661 // rdx: JSObject |
777 // rcx: index | 662 // rcx: index |
778 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | 663 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
779 // Check array bounds. | 664 // Check array bounds. |
780 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx); | 665 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx); |
781 // rax: value | 666 // rax: value |
782 // rbx: FixedArray | 667 // rbx: FixedArray |
783 // rcx: index | 668 // rcx: index |
784 __ j(above, &fast_object); | 669 __ j(above, &fast_object_with_map_check); |
785 | 670 |
786 // Slow case: call runtime. | 671 // Slow case: call runtime. |
787 __ bind(&slow); | 672 __ bind(&slow); |
788 __ Integer32ToSmi(rcx, rcx); | 673 __ Integer32ToSmi(rcx, rcx); |
789 __ bind(&slow_with_tagged_index); | 674 __ bind(&slow_with_tagged_index); |
790 GenerateRuntimeSetProperty(masm, strict_mode); | 675 GenerateRuntimeSetProperty(masm, strict_mode); |
791 // Never returns to here. | 676 // Never returns to here. |
792 | 677 |
793 // Extra capacity case: Check if there is extra capacity to | 678 // Extra capacity case: Check if there is extra capacity to |
794 // perform the store and update the length. Used for adding one | 679 // perform the store and update the length. Used for adding one |
795 // element to the array by writing to array[array.length]. | 680 // element to the array by writing to array[array.length]. |
796 __ bind(&extra); | 681 __ bind(&extra); |
797 // rax: value | 682 // rax: value |
798 // rdx: receiver (a JSArray) | 683 // rdx: receiver (a JSArray) |
799 // rbx: receiver's elements array (a FixedArray) | 684 // rbx: receiver's elements array (a FixedArray) |
800 // rcx: index | 685 // rcx: index |
801 // flags: smicompare (rdx.length(), rbx) | 686 // flags: smicompare (rdx.length(), rbx) |
802 __ j(not_equal, &slow); // do not leave holes in the array | 687 __ j(not_equal, &slow); // do not leave holes in the array |
803 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx); | 688 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx); |
804 __ j(below_equal, &slow); | 689 __ j(below_equal, &slow); |
805 // Increment index to get new length. | 690 // Increment index to get new length. |
806 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); | 691 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); |
807 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); | 692 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); |
808 __ j(not_equal, &check_if_double_array); | 693 __ j(not_equal, &check_extra_double); |
809 __ jmp(&fast_object_grow); | 694 __ leal(rdi, Operand(rcx, 1)); |
| 695 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); |
| 696 __ jmp(&fast_object_without_map_check); |
810 | 697 |
811 __ bind(&check_if_double_array); | 698 __ bind(&check_extra_double); |
812 // rdi: elements array's map | 699 // rdi: elements array's map |
813 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); | 700 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); |
814 __ j(not_equal, &slow); | 701 __ j(not_equal, &slow); |
815 __ jmp(&fast_double_grow); | 702 __ leal(rdi, Operand(rcx, 1)); |
| 703 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); |
| 704 __ jmp(&fast_double_without_map_check); |
816 | 705 |
817 // Array case: Get the length and the elements array from the JS | 706 // Array case: Get the length and the elements array from the JS |
818 // array. Check that the array is in fast mode (and writable); if it | 707 // array. Check that the array is in fast mode (and writable); if it |
819 // is the length is always a smi. | 708 // is the length is always a smi. |
820 __ bind(&array); | 709 __ bind(&array); |
821 // rax: value | 710 // rax: value |
822 // rdx: receiver (a JSArray) | 711 // rdx: receiver (a JSArray) |
823 // rcx: index | 712 // rcx: index |
824 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | 713 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
825 | 714 |
826 // Check the key against the length in the array, compute the | 715 // Check the key against the length in the array, compute the |
827 // address to store into and fall through to fast case. | 716 // address to store into and fall through to fast case. |
828 __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx); | 717 __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx); |
829 __ j(below_equal, &extra); | 718 __ j(below_equal, &extra); |
830 | 719 |
831 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, | 720 // Fast case: Do the store. |
832 &slow, kCheckMap, kDontIncrementLength); | 721 __ bind(&fast_object_with_map_check); |
833 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, | 722 // rax: value |
834 &slow, kDontCheckMap, kIncrementLength); | 723 // rbx: receiver's elements array (a FixedArray) |
| 724 // rcx: index |
| 725 // rdx: receiver (a JSArray) |
| 726 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); |
| 727 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); |
| 728 __ j(not_equal, &fast_double_with_map_check); |
| 729 __ bind(&fast_object_without_map_check); |
| 730 // Smi stores don't require further checks. |
| 731 Label non_smi_value; |
| 732 __ JumpIfNotSmi(rax, &non_smi_value); |
| 733 // It's irrelevant whether array is smi-only or not when writing a smi. |
| 734 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), |
| 735 rax); |
| 736 __ ret(0); |
| 737 |
| 738 __ bind(&non_smi_value); |
| 739 // Writing a non-smi, check whether array allows non-smi elements. |
| 740 // r9: receiver's map |
| 741 __ CheckFastObjectElements(r9, &transition_smi_elements); |
| 742 __ bind(&finish_object_store); |
| 743 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), |
| 744 rax); |
| 745 __ movq(rdx, rax); // Preserve the value which is returned. |
| 746 __ RecordWriteArray( |
| 747 rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 748 __ ret(0); |
| 749 |
| 750 __ bind(&fast_double_with_map_check); |
| 751 // Check for fast double array case. If this fails, call through to the |
| 752 // runtime. |
| 753 // rdi: elements array's map |
| 754 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); |
| 755 __ j(not_equal, &slow); |
| 756 __ bind(&fast_double_without_map_check); |
| 757 // If the value is a number, store it as a double in the FastDoubleElements |
| 758 // array. |
| 759 __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0, |
| 760 &transition_double_elements); |
| 761 __ ret(0); |
| 762 |
| 763 __ bind(&transition_smi_elements); |
| 764 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 765 |
| 766 // Transition the array appropriately depending on the value type. |
| 767 __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset)); |
| 768 __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex); |
| 769 __ j(not_equal, &non_double_value); |
| 770 |
| 771 // Value is a double. Transition FAST_SMI_ELEMENTS -> |
| 772 // FAST_DOUBLE_ELEMENTS and complete the store. |
| 773 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, |
| 774 FAST_DOUBLE_ELEMENTS, |
| 775 rbx, |
| 776 rdi, |
| 777 &slow); |
| 778 ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow); |
| 779 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 780 __ jmp(&fast_double_without_map_check); |
| 781 |
| 782 __ bind(&non_double_value); |
| 783 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS |
| 784 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, |
| 785 FAST_ELEMENTS, |
| 786 rbx, |
| 787 rdi, |
| 788 &slow); |
| 789 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); |
| 790 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 791 __ jmp(&finish_object_store); |
| 792 |
| 793 __ bind(&transition_double_elements); |
| 794 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a |
| 795 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and |
| 796 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS |
| 797 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 798 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, |
| 799 FAST_ELEMENTS, |
| 800 rbx, |
| 801 rdi, |
| 802 &slow); |
| 803 ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow); |
| 804 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 805 __ jmp(&finish_object_store); |
835 } | 806 } |
836 | 807 |
837 | 808 |
838 // The generated code does not accept smi keys. | 809 // The generated code does not accept smi keys. |
839 // The generated code falls through if both probes miss. | 810 // The generated code falls through if both probes miss. |
840 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, | 811 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, |
841 int argc, | 812 int argc, |
842 Code::Kind kind, | 813 Code::Kind kind, |
843 Code::ExtraICState extra_state) { | 814 Code::ExtraICState extra_state) { |
844 // ----------- S t a t e ------------- | 815 // ----------- S t a t e ------------- |
(...skipping 961 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1806 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) | 1777 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) |
1807 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 1778 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
1808 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 1779 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
1809 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1780 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
1810 } | 1781 } |
1811 | 1782 |
1812 | 1783 |
1813 } } // namespace v8::internal | 1784 } } // namespace v8::internal |
1814 | 1785 |
1815 #endif // V8_TARGET_ARCH_X64 | 1786 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |