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 698 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
709 __ bind(label); | 709 __ bind(label); |
710 __ Move(this->name(), name); | 710 __ Move(this->name(), name); |
711 } | 711 } |
712 } | 712 } |
713 | 713 |
714 | 714 |
715 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 715 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
716 // but may be destroyed if store is successful. | 716 // but may be destroyed if store is successful. |
717 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 717 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
718 Handle<JSObject> object, | 718 Handle<JSObject> object, |
719 int index, | 719 LookupResult* lookup, |
720 Handle<Map> transition, | 720 Handle<Map> transition, |
721 Handle<Name> name, | 721 Handle<Name> name, |
722 Register receiver_reg, | 722 Register receiver_reg, |
723 Register name_reg, | 723 Register name_reg, |
724 Register value_reg, | 724 Register value_reg, |
725 Register scratch1, | 725 Register scratch1, |
726 Register scratch2, | 726 Register scratch2, |
727 Label* miss_label, | 727 Label* miss_label, |
728 Label* miss_restore_name) { | 728 Label* miss_restore_name) { |
729 LookupResult lookup(masm->isolate()); | |
730 object->Lookup(*name, &lookup); | |
731 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { | |
732 // In sloppy mode, we could just return the value and be done. However, we | |
733 // might be in strict mode, where we have to throw. Since we cannot tell, | |
734 // go into slow case unconditionally. | |
735 __ jmp(miss_label); | |
736 return; | |
737 } | |
738 | |
739 // Check that the map of the object hasn't changed. | 729 // Check that the map of the object hasn't changed. |
740 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | 730 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS |
741 : REQUIRE_EXACT_MAP; | 731 : REQUIRE_EXACT_MAP; |
742 __ CheckMap(receiver_reg, Handle<Map>(object->map()), | 732 __ CheckMap(receiver_reg, Handle<Map>(object->map()), |
743 miss_label, DO_SMI_CHECK, mode); | 733 miss_label, DO_SMI_CHECK, mode); |
744 | 734 |
745 // Perform global security token check if needed. | 735 // Perform global security token check if needed. |
746 if (object->IsJSGlobalProxy()) { | 736 if (object->IsJSGlobalProxy()) { |
747 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | 737 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); |
748 } | 738 } |
749 | 739 |
750 // Check that we are allowed to write this. | 740 // Check that we are allowed to write this. |
751 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { | 741 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { |
752 JSObject* holder; | 742 JSObject* holder; |
753 if (lookup.IsFound()) { | 743 // holder == object indicates that no property was found. |
754 holder = lookup.holder(); | 744 if (lookup->holder() != *object) { |
| 745 holder = lookup->holder(); |
755 } else { | 746 } else { |
756 // Find the top object. | 747 // Find the top object. |
757 holder = *object; | 748 holder = *object; |
758 do { | 749 do { |
759 holder = JSObject::cast(holder->GetPrototype()); | 750 holder = JSObject::cast(holder->GetPrototype()); |
760 } while (holder->GetPrototype()->IsJSObject()); | 751 } while (holder->GetPrototype()->IsJSObject()); |
761 } | 752 } |
762 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, | 753 Register holder_reg = CheckPrototypes( |
763 scratch1, scratch2, name, miss_restore_name); | 754 object, receiver_reg, Handle<JSObject>(holder), name_reg, |
| 755 scratch1, scratch2, name, miss_restore_name); |
| 756 // If no property was found, and the holder (the last object in the |
| 757 // prototype chain) is in slow mode, we need to do a negative lookup on the |
| 758 // holder. |
| 759 if (lookup->holder() == *object && |
| 760 !holder->HasFastProperties() && |
| 761 !holder->IsJSGlobalProxy() && |
| 762 !holder->IsJSGlobalObject()) { |
| 763 GenerateDictionaryNegativeLookup( |
| 764 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); |
| 765 } |
764 } | 766 } |
765 | 767 |
766 // Stub never generated for non-global objects that require access | 768 // Stub never generated for non-global objects that require access |
767 // checks. | 769 // checks. |
768 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 770 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
769 | 771 |
770 // Perform map transition for the receiver if necessary. | 772 // Perform map transition for the receiver if necessary. |
771 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 773 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { |
772 // The properties must be extended before we can store the value. | 774 // The properties must be extended before we can store the value. |
773 // We jump to a runtime call that extends the properties array. | 775 // We jump to a runtime call that extends the properties array. |
774 __ pop(scratch1); // Return address. | 776 __ pop(scratch1); // Return address. |
775 __ push(receiver_reg); | 777 __ push(receiver_reg); |
776 __ Push(transition); | 778 __ Push(transition); |
777 __ push(value_reg); | 779 __ push(value_reg); |
778 __ push(scratch1); | 780 __ push(scratch1); |
779 __ TailCallExternalReference( | 781 __ TailCallExternalReference( |
780 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 782 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
781 masm->isolate()), | 783 masm->isolate()), |
782 3, | 784 3, |
783 1); | 785 1); |
784 return; | 786 return; |
785 } | 787 } |
786 | 788 |
| 789 int index; |
787 if (!transition.is_null()) { | 790 if (!transition.is_null()) { |
788 // Update the map of the object. | 791 // Update the map of the object. |
789 __ Move(scratch1, transition); | 792 __ Move(scratch1, transition); |
790 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); | 793 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); |
791 | 794 |
792 // Update the write barrier for the map field and pass the now unused | 795 // Update the write barrier for the map field and pass the now unused |
793 // name_reg as scratch register. | 796 // name_reg as scratch register. |
794 __ RecordWriteField(receiver_reg, | 797 __ RecordWriteField(receiver_reg, |
795 HeapObject::kMapOffset, | 798 HeapObject::kMapOffset, |
796 scratch1, | 799 scratch1, |
797 name_reg, | 800 name_reg, |
798 kDontSaveFPRegs, | 801 kDontSaveFPRegs, |
799 OMIT_REMEMBERED_SET, | 802 OMIT_REMEMBERED_SET, |
800 OMIT_SMI_CHECK); | 803 OMIT_SMI_CHECK); |
| 804 index = transition->instance_descriptors()->GetFieldIndex( |
| 805 transition->LastAdded()); |
| 806 } else { |
| 807 index = lookup->GetFieldIndex().field_index(); |
801 } | 808 } |
802 | 809 |
803 // Adjust for the number of properties stored in the object. Even in the | 810 // Adjust for the number of properties stored in the object. Even in the |
804 // face of a transition we can use the old map here because the size of the | 811 // face of a transition we can use the old map here because the size of the |
805 // object and the number of in-object properties is not going to change. | 812 // object and the number of in-object properties is not going to change. |
806 index -= object->map()->inobject_properties(); | 813 index -= object->map()->inobject_properties(); |
807 | 814 |
808 if (index < 0) { | 815 if (index < 0) { |
809 // Set the property straight into the object. | 816 // Set the property straight into the object. |
810 int offset = object->map()->instance_size() + (index * kPointerSize); | 817 int offset = object->map()->instance_size() + (index * kPointerSize); |
(...skipping 2590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3401 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | 3408 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
3402 } | 3409 } |
3403 } | 3410 } |
3404 | 3411 |
3405 | 3412 |
3406 #undef __ | 3413 #undef __ |
3407 | 3414 |
3408 } } // namespace v8::internal | 3415 } } // namespace v8::internal |
3409 | 3416 |
3410 #endif // V8_TARGET_ARCH_X64 | 3417 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |