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 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
744 Immediate(the_hole)); | 744 Immediate(the_hole)); |
745 } else { | 745 } else { |
746 __ cmp(Operand::Cell(cell), Immediate(the_hole)); | 746 __ cmp(Operand::Cell(cell), Immediate(the_hole)); |
747 } | 747 } |
748 __ j(not_equal, miss); | 748 __ j(not_equal, miss); |
749 } | 749 } |
750 | 750 |
751 | 751 |
752 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 752 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
753 // but may be destroyed if store is successful. | 753 // but may be destroyed if store is successful. |
754 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 754 void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, |
755 Handle<JSObject> object, | 755 Handle<JSObject> object, |
756 LookupResult* lookup, | 756 LookupResult* lookup, |
757 Handle<Map> transition, | 757 Handle<Map> transition, |
758 Handle<Name> name, | 758 Handle<Name> name, |
759 Register receiver_reg, | 759 Register receiver_reg, |
760 Register name_reg, | 760 Register name_reg, |
761 Register value_reg, | 761 Register value_reg, |
762 Register scratch1, | 762 Register scratch1, |
763 Register scratch2, | 763 Register scratch2, |
764 Label* miss_label, | 764 Label* miss_label, |
765 Label* miss_restore_name) { | 765 Label* miss_restore_name) { |
766 // Check that the map of the object hasn't changed. | 766 // Check that the map of the object hasn't changed. |
767 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | |
768 : REQUIRE_EXACT_MAP; | |
769 __ CheckMap(receiver_reg, Handle<Map>(object->map()), | 767 __ CheckMap(receiver_reg, Handle<Map>(object->map()), |
770 miss_label, DO_SMI_CHECK, mode); | 768 miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP); |
771 | 769 |
772 // Perform global security token check if needed. | 770 // Perform global security token check if needed. |
773 if (object->IsJSGlobalProxy()) { | 771 if (object->IsJSGlobalProxy()) { |
774 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label); | 772 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label); |
775 } | 773 } |
776 | 774 |
777 // Check that we are allowed to write this. | 775 // Check that we are allowed to write this. |
778 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { | 776 if (object->GetPrototype()->IsJSObject()) { |
779 JSObject* holder; | 777 JSObject* holder; |
780 // holder == object indicates that no property was found. | 778 // holder == object indicates that no property was found. |
781 if (lookup->holder() != *object) { | 779 if (lookup->holder() != *object) { |
782 holder = lookup->holder(); | 780 holder = lookup->holder(); |
783 } else { | 781 } else { |
784 // Find the top object. | 782 // Find the top object. |
785 holder = *object; | 783 holder = *object; |
786 do { | 784 do { |
787 holder = JSObject::cast(holder->GetPrototype()); | 785 holder = JSObject::cast(holder->GetPrototype()); |
788 } while (holder->GetPrototype()->IsJSObject()); | 786 } while (holder->GetPrototype()->IsJSObject()); |
(...skipping 18 matching lines...) Expand all Loading... |
807 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); | 805 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); |
808 } | 806 } |
809 } | 807 } |
810 } | 808 } |
811 | 809 |
812 // Stub never generated for non-global objects that require access | 810 // Stub never generated for non-global objects that require access |
813 // checks. | 811 // checks. |
814 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 812 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
815 | 813 |
816 // Perform map transition for the receiver if necessary. | 814 // Perform map transition for the receiver if necessary. |
817 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 815 if (object->map()->unused_property_fields() == 0) { |
818 // The properties must be extended before we can store the value. | 816 // The properties must be extended before we can store the value. |
819 // We jump to a runtime call that extends the properties array. | 817 // We jump to a runtime call that extends the properties array. |
820 __ pop(scratch1); // Return address. | 818 __ pop(scratch1); // Return address. |
821 __ push(receiver_reg); | 819 __ push(receiver_reg); |
822 __ push(Immediate(transition)); | 820 __ push(Immediate(transition)); |
823 __ push(eax); | 821 __ push(eax); |
824 __ push(scratch1); | 822 __ push(scratch1); |
825 __ TailCallExternalReference( | 823 __ TailCallExternalReference( |
826 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 824 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
827 masm->isolate()), | 825 masm->isolate()), |
828 3, | 826 3, |
829 1); | 827 1); |
830 return; | 828 return; |
831 } | 829 } |
832 | 830 |
833 int index; | 831 // Update the map of the object. |
834 if (!transition.is_null()) { | 832 __ mov(scratch1, Immediate(transition)); |
835 // Update the map of the object. | 833 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); |
836 __ mov(scratch1, Immediate(transition)); | |
837 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); | |
838 | 834 |
839 // Update the write barrier for the map field and pass the now unused | 835 // Update the write barrier for the map field and pass the now unused |
840 // name_reg as scratch register. | 836 // name_reg as scratch register. |
841 __ RecordWriteField(receiver_reg, | 837 __ RecordWriteField(receiver_reg, |
842 HeapObject::kMapOffset, | 838 HeapObject::kMapOffset, |
843 scratch1, | 839 scratch1, |
844 name_reg, | 840 name_reg, |
845 kDontSaveFPRegs, | 841 kDontSaveFPRegs, |
846 OMIT_REMEMBERED_SET, | 842 OMIT_REMEMBERED_SET, |
847 OMIT_SMI_CHECK); | 843 OMIT_SMI_CHECK); |
848 index = transition->instance_descriptors()->GetFieldIndex( | |
849 transition->LastAdded()); | |
850 } else { | |
851 index = lookup->GetFieldIndex().field_index(); | |
852 } | |
853 | 844 |
| 845 int index = transition->instance_descriptors()->GetFieldIndex( |
| 846 transition->LastAdded()); |
854 | 847 |
855 // Adjust for the number of properties stored in the object. Even in the | 848 // Adjust for the number of properties stored in the object. Even in the |
856 // face of a transition we can use the old map here because the size of the | 849 // face of a transition we can use the old map here because the size of the |
857 // object and the number of in-object properties is not going to change. | 850 // object and the number of in-object properties is not going to change. |
858 index -= object->map()->inobject_properties(); | 851 index -= object->map()->inobject_properties(); |
859 | 852 |
| 853 // TODO(verwaest): Share this code as a code stub. |
860 if (index < 0) { | 854 if (index < 0) { |
861 // Set the property straight into the object. | 855 // Set the property straight into the object. |
862 int offset = object->map()->instance_size() + (index * kPointerSize); | 856 int offset = object->map()->instance_size() + (index * kPointerSize); |
| 857 __ mov(FieldOperand(receiver_reg, offset), value_reg); |
| 858 |
| 859 // Update the write barrier for the array address. |
| 860 // Pass the value being stored in the now unused name_reg. |
| 861 __ mov(name_reg, value_reg); |
| 862 __ RecordWriteField(receiver_reg, |
| 863 offset, |
| 864 name_reg, |
| 865 scratch1, |
| 866 kDontSaveFPRegs); |
| 867 } else { |
| 868 // Write to the properties array. |
| 869 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
| 870 // Get the properties array (optimistically). |
| 871 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); |
| 872 __ mov(FieldOperand(scratch1, offset), eax); |
| 873 |
| 874 // Update the write barrier for the array address. |
| 875 // Pass the value being stored in the now unused name_reg. |
| 876 __ mov(name_reg, value_reg); |
| 877 __ RecordWriteField(scratch1, |
| 878 offset, |
| 879 name_reg, |
| 880 receiver_reg, |
| 881 kDontSaveFPRegs); |
| 882 } |
| 883 |
| 884 // Return the value (register eax). |
| 885 ASSERT(value_reg.is(eax)); |
| 886 __ ret(0); |
| 887 } |
| 888 |
| 889 |
| 890 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
| 891 // but may be destroyed if store is successful. |
| 892 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
| 893 Handle<JSObject> object, |
| 894 LookupResult* lookup, |
| 895 Register receiver_reg, |
| 896 Register name_reg, |
| 897 Register value_reg, |
| 898 Register scratch1, |
| 899 Register scratch2, |
| 900 Label* miss_label) { |
| 901 // Check that the map of the object hasn't changed. |
| 902 __ CheckMap(receiver_reg, Handle<Map>(object->map()), |
| 903 miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); |
| 904 |
| 905 // Perform global security token check if needed. |
| 906 if (object->IsJSGlobalProxy()) { |
| 907 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label); |
| 908 } |
| 909 |
| 910 // Stub never generated for non-global objects that require access |
| 911 // checks. |
| 912 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 913 |
| 914 int index = lookup->GetFieldIndex().field_index(); |
| 915 |
| 916 // Adjust for the number of properties stored in the object. Even in the |
| 917 // face of a transition we can use the old map here because the size of the |
| 918 // object and the number of in-object properties is not going to change. |
| 919 index -= object->map()->inobject_properties(); |
| 920 |
| 921 // TODO(verwaest): Share this code as a code stub. |
| 922 if (index < 0) { |
| 923 // Set the property straight into the object. |
| 924 int offset = object->map()->instance_size() + (index * kPointerSize); |
863 __ mov(FieldOperand(receiver_reg, offset), value_reg); | 925 __ mov(FieldOperand(receiver_reg, offset), value_reg); |
864 | 926 |
865 // Update the write barrier for the array address. | 927 // Update the write barrier for the array address. |
866 // Pass the value being stored in the now unused name_reg. | 928 // Pass the value being stored in the now unused name_reg. |
867 __ mov(name_reg, value_reg); | 929 __ mov(name_reg, value_reg); |
868 __ RecordWriteField(receiver_reg, | 930 __ RecordWriteField(receiver_reg, |
869 offset, | 931 offset, |
870 name_reg, | 932 name_reg, |
871 scratch1, | 933 scratch1, |
872 kDontSaveFPRegs); | 934 kDontSaveFPRegs); |
(...skipping 2755 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3628 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | 3690 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
3629 } | 3691 } |
3630 } | 3692 } |
3631 | 3693 |
3632 | 3694 |
3633 #undef __ | 3695 #undef __ |
3634 | 3696 |
3635 } } // namespace v8::internal | 3697 } } // namespace v8::internal |
3636 | 3698 |
3637 #endif // V8_TARGET_ARCH_IA32 | 3699 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |