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, |
734 Register receiver_reg, | 735 Register receiver_reg, |
735 Register name_reg, | 736 Register name_reg, |
736 Register scratch, | 737 Register scratch1, |
| 738 Register scratch2, |
737 Label* miss_label) { | 739 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 |
738 // Check that the map of the object hasn't changed. | 750 // Check that the map of the object hasn't changed. |
739 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | 751 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS |
740 : REQUIRE_EXACT_MAP; | 752 : REQUIRE_EXACT_MAP; |
741 __ CheckMap(receiver_reg, Handle<Map>(object->map()), | 753 __ CheckMap(receiver_reg, Handle<Map>(object->map()), |
742 miss_label, DO_SMI_CHECK, mode); | 754 miss_label, DO_SMI_CHECK, mode); |
743 | 755 |
744 // Perform global security token check if needed. | 756 // Perform global security token check if needed. |
745 if (object->IsJSGlobalProxy()) { | 757 if (object->IsJSGlobalProxy()) { |
746 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); | 758 __ CheckAccessGlobalProxy(receiver_reg, scratch1, 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); |
747 } | 784 } |
748 | 785 |
749 // Stub never generated for non-global objects that require access | 786 // Stub never generated for non-global objects that require access |
750 // checks. | 787 // checks. |
751 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 788 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
752 | 789 |
753 // Perform map transition for the receiver if necessary. | 790 // Perform map transition for the receiver if necessary. |
754 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 791 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { |
755 // The properties must be extended before we can store the value. | 792 // The properties must be extended before we can store the value. |
756 // We jump to a runtime call that extends the properties array. | 793 // We jump to a runtime call that extends the properties array. |
757 __ pop(scratch); // Return address. | 794 __ pop(scratch1); // Return address. |
758 __ push(receiver_reg); | 795 __ push(receiver_reg); |
759 __ Push(transition); | 796 __ Push(transition); |
760 __ push(rax); | 797 __ push(rax); |
761 __ push(scratch); | 798 __ push(scratch1); |
762 __ TailCallExternalReference( | 799 __ TailCallExternalReference( |
763 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 800 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
764 masm->isolate()), | 801 masm->isolate()), |
765 3, | 802 3, |
766 1); | 803 1); |
767 return; | 804 return; |
768 } | 805 } |
769 | 806 |
770 if (!transition.is_null()) { | 807 if (!transition.is_null()) { |
771 // Update the map of the object; no write barrier updating is | 808 // Update the map of the object; no write barrier updating is |
772 // needed because the map is never in new space. | 809 // needed because the map is never in new space. |
773 __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset), transition); | 810 __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset), transition); |
774 } | 811 } |
775 | 812 |
776 // Adjust for the number of properties stored in the object. Even in the | 813 // Adjust for the number of properties stored in the object. Even in the |
777 // face of a transition we can use the old map here because the size of the | 814 // face of a transition we can use the old map here because the size of the |
778 // object and the number of in-object properties is not going to change. | 815 // object and the number of in-object properties is not going to change. |
779 index -= object->map()->inobject_properties(); | 816 index -= object->map()->inobject_properties(); |
780 | 817 |
781 if (index < 0) { | 818 if (index < 0) { |
782 // Set the property straight into the object. | 819 // Set the property straight into the object. |
783 int offset = object->map()->instance_size() + (index * kPointerSize); | 820 int offset = object->map()->instance_size() + (index * kPointerSize); |
784 __ movq(FieldOperand(receiver_reg, offset), rax); | 821 __ movq(FieldOperand(receiver_reg, offset), rax); |
785 | 822 |
786 // Update the write barrier for the array address. | 823 // Update the write barrier for the array address. |
787 // Pass the value being stored in the now unused name_reg. | 824 // Pass the value being stored in the now unused name_reg. |
788 __ movq(name_reg, rax); | 825 __ movq(name_reg, rax); |
789 __ RecordWriteField( | 826 __ RecordWriteField( |
790 receiver_reg, offset, name_reg, scratch, kDontSaveFPRegs); | 827 receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs); |
791 } else { | 828 } else { |
792 // Write to the properties array. | 829 // Write to the properties array. |
793 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 830 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
794 // Get the properties array (optimistically). | 831 // Get the properties array (optimistically). |
795 __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); | 832 __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); |
796 __ movq(FieldOperand(scratch, offset), rax); | 833 __ movq(FieldOperand(scratch1, offset), rax); |
797 | 834 |
798 // Update the write barrier for the array address. | 835 // Update the write barrier for the array address. |
799 // Pass the value being stored in the now unused name_reg. | 836 // Pass the value being stored in the now unused name_reg. |
800 __ movq(name_reg, rax); | 837 __ movq(name_reg, rax); |
801 __ RecordWriteField( | 838 __ RecordWriteField( |
802 scratch, offset, name_reg, receiver_reg, kDontSaveFPRegs); | 839 scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs); |
803 } | 840 } |
804 | 841 |
805 // Return the value (register rax). | 842 // Return the value (register rax). |
806 __ ret(0); | 843 __ ret(0); |
807 } | 844 } |
808 | 845 |
809 | 846 |
810 // Generate code to check that a global property cell is empty. Create | 847 // Generate code to check that a global property cell is empty. Create |
811 // the property cell at compilation time if no cell exists for the | 848 // the property cell at compilation time if no cell exists for the |
812 // property. | 849 // property. |
(...skipping 1476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2289 Handle<String> name) { | 2326 Handle<String> name) { |
2290 // ----------- S t a t e ------------- | 2327 // ----------- S t a t e ------------- |
2291 // -- rax : value | 2328 // -- rax : value |
2292 // -- rcx : name | 2329 // -- rcx : name |
2293 // -- rdx : receiver | 2330 // -- rdx : receiver |
2294 // -- rsp[0] : return address | 2331 // -- rsp[0] : return address |
2295 // ----------------------------------- | 2332 // ----------------------------------- |
2296 Label miss; | 2333 Label miss; |
2297 | 2334 |
2298 // Generate store field code. Preserves receiver and name on jump to miss. | 2335 // Generate store field code. Preserves receiver and name on jump to miss. |
2299 GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss); | 2336 GenerateStoreField(masm(), |
| 2337 object, |
| 2338 index, |
| 2339 transition, |
| 2340 name, |
| 2341 rdx, rcx, rbx, rdi, |
| 2342 &miss); |
2300 | 2343 |
2301 // Handle store cache miss. | 2344 // Handle store cache miss. |
2302 __ bind(&miss); | 2345 __ bind(&miss); |
2303 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); | 2346 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); |
2304 __ Jump(ic, RelocInfo::CODE_TARGET); | 2347 __ Jump(ic, RelocInfo::CODE_TARGET); |
2305 | 2348 |
2306 // Return the generated code. | 2349 // Return the generated code. |
2307 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 2350 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
2308 } | 2351 } |
2309 | 2352 |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2462 Label miss; | 2505 Label miss; |
2463 | 2506 |
2464 Counters* counters = isolate()->counters(); | 2507 Counters* counters = isolate()->counters(); |
2465 __ IncrementCounter(counters->keyed_store_field(), 1); | 2508 __ IncrementCounter(counters->keyed_store_field(), 1); |
2466 | 2509 |
2467 // Check that the name has not changed. | 2510 // Check that the name has not changed. |
2468 __ Cmp(rcx, name); | 2511 __ Cmp(rcx, name); |
2469 __ j(not_equal, &miss); | 2512 __ j(not_equal, &miss); |
2470 | 2513 |
2471 // Generate store field code. Preserves receiver and name on jump to miss. | 2514 // Generate store field code. Preserves receiver and name on jump to miss. |
2472 GenerateStoreField(masm(), object, index, transition, rdx, rcx, rbx, &miss); | 2515 GenerateStoreField(masm(), |
| 2516 object, |
| 2517 index, |
| 2518 transition, |
| 2519 name, |
| 2520 rdx, rcx, rbx, rdi, |
| 2521 &miss); |
2473 | 2522 |
2474 // Handle store cache miss. | 2523 // Handle store cache miss. |
2475 __ bind(&miss); | 2524 __ bind(&miss); |
2476 __ DecrementCounter(counters->keyed_store_field(), 1); | 2525 __ DecrementCounter(counters->keyed_store_field(), 1); |
2477 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2526 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
2478 __ Jump(ic, RelocInfo::CODE_TARGET); | 2527 __ Jump(ic, RelocInfo::CODE_TARGET); |
2479 | 2528 |
2480 // Return the generated code. | 2529 // Return the generated code. |
2481 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 2530 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
2482 } | 2531 } |
(...skipping 1348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3831 __ jmp(ic_slow, RelocInfo::CODE_TARGET); | 3880 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
3832 } | 3881 } |
3833 } | 3882 } |
3834 | 3883 |
3835 | 3884 |
3836 #undef __ | 3885 #undef __ |
3837 | 3886 |
3838 } } // namespace v8::internal | 3887 } } // namespace v8::internal |
3839 | 3888 |
3840 #endif // V8_TARGET_ARCH_X64 | 3889 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |