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 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 __ jmp(code, RelocInfo::CODE_TARGET); | 738 __ jmp(code, RelocInfo::CODE_TARGET); |
739 } | 739 } |
740 | 740 |
741 | 741 |
742 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 742 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
743 // but may be destroyed if store is successful. | 743 // but may be destroyed if store is successful. |
744 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 744 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
745 Handle<JSObject> object, | 745 Handle<JSObject> object, |
746 int index, | 746 int index, |
747 Handle<Map> transition, | 747 Handle<Map> transition, |
748 Handle<String> name, | |
749 Register receiver_reg, | 748 Register receiver_reg, |
750 Register name_reg, | 749 Register name_reg, |
751 Register scratch1, | 750 Register scratch, |
752 Register scratch2, | |
753 Label* miss_label) { | 751 Label* miss_label) { |
754 LookupResult lookup(masm->isolate()); | |
755 object->Lookup(*name, &lookup); | |
756 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { | |
757 // In sloppy mode, we could just return the value and be done. However, we | |
758 // might be in strict mode, where we have to throw. Since we cannot tell, | |
759 // go into slow case unconditionally. | |
760 __ jmp(miss_label); | |
761 return; | |
762 } | |
763 | |
764 // Check that the map of the object hasn't changed. | 752 // Check that the map of the object hasn't changed. |
765 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | 753 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS |
766 : REQUIRE_EXACT_MAP; | 754 : REQUIRE_EXACT_MAP; |
767 __ CheckMap(receiver_reg, Handle<Map>(object->map()), | 755 __ CheckMap(receiver_reg, Handle<Map>(object->map()), |
768 miss_label, DO_SMI_CHECK, mode); | 756 miss_label, DO_SMI_CHECK, mode); |
769 | 757 |
770 // Perform global security token check if needed. | 758 // Perform global security token check if needed. |
771 if (object->IsJSGlobalProxy()) { | 759 if (object->IsJSGlobalProxy()) { |
772 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | 760 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); |
773 } | |
774 | |
775 // Check that we are allowed to write this. | |
776 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { | |
777 JSObject* holder; | |
778 if (lookup.IsFound()) { | |
779 holder = lookup.holder(); | |
780 } else { | |
781 // Find the top object. | |
782 holder = *object; | |
783 do { | |
784 holder = JSObject::cast(holder->GetPrototype()); | |
785 } while (holder->GetPrototype()->IsJSObject()); | |
786 } | |
787 // We need an extra register, push | |
788 __ push(name_reg); | |
789 Label miss_pop, done_check; | |
790 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, | |
791 scratch1, scratch2, name, &miss_pop); | |
792 __ jmp(&done_check); | |
793 __ bind(&miss_pop); | |
794 __ pop(name_reg); | |
795 __ jmp(miss_label); | |
796 __ bind(&done_check); | |
797 __ pop(name_reg); | |
798 } | 761 } |
799 | 762 |
800 // Stub never generated for non-global objects that require access | 763 // Stub never generated for non-global objects that require access |
801 // checks. | 764 // checks. |
802 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 765 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
803 | 766 |
804 // Perform map transition for the receiver if necessary. | 767 // Perform map transition for the receiver if necessary. |
805 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 768 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { |
806 // The properties must be extended before we can store the value. | 769 // The properties must be extended before we can store the value. |
807 // We jump to a runtime call that extends the properties array. | 770 // We jump to a runtime call that extends the properties array. |
808 __ pop(scratch1); // Return address. | 771 __ pop(scratch); // Return address. |
809 __ push(receiver_reg); | 772 __ push(receiver_reg); |
810 __ push(Immediate(transition)); | 773 __ push(Immediate(transition)); |
811 __ push(eax); | 774 __ push(eax); |
812 __ push(scratch1); | 775 __ push(scratch); |
813 __ TailCallExternalReference( | 776 __ TailCallExternalReference( |
814 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 777 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
815 masm->isolate()), | 778 masm->isolate()), |
816 3, | 779 3, |
817 1); | 780 1); |
818 return; | 781 return; |
819 } | 782 } |
820 | 783 |
821 if (!transition.is_null()) { | 784 if (!transition.is_null()) { |
822 // Update the map of the object. | 785 // Update the map of the object. |
823 __ mov(scratch1, Immediate(transition)); | 786 __ mov(scratch, Immediate(transition)); |
824 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); | 787 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch); |
825 | 788 |
826 // Update the write barrier for the map field and pass the now unused | 789 // Update the write barrier for the map field and pass the now unused |
827 // name_reg as scratch register. | 790 // name_reg as scratch register. |
828 __ RecordWriteField(receiver_reg, | 791 __ RecordWriteField(receiver_reg, |
829 HeapObject::kMapOffset, | 792 HeapObject::kMapOffset, |
830 scratch1, | 793 scratch, |
831 name_reg, | 794 name_reg, |
832 kDontSaveFPRegs, | 795 kDontSaveFPRegs, |
833 OMIT_REMEMBERED_SET, | 796 OMIT_REMEMBERED_SET, |
834 OMIT_SMI_CHECK); | 797 OMIT_SMI_CHECK); |
835 } | 798 } |
836 | 799 |
837 // Adjust for the number of properties stored in the object. Even in the | 800 // Adjust for the number of properties stored in the object. Even in the |
838 // face of a transition we can use the old map here because the size of the | 801 // face of a transition we can use the old map here because the size of the |
839 // object and the number of in-object properties is not going to change. | 802 // object and the number of in-object properties is not going to change. |
840 index -= object->map()->inobject_properties(); | 803 index -= object->map()->inobject_properties(); |
841 | 804 |
842 if (index < 0) { | 805 if (index < 0) { |
843 // Set the property straight into the object. | 806 // Set the property straight into the object. |
844 int offset = object->map()->instance_size() + (index * kPointerSize); | 807 int offset = object->map()->instance_size() + (index * kPointerSize); |
845 __ mov(FieldOperand(receiver_reg, offset), eax); | 808 __ mov(FieldOperand(receiver_reg, offset), eax); |
846 | 809 |
847 // Update the write barrier for the array address. | 810 // Update the write barrier for the array address. |
848 // Pass the value being stored in the now unused name_reg. | 811 // Pass the value being stored in the now unused name_reg. |
849 __ mov(name_reg, eax); | 812 __ mov(name_reg, eax); |
850 __ RecordWriteField(receiver_reg, | 813 __ RecordWriteField(receiver_reg, |
851 offset, | 814 offset, |
852 name_reg, | 815 name_reg, |
853 scratch1, | 816 scratch, |
854 kDontSaveFPRegs); | 817 kDontSaveFPRegs); |
855 } else { | 818 } else { |
856 // Write to the properties array. | 819 // Write to the properties array. |
857 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 820 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
858 // Get the properties array (optimistically). | 821 // Get the properties array (optimistically). |
859 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); | 822 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); |
860 __ mov(FieldOperand(scratch1, offset), eax); | 823 __ mov(FieldOperand(scratch, offset), eax); |
861 | 824 |
862 // Update the write barrier for the array address. | 825 // Update the write barrier for the array address. |
863 // Pass the value being stored in the now unused name_reg. | 826 // Pass the value being stored in the now unused name_reg. |
864 __ mov(name_reg, eax); | 827 __ mov(name_reg, eax); |
865 __ RecordWriteField(scratch1, | 828 __ RecordWriteField(scratch, |
866 offset, | 829 offset, |
867 name_reg, | 830 name_reg, |
868 receiver_reg, | 831 receiver_reg, |
869 kDontSaveFPRegs); | 832 kDontSaveFPRegs); |
870 } | 833 } |
871 | 834 |
872 // Return the value (register eax). | 835 // Return the value (register eax). |
873 __ ret(0); | 836 __ ret(0); |
874 } | 837 } |
875 | 838 |
(...skipping 1638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2514 Handle<String> name) { | 2477 Handle<String> name) { |
2515 // ----------- S t a t e ------------- | 2478 // ----------- S t a t e ------------- |
2516 // -- eax : value | 2479 // -- eax : value |
2517 // -- ecx : name | 2480 // -- ecx : name |
2518 // -- edx : receiver | 2481 // -- edx : receiver |
2519 // -- esp[0] : return address | 2482 // -- esp[0] : return address |
2520 // ----------------------------------- | 2483 // ----------------------------------- |
2521 Label miss; | 2484 Label miss; |
2522 | 2485 |
2523 // Generate store field code. Trashes the name register. | 2486 // Generate store field code. Trashes the name register. |
2524 GenerateStoreField(masm(), | 2487 GenerateStoreField(masm(), object, index, transition, edx, ecx, ebx, &miss); |
2525 object, | 2488 |
2526 index, | |
2527 transition, | |
2528 name, | |
2529 edx, ecx, ebx, edi, | |
2530 &miss); | |
2531 // Handle store cache miss. | 2489 // Handle store cache miss. |
2532 __ bind(&miss); | 2490 __ bind(&miss); |
2533 __ mov(ecx, Immediate(name)); // restore name | 2491 __ mov(ecx, Immediate(name)); // restore name |
2534 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); | 2492 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); |
2535 __ jmp(ic, RelocInfo::CODE_TARGET); | 2493 __ jmp(ic, RelocInfo::CODE_TARGET); |
2536 | 2494 |
2537 // Return the generated code. | 2495 // Return the generated code. |
2538 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 2496 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
2539 } | 2497 } |
2540 | 2498 |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2693 Label miss; | 2651 Label miss; |
2694 | 2652 |
2695 Counters* counters = isolate()->counters(); | 2653 Counters* counters = isolate()->counters(); |
2696 __ IncrementCounter(counters->keyed_store_field(), 1); | 2654 __ IncrementCounter(counters->keyed_store_field(), 1); |
2697 | 2655 |
2698 // Check that the name has not changed. | 2656 // Check that the name has not changed. |
2699 __ cmp(ecx, Immediate(name)); | 2657 __ cmp(ecx, Immediate(name)); |
2700 __ j(not_equal, &miss); | 2658 __ j(not_equal, &miss); |
2701 | 2659 |
2702 // Generate store field code. Trashes the name register. | 2660 // Generate store field code. Trashes the name register. |
2703 GenerateStoreField(masm(), | 2661 GenerateStoreField(masm(), object, index, transition, edx, ecx, ebx, &miss); |
2704 object, | |
2705 index, | |
2706 transition, | |
2707 name, | |
2708 edx, ecx, ebx, edi, | |
2709 &miss); | |
2710 | 2662 |
2711 // Handle store cache miss. | 2663 // Handle store cache miss. |
2712 __ bind(&miss); | 2664 __ bind(&miss); |
2713 __ DecrementCounter(counters->keyed_store_field(), 1); | 2665 __ DecrementCounter(counters->keyed_store_field(), 1); |
2714 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2666 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
2715 __ jmp(ic, RelocInfo::CODE_TARGET); | 2667 __ jmp(ic, RelocInfo::CODE_TARGET); |
2716 | 2668 |
2717 // Return the generated code. | 2669 // Return the generated code. |
2718 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 2670 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
2719 } | 2671 } |
(...skipping 1433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4153 __ jmp(ic_slow, RelocInfo::CODE_TARGET); | 4105 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
4154 } | 4106 } |
4155 } | 4107 } |
4156 | 4108 |
4157 | 4109 |
4158 #undef __ | 4110 #undef __ |
4159 | 4111 |
4160 } } // namespace v8::internal | 4112 } } // namespace v8::internal |
4161 | 4113 |
4162 #endif // V8_TARGET_ARCH_IA32 | 4114 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |