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 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 __ Jump(code, RelocInfo::CODE_TARGET); | 724 __ Jump(code, RelocInfo::CODE_TARGET); |
725 } | 725 } |
726 | 726 |
727 | 727 |
728 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 728 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
729 // but may be destroyed if store is successful. | 729 // but may be destroyed if store is successful. |
730 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 730 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
731 Handle<JSObject> object, | 731 Handle<JSObject> object, |
732 int index, | 732 int index, |
733 Handle<Map> transition, | 733 Handle<Map> transition, |
734 Handle<String> name, | |
735 Register receiver_reg, | 734 Register receiver_reg, |
736 Register name_reg, | 735 Register name_reg, |
737 Register scratch1, | 736 Register scratch, |
738 Register scratch2, | |
739 Label* miss_label) { | 737 Label* miss_label) { |
740 LookupResult lookup(masm->isolate()); | |
741 object->Lookup(*name, &lookup); | |
742 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { | |
743 // In sloppy mode, we could just return the value and be done. However, we | |
744 // might be in strict mode, where we have to throw. Since we cannot tell, | |
745 // go into slow case unconditionally. | |
746 __ jmp(miss_label); | |
747 return; | |
748 } | |
749 | |
750 // Check that the map of the object hasn't changed. | 738 // Check that the map of the object hasn't changed. |
751 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | 739 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS |
752 : REQUIRE_EXACT_MAP; | 740 : REQUIRE_EXACT_MAP; |
753 __ CheckMap(receiver_reg, Handle<Map>(object->map()), | 741 __ CheckMap(receiver_reg, Handle<Map>(object->map()), |
754 miss_label, DO_SMI_CHECK, mode); | 742 miss_label, DO_SMI_CHECK, mode); |
755 | 743 |
756 // Perform global security token check if needed. | 744 // Perform global security token check if needed. |
757 if (object->IsJSGlobalProxy()) { | 745 if (object->IsJSGlobalProxy()) { |
758 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | 746 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); |
759 } | |
760 | |
761 // Check that we are allowed to write this. | |
762 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { | |
763 JSObject* holder; | |
764 if (lookup.IsFound()) { | |
765 holder = lookup.holder(); | |
766 } else { | |
767 // Find the top object. | |
768 holder = *object; | |
769 do { | |
770 holder = JSObject::cast(holder->GetPrototype()); | |
771 } while (holder->GetPrototype()->IsJSObject()); | |
772 } | |
773 // We need an extra register, push | |
774 __ push(name_reg); | |
775 Label miss_pop, done_check; | |
776 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, | |
777 scratch1, scratch2, name, &miss_pop); | |
778 __ jmp(&done_check); | |
779 __ bind(&miss_pop); | |
780 __ pop(name_reg); | |
781 __ jmp(miss_label); | |
782 __ bind(&done_check); | |
783 __ pop(name_reg); | |
784 } | 747 } |
785 | 748 |
786 // Stub never generated for non-global objects that require access | 749 // Stub never generated for non-global objects that require access |
787 // checks. | 750 // checks. |
788 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 751 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
789 | 752 |
790 // Perform map transition for the receiver if necessary. | 753 // Perform map transition for the receiver if necessary. |
791 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 754 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { |
792 // The properties must be extended before we can store the value. | 755 // The properties must be extended before we can store the value. |
793 // We jump to a runtime call that extends the properties array. | 756 // We jump to a runtime call that extends the properties array. |
794 __ pop(scratch1); // Return address. | 757 __ pop(scratch); // Return address. |
795 __ push(receiver_reg); | 758 __ push(receiver_reg); |
796 __ Push(transition); | 759 __ Push(transition); |
797 __ push(rax); | 760 __ push(rax); |
798 __ push(scratch1); | 761 __ push(scratch); |
799 __ TailCallExternalReference( | 762 __ TailCallExternalReference( |
800 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 763 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
801 masm->isolate()), | 764 masm->isolate()), |
802 3, | 765 3, |
803 1); | 766 1); |
804 return; | 767 return; |
805 } | 768 } |
806 | 769 |
807 if (!transition.is_null()) { | 770 if (!transition.is_null()) { |
808 // Update the map of the object. | 771 // Update the map of the object. |
809 __ Move(scratch1, transition); | 772 __ Move(scratch, transition); |
810 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); | 773 __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch); |
811 | 774 |
812 // Update the write barrier for the map field and pass the now unused | 775 // Update the write barrier for the map field and pass the now unused |
813 // name_reg as scratch register. | 776 // name_reg as scratch register. |
814 __ RecordWriteField(receiver_reg, | 777 __ RecordWriteField(receiver_reg, |
815 HeapObject::kMapOffset, | 778 HeapObject::kMapOffset, |
816 scratch1, | 779 scratch, |
817 name_reg, | 780 name_reg, |
818 kDontSaveFPRegs, | 781 kDontSaveFPRegs, |
819 OMIT_REMEMBERED_SET, | 782 OMIT_REMEMBERED_SET, |
820 OMIT_SMI_CHECK); | 783 OMIT_SMI_CHECK); |
821 } | 784 } |
822 | 785 |
823 // Adjust for the number of properties stored in the object. Even in the | 786 // Adjust for the number of properties stored in the object. Even in the |
824 // face of a transition we can use the old map here because the size of the | 787 // face of a transition we can use the old map here because the size of the |
825 // object and the number of in-object properties is not going to change. | 788 // object and the number of in-object properties is not going to change. |
826 index -= object->map()->inobject_properties(); | 789 index -= object->map()->inobject_properties(); |
827 | 790 |
828 if (index < 0) { | 791 if (index < 0) { |
829 // Set the property straight into the object. | 792 // Set the property straight into the object. |
830 int offset = object->map()->instance_size() + (index * kPointerSize); | 793 int offset = object->map()->instance_size() + (index * kPointerSize); |
831 __ movq(FieldOperand(receiver_reg, offset), rax); | 794 __ movq(FieldOperand(receiver_reg, offset), rax); |
832 | 795 |
833 // Update the write barrier for the array address. | 796 // Update the write barrier for the array address. |
834 // Pass the value being stored in the now unused name_reg. | 797 // Pass the value being stored in the now unused name_reg. |
835 __ movq(name_reg, rax); | 798 __ movq(name_reg, rax); |
836 __ RecordWriteField( | 799 __ RecordWriteField( |
837 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs); | 800 receiver_reg, offset, name_reg, scratch, kDontSaveFPRegs); |
838 } else { | 801 } else { |
839 // Write to the properties array. | 802 // Write to the properties array. |
840 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 803 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
841 // Get the properties array (optimistically). | 804 // Get the properties array (optimistically). |
842 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); | 805 __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); |
843 __ movq(FieldOperand(scratch1, offset), rax); | 806 __ movq(FieldOperand(scratch, offset), rax); |
844 | 807 |
845 // Update the write barrier for the array address. | 808 // Update the write barrier for the array address. |
846 // Pass the value being stored in the now unused name_reg. | 809 // Pass the value being stored in the now unused name_reg. |
847 __ movq(name_reg, rax); | 810 __ movq(name_reg, rax); |
848 __ RecordWriteField( | 811 __ RecordWriteField( |
849 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs); | 812 scratch, offset, name_reg, receiver_reg, kDontSaveFPRegs); |
850 } | 813 } |
851 | 814 |
852 // Return the value (register rax). | 815 // Return the value (register rax). |
853 __ ret(0); | 816 __ ret(0); |
854 } | 817 } |
855 | 818 |
856 | 819 |
857 // Generate code to check that a global property cell is empty. Create | 820 // Generate code to check that a global property cell is empty. Create |
858 // the property cell at compilation time if no cell exists for the | 821 // the property cell at compilation time if no cell exists for the |
859 // property. | 822 // property. |
(...skipping 1491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2351 Handle<String> name) { | 2314 Handle<String> name) { |
2352 // ----------- S t a t e ------------- | 2315 // ----------- S t a t e ------------- |
2353 // -- rax : value | 2316 // -- rax : value |
2354 // -- rcx : name | 2317 // -- rcx : name |
2355 // -- rdx : receiver | 2318 // -- rdx : receiver |
2356 // -- rsp[0] : return address | 2319 // -- rsp[0] : return address |
2357 // ----------------------------------- | 2320 // ----------------------------------- |
2358 Label miss; | 2321 Label miss; |
2359 | 2322 |
2360 // Generate store field code. Preserves receiver and name on jump to miss. | 2323 // Generate store field code. Preserves receiver and name on jump to miss. |
2361 GenerateStoreField(masm(), | 2324 GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss); |
2362 object, | |
2363 index, | |
2364 transition, | |
2365 name, | |
2366 rdx, rcx, rbx, rdi, | |
2367 &miss); | |
2368 | 2325 |
2369 // Handle store cache miss. | 2326 // Handle store cache miss. |
2370 __ bind(&miss); | 2327 __ bind(&miss); |
2371 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); | 2328 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); |
2372 __ Jump(ic, RelocInfo::CODE_TARGET); | 2329 __ Jump(ic, RelocInfo::CODE_TARGET); |
2373 | 2330 |
2374 // Return the generated code. | 2331 // Return the generated code. |
2375 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 2332 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
2376 } | 2333 } |
2377 | 2334 |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2530 Label miss; | 2487 Label miss; |
2531 | 2488 |
2532 Counters* counters = isolate()->counters(); | 2489 Counters* counters = isolate()->counters(); |
2533 __ IncrementCounter(counters->keyed_store_field(), 1); | 2490 __ IncrementCounter(counters->keyed_store_field(), 1); |
2534 | 2491 |
2535 // Check that the name has not changed. | 2492 // Check that the name has not changed. |
2536 __ Cmp(rcx, name); | 2493 __ Cmp(rcx, name); |
2537 __ j(not_equal, &miss); | 2494 __ j(not_equal, &miss); |
2538 | 2495 |
2539 // Generate store field code. Preserves receiver and name on jump to miss. | 2496 // Generate store field code. Preserves receiver and name on jump to miss. |
2540 GenerateStoreField(masm(), | 2497 GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss); |
2541 object, | |
2542 index, | |
2543 transition, | |
2544 name, | |
2545 rdx, rcx, rbx, rdi, | |
2546 &miss); | |
2547 | 2498 |
2548 // Handle store cache miss. | 2499 // Handle store cache miss. |
2549 __ bind(&miss); | 2500 __ bind(&miss); |
2550 __ DecrementCounter(counters->keyed_store_field(), 1); | 2501 __ DecrementCounter(counters->keyed_store_field(), 1); |
2551 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2502 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
2552 __ Jump(ic, RelocInfo::CODE_TARGET); | 2503 __ Jump(ic, RelocInfo::CODE_TARGET); |
2553 | 2504 |
2554 // Return the generated code. | 2505 // Return the generated code. |
2555 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 2506 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
2556 } | 2507 } |
(...skipping 1354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3911 __ jmp(ic_slow, RelocInfo::CODE_TARGET); | 3862 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
3912 } | 3863 } |
3913 } | 3864 } |
3914 | 3865 |
3915 | 3866 |
3916 #undef __ | 3867 #undef __ |
3917 | 3868 |
3918 } } // namespace v8::internal | 3869 } } // namespace v8::internal |
3919 | 3870 |
3920 #endif // V8_TARGET_ARCH_X64 | 3871 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |