| 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 |