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 2573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2584 Handle<Map> receiver_map) { | 2584 Handle<Map> receiver_map) { |
2585 // ----------- S t a t e ------------- | 2585 // ----------- S t a t e ------------- |
2586 // -- eax : value | 2586 // -- eax : value |
2587 // -- ecx : key | 2587 // -- ecx : key |
2588 // -- edx : receiver | 2588 // -- edx : receiver |
2589 // -- esp[0] : return address | 2589 // -- esp[0] : return address |
2590 // ----------------------------------- | 2590 // ----------------------------------- |
2591 ElementsKind elements_kind = receiver_map->elements_kind(); | 2591 ElementsKind elements_kind = receiver_map->elements_kind(); |
2592 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; | 2592 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; |
2593 Handle<Code> stub = | 2593 Handle<Code> stub = |
2594 KeyedStoreElementStub(is_jsarray, elements_kind).GetCode(); | 2594 KeyedStoreElementStub(is_jsarray, elements_kind, grow_mode_).GetCode(); |
2595 | 2595 |
2596 __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK); | 2596 __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK); |
2597 | 2597 |
2598 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2598 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
2599 __ jmp(ic, RelocInfo::CODE_TARGET); | 2599 __ jmp(ic, RelocInfo::CODE_TARGET); |
2600 | 2600 |
2601 // Return the generated code. | 2601 // Return the generated code. |
2602 return GetCode(NORMAL, factory()->empty_string()); | 2602 return GetCode(NORMAL, factory()->empty_string()); |
2603 } | 2603 } |
2604 | 2604 |
(...skipping 1106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3711 __ bind(&miss_force_generic); | 3711 __ bind(&miss_force_generic); |
3712 Handle<Code> miss_ic = | 3712 Handle<Code> miss_ic = |
3713 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); | 3713 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
3714 __ jmp(miss_ic, RelocInfo::CODE_TARGET); | 3714 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
3715 } | 3715 } |
3716 | 3716 |
3717 | 3717 |
3718 void KeyedStoreStubCompiler::GenerateStoreFastElement( | 3718 void KeyedStoreStubCompiler::GenerateStoreFastElement( |
3719 MacroAssembler* masm, | 3719 MacroAssembler* masm, |
3720 bool is_js_array, | 3720 bool is_js_array, |
3721 ElementsKind elements_kind) { | 3721 ElementsKind elements_kind, |
| 3722 KeyedAccessGrowMode grow_mode) { |
3722 // ----------- S t a t e ------------- | 3723 // ----------- S t a t e ------------- |
3723 // -- eax : value | 3724 // -- eax : value |
3724 // -- ecx : key | 3725 // -- ecx : key |
3725 // -- edx : receiver | 3726 // -- edx : receiver |
3726 // -- esp[0] : return address | 3727 // -- esp[0] : return address |
3727 // ----------------------------------- | 3728 // ----------------------------------- |
3728 Label miss_force_generic, transition_elements_kind; | 3729 Label miss_force_generic, grow, slow, transition_elements_kind; |
| 3730 Label check_capacity, prepare_slow, finish_store, commit_backing_store; |
3729 | 3731 |
3730 // This stub is meant to be tail-jumped to, the receiver must already | 3732 // This stub is meant to be tail-jumped to, the receiver must already |
3731 // have been verified by the caller to not be a smi. | 3733 // have been verified by the caller to not be a smi. |
3732 | 3734 |
3733 // Check that the key is a smi. | 3735 // Check that the key is a smi. |
3734 __ JumpIfNotSmi(ecx, &miss_force_generic); | 3736 __ JumpIfNotSmi(ecx, &miss_force_generic); |
3735 | 3737 |
| 3738 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
| 3739 __ JumpIfNotSmi(eax, &transition_elements_kind); |
| 3740 } |
| 3741 |
3736 // Get the elements array and make sure it is a fast element array, not 'cow'. | 3742 // Get the elements array and make sure it is a fast element array, not 'cow'. |
3737 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 3743 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
3738 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), | |
3739 Immediate(masm->isolate()->factory()->fixed_array_map())); | |
3740 __ j(not_equal, &miss_force_generic); | |
3741 | |
3742 if (is_js_array) { | 3744 if (is_js_array) { |
3743 // Check that the key is within bounds. | 3745 // Check that the key is within bounds. |
3744 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. | 3746 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. |
3745 __ j(above_equal, &miss_force_generic); | 3747 if (grow_mode == ALLOW_JSARRAY_GROWTH) { |
| 3748 __ j(above_equal, &grow); |
| 3749 } else { |
| 3750 __ j(above_equal, &miss_force_generic); |
| 3751 } |
3746 } else { | 3752 } else { |
3747 // Check that the key is within bounds. | 3753 // Check that the key is within bounds. |
3748 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. | 3754 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. |
3749 __ j(above_equal, &miss_force_generic); | 3755 __ j(above_equal, &miss_force_generic); |
3750 } | 3756 } |
3751 | 3757 |
| 3758 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), |
| 3759 Immediate(masm->isolate()->factory()->fixed_array_map())); |
| 3760 __ j(not_equal, &miss_force_generic); |
| 3761 |
| 3762 __ bind(&finish_store); |
3752 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { | 3763 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
3753 __ JumpIfNotSmi(eax, &transition_elements_kind); | |
3754 // ecx is a smi, use times_half_pointer_size instead of | 3764 // ecx is a smi, use times_half_pointer_size instead of |
3755 // times_pointer_size | 3765 // times_pointer_size |
3756 __ mov(FieldOperand(edi, | 3766 __ mov(FieldOperand(edi, |
3757 ecx, | 3767 ecx, |
3758 times_half_pointer_size, | 3768 times_half_pointer_size, |
3759 FixedArray::kHeaderSize), eax); | 3769 FixedArray::kHeaderSize), eax); |
3760 } else { | 3770 } else { |
3761 ASSERT(elements_kind == FAST_ELEMENTS); | 3771 ASSERT(elements_kind == FAST_ELEMENTS); |
3762 // Do the store and update the write barrier. | 3772 // Do the store and update the write barrier. |
3763 // ecx is a smi, use times_half_pointer_size instead of | 3773 // ecx is a smi, use times_half_pointer_size instead of |
3764 // times_pointer_size | 3774 // times_pointer_size |
3765 __ lea(ecx, FieldOperand(edi, | 3775 __ lea(ecx, FieldOperand(edi, |
3766 ecx, | 3776 ecx, |
3767 times_half_pointer_size, | 3777 times_half_pointer_size, |
3768 FixedArray::kHeaderSize)); | 3778 FixedArray::kHeaderSize)); |
3769 __ mov(Operand(ecx, 0), eax); | 3779 __ mov(Operand(ecx, 0), eax); |
3770 // Make sure to preserve the value in register eax. | 3780 // Make sure to preserve the value in register eax. |
3771 __ mov(edx, eax); | 3781 __ mov(ebx, eax); |
3772 __ RecordWrite(edi, ecx, edx, kDontSaveFPRegs); | 3782 __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs); |
3773 } | 3783 } |
3774 | 3784 |
3775 // Done. | 3785 // Done. |
3776 __ ret(0); | 3786 __ ret(0); |
3777 | 3787 |
3778 // Handle store cache miss, replacing the ic with the generic stub. | 3788 // Handle store cache miss, replacing the ic with the generic stub. |
3779 __ bind(&miss_force_generic); | 3789 __ bind(&miss_force_generic); |
3780 Handle<Code> ic_force_generic = | 3790 Handle<Code> ic_force_generic = |
3781 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3791 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
3782 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 3792 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
3783 | 3793 |
3784 // Handle transition to other elements kinds without using the generic stub. | 3794 // Handle transition to other elements kinds without using the generic stub. |
3785 __ bind(&transition_elements_kind); | 3795 __ bind(&transition_elements_kind); |
3786 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); | 3796 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); |
3787 __ jmp(ic_miss, RelocInfo::CODE_TARGET); | 3797 __ jmp(ic_miss, RelocInfo::CODE_TARGET); |
| 3798 |
| 3799 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) { |
| 3800 // Handle transition requiring the array to grow. |
| 3801 __ bind(&grow); |
| 3802 |
| 3803 // Make sure the array is only growing by a single element, anything else |
| 3804 // must be handled by the runtime. Flags are already set by previous |
| 3805 // compare. |
| 3806 __ j(not_equal, &miss_force_generic); |
| 3807 |
| 3808 // Check for the empty array, and preallocate a small backing store if |
| 3809 // possible. |
| 3810 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3811 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); |
| 3812 __ j(not_equal, &check_capacity); |
| 3813 |
| 3814 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); |
| 3815 __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT); |
| 3816 // Restore the key, which is known to be the array length. |
| 3817 |
| 3818 // eax: value |
| 3819 // ecx: key |
| 3820 // edx: receiver |
| 3821 // edi: elements |
| 3822 // Make sure that the backing store can hold additional elements. |
| 3823 __ mov(FieldOperand(edi, JSObject::kMapOffset), |
| 3824 Immediate(masm->isolate()->factory()->fixed_array_map())); |
| 3825 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), |
| 3826 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements))); |
| 3827 __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value())); |
| 3828 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) { |
| 3829 __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx); |
| 3830 } |
| 3831 |
| 3832 // Store the element at index zero. |
| 3833 __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax); |
| 3834 |
| 3835 // Install the new backing store in the JSArray. |
| 3836 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi); |
| 3837 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx, |
| 3838 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 3839 |
| 3840 // Increment the length of the array. |
| 3841 __ mov(FieldOperand(edx, JSArray::kLengthOffset), |
| 3842 Immediate(Smi::FromInt(1))); |
| 3843 __ ret(0); |
| 3844 |
| 3845 __ bind(&check_capacity); |
| 3846 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), |
| 3847 Immediate(masm->isolate()->factory()->fixed_cow_array_map())); |
| 3848 __ j(equal, &miss_force_generic); |
| 3849 |
| 3850 // eax: value |
| 3851 // ecx: key |
| 3852 // edx: receiver |
| 3853 // edi: elements |
| 3854 // Make sure that the backing store can hold additional elements. |
| 3855 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); |
| 3856 __ j(above_equal, &slow); |
| 3857 |
| 3858 // Grow the array and finish the store. |
| 3859 __ add(FieldOperand(edx, JSArray::kLengthOffset), |
| 3860 Immediate(Smi::FromInt(1))); |
| 3861 __ jmp(&finish_store); |
| 3862 |
| 3863 __ bind(&prepare_slow); |
| 3864 // Restore the key, which is known to be the array length. |
| 3865 __ mov(ecx, Immediate(0)); |
| 3866 |
| 3867 __ bind(&slow); |
| 3868 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
| 3869 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
| 3870 } |
3788 } | 3871 } |
3789 | 3872 |
3790 | 3873 |
3791 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( | 3874 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
3792 MacroAssembler* masm, | 3875 MacroAssembler* masm, |
3793 bool is_js_array) { | 3876 bool is_js_array, |
| 3877 KeyedAccessGrowMode grow_mode) { |
3794 // ----------- S t a t e ------------- | 3878 // ----------- S t a t e ------------- |
3795 // -- eax : value | 3879 // -- eax : value |
3796 // -- ecx : key | 3880 // -- ecx : key |
3797 // -- edx : receiver | 3881 // -- edx : receiver |
3798 // -- esp[0] : return address | 3882 // -- esp[0] : return address |
3799 // ----------------------------------- | 3883 // ----------------------------------- |
3800 Label miss_force_generic, transition_elements_kind; | 3884 Label miss_force_generic, transition_elements_kind, grow, slow; |
| 3885 Label check_capacity, prepare_slow, finish_store, commit_backing_store; |
3801 | 3886 |
3802 // This stub is meant to be tail-jumped to, the receiver must already | 3887 // This stub is meant to be tail-jumped to, the receiver must already |
3803 // have been verified by the caller to not be a smi. | 3888 // have been verified by the caller to not be a smi. |
3804 | 3889 |
3805 // Check that the key is a smi. | 3890 // Check that the key is a smi. |
3806 __ JumpIfNotSmi(ecx, &miss_force_generic); | 3891 __ JumpIfNotSmi(ecx, &miss_force_generic); |
3807 | 3892 |
3808 // Get the elements array. | 3893 // Get the elements array. |
3809 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 3894 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
3810 __ AssertFastElements(edi); | 3895 __ AssertFastElements(edi); |
3811 | 3896 |
3812 if (is_js_array) { | 3897 if (is_js_array) { |
3813 // Check that the key is within bounds. | 3898 // Check that the key is within bounds. |
3814 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. | 3899 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. |
| 3900 if (grow_mode == ALLOW_JSARRAY_GROWTH) { |
| 3901 __ j(above_equal, &grow); |
| 3902 } else { |
| 3903 __ j(above_equal, &miss_force_generic); |
| 3904 } |
3815 } else { | 3905 } else { |
3816 // Check that the key is within bounds. | 3906 // Check that the key is within bounds. |
3817 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. | 3907 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. |
3818 } | 3908 } |
3819 __ j(above_equal, &miss_force_generic); | |
3820 | 3909 |
3821 __ StoreNumberToDoubleElements(eax, | 3910 __ bind(&finish_store); |
3822 edi, | 3911 __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0, |
3823 ecx, | 3912 &transition_elements_kind, true); |
3824 edx, | |
3825 xmm0, | |
3826 &transition_elements_kind, | |
3827 true); | |
3828 __ ret(0); | 3913 __ ret(0); |
3829 | 3914 |
3830 // Handle store cache miss, replacing the ic with the generic stub. | 3915 // Handle store cache miss, replacing the ic with the generic stub. |
3831 __ bind(&miss_force_generic); | 3916 __ bind(&miss_force_generic); |
3832 Handle<Code> ic_force_generic = | 3917 Handle<Code> ic_force_generic = |
3833 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3918 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
3834 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 3919 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
3835 | 3920 |
3836 // Handle transition to other elements kinds without using the generic stub. | 3921 // Handle transition to other elements kinds without using the generic stub. |
3837 __ bind(&transition_elements_kind); | 3922 __ bind(&transition_elements_kind); |
3838 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); | 3923 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); |
3839 __ jmp(ic_miss, RelocInfo::CODE_TARGET); | 3924 __ jmp(ic_miss, RelocInfo::CODE_TARGET); |
| 3925 |
| 3926 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) { |
| 3927 // Handle transition requiring the array to grow. |
| 3928 __ bind(&grow); |
| 3929 |
| 3930 // Make sure the array is only growing by a single element, anything else |
| 3931 // must be handled by the runtime. Flags are already set by previous |
| 3932 // compare. |
| 3933 __ j(not_equal, &miss_force_generic); |
| 3934 |
| 3935 // Transition on values that can't be stored in a FixedDoubleArray. |
| 3936 Label value_is_smi; |
| 3937 __ JumpIfSmi(eax, &value_is_smi); |
| 3938 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3939 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map()))); |
| 3940 __ j(not_equal, &transition_elements_kind); |
| 3941 __ bind(&value_is_smi); |
| 3942 |
| 3943 // Check for the empty array, and preallocate a small backing store if |
| 3944 // possible. |
| 3945 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3946 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); |
| 3947 __ j(not_equal, &check_capacity); |
| 3948 |
| 3949 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); |
| 3950 __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT); |
| 3951 // Restore the key, which is known to be the array length. |
| 3952 __ mov(ecx, Immediate(0)); |
| 3953 |
| 3954 // eax: value |
| 3955 // ecx: key |
| 3956 // edx: receiver |
| 3957 // edi: elements |
| 3958 // Initialize the new FixedDoubleArray. Leave elements unitialized for |
| 3959 // efficiency, they are guaranteed to be initialized before use. |
| 3960 __ mov(FieldOperand(edi, JSObject::kMapOffset), |
| 3961 Immediate(masm->isolate()->factory()->fixed_double_array_map())); |
| 3962 __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset), |
| 3963 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements))); |
| 3964 |
| 3965 // Install the new backing store in the JSArray. |
| 3966 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi); |
| 3967 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx, |
| 3968 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 3969 |
| 3970 // Increment the length of the array. |
| 3971 __ add(FieldOperand(edx, JSArray::kLengthOffset), |
| 3972 Immediate(Smi::FromInt(1))); |
| 3973 __ jmp(&finish_store); |
| 3974 |
| 3975 __ bind(&check_capacity); |
| 3976 // eax: value |
| 3977 // ecx: key |
| 3978 // edx: receiver |
| 3979 // edi: elements |
| 3980 // Make sure that the backing store can hold additional elements. |
| 3981 __ cmp(ecx, FieldOperand(edi, FixedDoubleArray::kLengthOffset)); |
| 3982 __ j(above_equal, &slow); |
| 3983 |
| 3984 // Grow the array and finish the store. |
| 3985 __ add(FieldOperand(edx, JSArray::kLengthOffset), |
| 3986 Immediate(Smi::FromInt(1))); |
| 3987 __ jmp(&finish_store); |
| 3988 |
| 3989 __ bind(&prepare_slow); |
| 3990 // Restore the key, which is known to be the array length. |
| 3991 __ mov(ecx, Immediate(0)); |
| 3992 |
| 3993 __ bind(&slow); |
| 3994 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
| 3995 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
| 3996 } |
3840 } | 3997 } |
3841 | 3998 |
3842 | 3999 |
3843 #undef __ | 4000 #undef __ |
3844 | 4001 |
3845 } } // namespace v8::internal | 4002 } } // namespace v8::internal |
3846 | 4003 |
3847 #endif // V8_TARGET_ARCH_IA32 | 4004 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |