Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 8 | 8 |
| 9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 10 #include "src/ic-inl.h" | 10 #include "src/ic-inl.h" |
| (...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 560 static void KeyedStoreGenerateGenericHelper( | 560 static void KeyedStoreGenerateGenericHelper( |
| 561 MacroAssembler* masm, | 561 MacroAssembler* masm, |
| 562 Label* fast_object, | 562 Label* fast_object, |
| 563 Label* fast_double, | 563 Label* fast_double, |
| 564 Label* slow, | 564 Label* slow, |
| 565 KeyedStoreCheckMap check_map, | 565 KeyedStoreCheckMap check_map, |
| 566 KeyedStoreIncrementLength increment_length) { | 566 KeyedStoreIncrementLength increment_length) { |
| 567 Label transition_smi_elements; | 567 Label transition_smi_elements; |
| 568 Label finish_object_store, non_double_value, transition_double_elements; | 568 Label finish_object_store, non_double_value, transition_double_elements; |
| 569 Label fast_double_without_map_check; | 569 Label fast_double_without_map_check; |
| 570 Register receiver = KeyedStoreIC::ReceiverRegister(); | |
| 571 Register key = KeyedStoreIC::NameRegister(); | |
| 572 Register value = KeyedStoreIC::ValueRegister(); | |
| 573 ASSERT(receiver.is(rdx)); | |
| 574 ASSERT(key.is(rcx)); | |
| 575 ASSERT(value.is(rax)); | |
| 570 // Fast case: Do the store, could be either Object or double. | 576 // Fast case: Do the store, could be either Object or double. |
| 571 __ bind(fast_object); | 577 __ bind(fast_object); |
| 572 // rax: value | |
| 573 // rbx: receiver's elements array (a FixedArray) | 578 // rbx: receiver's elements array (a FixedArray) |
| 574 // rcx: index | 579 // receiver is a JSArray. |
| 575 // rdx: receiver (a JSArray) | |
| 576 // r9: map of receiver | 580 // r9: map of receiver |
| 577 if (check_map == kCheckMap) { | 581 if (check_map == kCheckMap) { |
| 578 __ movp(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); | 582 __ movp(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); |
| 579 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); | 583 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); |
| 580 __ j(not_equal, fast_double); | 584 __ j(not_equal, fast_double); |
| 581 } | 585 } |
| 582 | 586 |
| 583 // HOLECHECK: guards "A[i] = V" | 587 // HOLECHECK: guards "A[i] = V" |
| 584 // We have to go to the runtime if the current value is the hole because | 588 // We have to go to the runtime if the current value is the hole because |
| 585 // there may be a callback on the element | 589 // there may be a callback on the element |
| 586 Label holecheck_passed1; | 590 Label holecheck_passed1; |
| 587 __ movp(kScratchRegister, FieldOperand(rbx, | 591 __ movp(kScratchRegister, FieldOperand(rbx, |
| 588 rcx, | 592 key, |
| 589 times_pointer_size, | 593 times_pointer_size, |
| 590 FixedArray::kHeaderSize)); | 594 FixedArray::kHeaderSize)); |
| 591 __ CompareRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 595 __ CompareRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 592 __ j(not_equal, &holecheck_passed1); | 596 __ j(not_equal, &holecheck_passed1); |
| 593 __ JumpIfDictionaryInPrototypeChain(rdx, rdi, kScratchRegister, slow); | 597 __ JumpIfDictionaryInPrototypeChain(receiver, rdi, kScratchRegister, slow); |
| 594 | 598 |
| 595 __ bind(&holecheck_passed1); | 599 __ bind(&holecheck_passed1); |
| 596 | 600 |
| 597 // Smi stores don't require further checks. | 601 // Smi stores don't require further checks. |
| 598 Label non_smi_value; | 602 Label non_smi_value; |
| 599 __ JumpIfNotSmi(rax, &non_smi_value); | 603 __ JumpIfNotSmi(value, &non_smi_value); |
| 600 if (increment_length == kIncrementLength) { | 604 if (increment_length == kIncrementLength) { |
| 601 // Add 1 to receiver->length. | 605 // Add 1 to receiver->length. |
| 602 __ leal(rdi, Operand(rcx, 1)); | 606 __ leal(rdi, Operand(key, 1)); |
| 603 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); | 607 __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi); |
| 604 } | 608 } |
| 605 // It's irrelevant whether array is smi-only or not when writing a smi. | 609 // It's irrelevant whether array is smi-only or not when writing a smi. |
| 606 __ movp(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), | 610 __ movp(FieldOperand(rbx, key, times_pointer_size, FixedArray::kHeaderSize), |
| 607 rax); | 611 value); |
| 608 __ ret(0); | 612 __ ret(0); |
| 609 | 613 |
| 610 __ bind(&non_smi_value); | 614 __ bind(&non_smi_value); |
| 611 // Writing a non-smi, check whether array allows non-smi elements. | 615 // Writing a non-smi, check whether array allows non-smi elements. |
| 612 // r9: receiver's map | 616 // r9: receiver's map |
| 613 __ CheckFastObjectElements(r9, &transition_smi_elements); | 617 __ CheckFastObjectElements(r9, &transition_smi_elements); |
| 614 | 618 |
| 615 __ bind(&finish_object_store); | 619 __ bind(&finish_object_store); |
| 616 if (increment_length == kIncrementLength) { | 620 if (increment_length == kIncrementLength) { |
| 617 // Add 1 to receiver->length. | 621 // Add 1 to receiver->length. |
| 618 __ leal(rdi, Operand(rcx, 1)); | 622 __ leal(rdi, Operand(key, 1)); |
| 619 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); | 623 __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi); |
| 620 } | 624 } |
| 621 __ movp(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), | 625 __ movp(FieldOperand(rbx, key, times_pointer_size, FixedArray::kHeaderSize), |
| 622 rax); | 626 value); |
| 623 __ movp(rdx, rax); // Preserve the value which is returned. | 627 __ movp(rdx, value); // Preserve the value which is returned. |
| 624 __ RecordWriteArray( | 628 __ RecordWriteArray( |
| 625 rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 629 rbx, rdx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 626 __ ret(0); | 630 __ ret(0); |
| 627 | 631 |
| 628 __ bind(fast_double); | 632 __ bind(fast_double); |
| 629 if (check_map == kCheckMap) { | 633 if (check_map == kCheckMap) { |
| 630 // Check for fast double array case. If this fails, call through to the | 634 // Check for fast double array case. If this fails, call through to the |
| 631 // runtime. | 635 // runtime. |
| 632 // rdi: elements array's map | 636 // rdi: elements array's map |
| 633 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); | 637 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); |
| 634 __ j(not_equal, slow); | 638 __ j(not_equal, slow); |
| 635 } | 639 } |
| 636 | 640 |
| 637 // HOLECHECK: guards "A[i] double hole?" | 641 // HOLECHECK: guards "A[i] double hole?" |
| 638 // We have to see if the double version of the hole is present. If so | 642 // We have to see if the double version of the hole is present. If so |
| 639 // go to the runtime. | 643 // go to the runtime. |
| 640 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); | 644 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); |
| 641 __ cmpl(FieldOperand(rbx, rcx, times_8, offset), Immediate(kHoleNanUpper32)); | 645 __ cmpl(FieldOperand(rbx, key, times_8, offset), Immediate(kHoleNanUpper32)); |
| 642 __ j(not_equal, &fast_double_without_map_check); | 646 __ j(not_equal, &fast_double_without_map_check); |
| 643 __ JumpIfDictionaryInPrototypeChain(rdx, rdi, kScratchRegister, slow); | 647 __ JumpIfDictionaryInPrototypeChain(receiver, rdi, kScratchRegister, slow); |
| 644 | 648 |
| 645 __ bind(&fast_double_without_map_check); | 649 __ bind(&fast_double_without_map_check); |
| 646 __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0, | 650 __ StoreNumberToDoubleElements(value, rbx, key, xmm0, |
| 647 &transition_double_elements); | 651 &transition_double_elements); |
| 648 if (increment_length == kIncrementLength) { | 652 if (increment_length == kIncrementLength) { |
| 649 // Add 1 to receiver->length. | 653 // Add 1 to receiver->length. |
| 650 __ leal(rdi, Operand(rcx, 1)); | 654 __ leal(rdi, Operand(key, 1)); |
| 651 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); | 655 __ Integer32ToSmiField(FieldOperand(receiver, JSArray::kLengthOffset), rdi); |
| 652 } | 656 } |
| 653 __ ret(0); | 657 __ ret(0); |
| 654 | 658 |
| 655 __ bind(&transition_smi_elements); | 659 __ bind(&transition_smi_elements); |
| 656 __ movp(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | 660 __ movp(rbx, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 657 | 661 |
| 658 // Transition the array appropriately depending on the value type. | 662 // Transition the array appropriately depending on the value type. |
| 659 __ movp(r9, FieldOperand(rax, HeapObject::kMapOffset)); | 663 __ movp(r9, FieldOperand(value, HeapObject::kMapOffset)); |
| 660 __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex); | 664 __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex); |
| 661 __ j(not_equal, &non_double_value); | 665 __ j(not_equal, &non_double_value); |
| 662 | 666 |
| 663 // Value is a double. Transition FAST_SMI_ELEMENTS -> | 667 // Value is a double. Transition FAST_SMI_ELEMENTS -> |
| 664 // FAST_DOUBLE_ELEMENTS and complete the store. | 668 // FAST_DOUBLE_ELEMENTS and complete the store. |
| 665 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | 669 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, |
| 666 FAST_DOUBLE_ELEMENTS, | 670 FAST_DOUBLE_ELEMENTS, |
| 667 rbx, | 671 rbx, |
| 668 rdi, | 672 rdi, |
| 669 slow); | 673 slow); |
| 670 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, | 674 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, |
| 671 FAST_DOUBLE_ELEMENTS); | 675 FAST_DOUBLE_ELEMENTS); |
| 672 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow); | 676 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow); |
| 673 __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | 677 __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 674 __ jmp(&fast_double_without_map_check); | 678 __ jmp(&fast_double_without_map_check); |
| 675 | 679 |
| 676 __ bind(&non_double_value); | 680 __ bind(&non_double_value); |
| 677 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS | 681 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS |
| 678 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | 682 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, |
| 679 FAST_ELEMENTS, | 683 FAST_ELEMENTS, |
| 680 rbx, | 684 rbx, |
| 681 rdi, | 685 rdi, |
| 682 slow); | 686 slow); |
| 683 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); | 687 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); |
| 684 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode, | 688 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode, |
| 685 slow); | 689 slow); |
| 686 __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | 690 __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 687 __ jmp(&finish_object_store); | 691 __ jmp(&finish_object_store); |
| 688 | 692 |
| 689 __ bind(&transition_double_elements); | 693 __ bind(&transition_double_elements); |
| 690 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a | 694 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a |
| 691 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and | 695 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and |
| 692 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS | 696 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS |
| 693 __ movp(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | 697 __ movp(rbx, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 694 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, | 698 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, |
| 695 FAST_ELEMENTS, | 699 FAST_ELEMENTS, |
| 696 rbx, | 700 rbx, |
| 697 rdi, | 701 rdi, |
| 698 slow); | 702 slow); |
| 699 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); | 703 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); |
| 700 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow); | 704 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow); |
| 701 __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | 705 __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 702 __ jmp(&finish_object_store); | 706 __ jmp(&finish_object_store); |
| 703 } | 707 } |
| 704 | 708 |
| 705 | 709 |
| 706 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, | 710 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, |
| 707 StrictMode strict_mode) { | 711 StrictMode strict_mode) { |
| 708 // ----------- S t a t e ------------- | 712 // Return address is on the stack. |
| 709 // -- rax : value | |
| 710 // -- rcx : key | |
| 711 // -- rdx : receiver | |
| 712 // -- rsp[0] : return address | |
| 713 // ----------------------------------- | |
| 714 Label slow, slow_with_tagged_index, fast_object, fast_object_grow; | 713 Label slow, slow_with_tagged_index, fast_object, fast_object_grow; |
| 715 Label fast_double, fast_double_grow; | 714 Label fast_double, fast_double_grow; |
| 716 Label array, extra, check_if_double_array; | 715 Label array, extra, check_if_double_array; |
| 716 Register receiver = ReceiverRegister(); | |
| 717 Register key = NameRegister(); | |
| 718 ASSERT(receiver.is(rdx)); | |
| 719 ASSERT(key.is(rcx)); | |
| 717 | 720 |
| 718 // Check that the object isn't a smi. | 721 // Check that the object isn't a smi. |
| 719 __ JumpIfSmi(rdx, &slow_with_tagged_index); | 722 __ JumpIfSmi(receiver, &slow_with_tagged_index); |
| 720 // Get the map from the receiver. | 723 // Get the map from the receiver. |
| 721 __ movp(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | 724 __ movp(r9, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 722 // Check that the receiver does not require access checks and is not observed. | 725 // Check that the receiver does not require access checks and is not observed. |
| 723 // The generic stub does not perform map checks or handle observed objects. | 726 // The generic stub does not perform map checks or handle observed objects. |
| 724 __ testb(FieldOperand(r9, Map::kBitFieldOffset), | 727 __ testb(FieldOperand(r9, Map::kBitFieldOffset), |
| 725 Immediate(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved)); | 728 Immediate(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved)); |
| 726 __ j(not_zero, &slow_with_tagged_index); | 729 __ j(not_zero, &slow_with_tagged_index); |
| 727 // Check that the key is a smi. | 730 // Check that the key is a smi. |
| 728 __ JumpIfNotSmi(rcx, &slow_with_tagged_index); | 731 __ JumpIfNotSmi(key, &slow_with_tagged_index); |
| 729 __ SmiToInteger32(rcx, rcx); | 732 __ SmiToInteger32(key, key); |
| 730 | 733 |
| 731 __ CmpInstanceType(r9, JS_ARRAY_TYPE); | 734 __ CmpInstanceType(r9, JS_ARRAY_TYPE); |
| 732 __ j(equal, &array); | 735 __ j(equal, &array); |
| 733 // Check that the object is some kind of JSObject. | 736 // Check that the object is some kind of JSObject. |
| 734 __ CmpInstanceType(r9, FIRST_JS_OBJECT_TYPE); | 737 __ CmpInstanceType(r9, FIRST_JS_OBJECT_TYPE); |
| 735 __ j(below, &slow); | 738 __ j(below, &slow); |
| 736 | 739 |
| 737 // Object case: Check key against length in the elements array. | 740 // Object case: Check key against length in the elements array. |
| 738 // rax: value | 741 __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 739 // rdx: JSObject | |
| 740 // rcx: index | |
| 741 __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
| 742 // Check array bounds. | 742 // Check array bounds. |
| 743 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx); | 743 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), key); |
| 744 // rax: value | |
| 745 // rbx: FixedArray | 744 // rbx: FixedArray |
| 746 // rcx: index | |
| 747 __ j(above, &fast_object); | 745 __ j(above, &fast_object); |
| 748 | 746 |
| 749 // Slow case: call runtime. | 747 // Slow case: call runtime. |
| 750 __ bind(&slow); | 748 __ bind(&slow); |
| 751 __ Integer32ToSmi(rcx, rcx); | 749 __ Integer32ToSmi(key, key); |
| 752 __ bind(&slow_with_tagged_index); | 750 __ bind(&slow_with_tagged_index); |
| 753 GenerateRuntimeSetProperty(masm, strict_mode); | 751 GenerateRuntimeSetProperty(masm, strict_mode); |
| 754 // Never returns to here. | 752 // Never returns to here. |
| 755 | 753 |
| 756 // Extra capacity case: Check if there is extra capacity to | 754 // Extra capacity case: Check if there is extra capacity to |
| 757 // perform the store and update the length. Used for adding one | 755 // perform the store and update the length. Used for adding one |
| 758 // element to the array by writing to array[array.length]. | 756 // element to the array by writing to array[array.length]. |
| 759 __ bind(&extra); | 757 __ bind(&extra); |
| 760 // rax: value | 758 // receiver is a JSArray. |
| 761 // rdx: receiver (a JSArray) | |
| 762 // rbx: receiver's elements array (a FixedArray) | 759 // rbx: receiver's elements array (a FixedArray) |
| 763 // rcx: index | 760 // flags: smicompare (receiver.length(), rbx) |
| 764 // flags: smicompare (rdx.length(), rbx) | |
| 765 __ j(not_equal, &slow); // do not leave holes in the array | 761 __ j(not_equal, &slow); // do not leave holes in the array |
| 766 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx); | 762 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), key); |
| 767 __ j(below_equal, &slow); | 763 __ j(below_equal, &slow); |
| 768 // Increment index to get new length. | 764 // Increment index to get new length. |
| 769 __ movp(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); | 765 __ movp(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); |
| 770 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); | 766 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); |
| 771 __ j(not_equal, &check_if_double_array); | 767 __ j(not_equal, &check_if_double_array); |
| 772 __ jmp(&fast_object_grow); | 768 __ jmp(&fast_object_grow); |
| 773 | 769 |
| 774 __ bind(&check_if_double_array); | 770 __ bind(&check_if_double_array); |
| 775 // rdi: elements array's map | 771 // rdi: elements array's map |
| 776 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); | 772 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); |
| 777 __ j(not_equal, &slow); | 773 __ j(not_equal, &slow); |
| 778 __ jmp(&fast_double_grow); | 774 __ jmp(&fast_double_grow); |
| 779 | 775 |
| 780 // Array case: Get the length and the elements array from the JS | 776 // Array case: Get the length and the elements array from the JS |
| 781 // array. Check that the array is in fast mode (and writable); if it | 777 // array. Check that the array is in fast mode (and writable); if it |
| 782 // is the length is always a smi. | 778 // is the length is always a smi. |
| 783 __ bind(&array); | 779 __ bind(&array); |
| 784 // rax: value | 780 // receiver is a JSArray. |
| 785 // rdx: receiver (a JSArray) | 781 __ movp(rbx, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 786 // rcx: index | |
| 787 __ movp(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
| 788 | 782 |
| 789 // Check the key against the length in the array, compute the | 783 // Check the key against the length in the array, compute the |
| 790 // address to store into and fall through to fast case. | 784 // address to store into and fall through to fast case. |
| 791 __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx); | 785 __ SmiCompareInteger32(FieldOperand(receiver, JSArray::kLengthOffset), key); |
| 792 __ j(below_equal, &extra); | 786 __ j(below_equal, &extra); |
| 793 | 787 |
| 794 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, | 788 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, |
| 795 &slow, kCheckMap, kDontIncrementLength); | 789 &slow, kCheckMap, kDontIncrementLength); |
| 796 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, | 790 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, |
| 797 &slow, kDontCheckMap, kIncrementLength); | 791 &slow, kDontCheckMap, kIncrementLength); |
| 798 } | 792 } |
| 799 | 793 |
| 800 | 794 |
| 801 static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, | 795 static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 899 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex); | 893 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex); |
| 900 __ j(equal, &slow); | 894 __ j(equal, &slow); |
| 901 __ movp(rax, unmapped_location); | 895 __ movp(rax, unmapped_location); |
| 902 __ Ret(); | 896 __ Ret(); |
| 903 __ bind(&slow); | 897 __ bind(&slow); |
| 904 GenerateMiss(masm); | 898 GenerateMiss(masm); |
| 905 } | 899 } |
| 906 | 900 |
| 907 | 901 |
| 908 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) { | 902 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) { |
| 909 // ----------- S t a t e ------------- | 903 // ----------- S t a t e ------------- |
|
Jakob Kummerow
2014/07/10 13:42:05
just "// The return address is on the stack."
| |
| 910 // -- rax : value | 904 // -- rax : value |
| 911 // -- rcx : key | 905 // -- rcx : key |
| 912 // -- rdx : receiver | 906 // -- rdx : receiver |
| 913 // -- rsp[0] : return address | 907 // -- rsp[0] : return address |
| 914 // ----------------------------------- | 908 // ----------------------------------- |
| 915 Label slow, notin; | 909 Label slow, notin; |
| 910 Register receiver = ReceiverRegister(); | |
| 911 Register name = NameRegister(); | |
| 912 Register value = ValueRegister(); | |
| 913 ASSERT(receiver.is(rdx)); | |
| 914 ASSERT(name.is(rcx)); | |
| 915 ASSERT(value.is(rax)); | |
| 916 | |
| 916 Operand mapped_location = GenerateMappedArgumentsLookup( | 917 Operand mapped_location = GenerateMappedArgumentsLookup( |
| 917 masm, rdx, rcx, rbx, rdi, r8, ¬in, &slow); | 918 masm, receiver, name, rbx, rdi, r8, ¬in, &slow); |
| 918 __ movp(mapped_location, rax); | 919 __ movp(mapped_location, value); |
| 919 __ leap(r9, mapped_location); | 920 __ leap(r9, mapped_location); |
| 920 __ movp(r8, rax); | 921 __ movp(r8, value); |
| 921 __ RecordWrite(rbx, | 922 __ RecordWrite(rbx, |
| 922 r9, | 923 r9, |
| 923 r8, | 924 r8, |
| 924 kDontSaveFPRegs, | 925 kDontSaveFPRegs, |
| 925 EMIT_REMEMBERED_SET, | 926 EMIT_REMEMBERED_SET, |
| 926 INLINE_SMI_CHECK); | 927 INLINE_SMI_CHECK); |
| 927 __ Ret(); | 928 __ Ret(); |
| 928 __ bind(¬in); | 929 __ bind(¬in); |
| 929 // The unmapped lookup expects that the parameter map is in rbx. | 930 // The unmapped lookup expects that the parameter map is in rbx. |
| 930 Operand unmapped_location = | 931 Operand unmapped_location = |
| 931 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rdi, &slow); | 932 GenerateUnmappedArgumentsLookup(masm, name, rbx, rdi, &slow); |
| 932 __ movp(unmapped_location, rax); | 933 __ movp(unmapped_location, value); |
| 933 __ leap(r9, unmapped_location); | 934 __ leap(r9, unmapped_location); |
| 934 __ movp(r8, rax); | 935 __ movp(r8, value); |
| 935 __ RecordWrite(rbx, | 936 __ RecordWrite(rbx, |
| 936 r9, | 937 r9, |
| 937 r8, | 938 r8, |
| 938 kDontSaveFPRegs, | 939 kDontSaveFPRegs, |
| 939 EMIT_REMEMBERED_SET, | 940 EMIT_REMEMBERED_SET, |
| 940 INLINE_SMI_CHECK); | 941 INLINE_SMI_CHECK); |
| 941 __ Ret(); | 942 __ Ret(); |
| 942 __ bind(&slow); | 943 __ bind(&slow); |
| 943 GenerateMiss(masm); | 944 GenerateMiss(masm); |
| 944 } | 945 } |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1042 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); | 1043 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); |
| 1043 __ TailCallExternalReference(ref, 2, 1); | 1044 __ TailCallExternalReference(ref, 2, 1); |
| 1044 } | 1045 } |
| 1045 | 1046 |
| 1046 | 1047 |
| 1047 // IC register specifications | 1048 // IC register specifications |
| 1048 const Register LoadIC::ReceiverRegister() { return rdx; } | 1049 const Register LoadIC::ReceiverRegister() { return rdx; } |
| 1049 const Register LoadIC::NameRegister() { return rcx; } | 1050 const Register LoadIC::NameRegister() { return rcx; } |
| 1050 | 1051 |
| 1051 | 1052 |
| 1053 const Register StoreIC::ReceiverRegister() { return rdx; } | |
| 1054 const Register StoreIC::NameRegister() { return rcx; } | |
| 1055 const Register StoreIC::ValueRegister() { return rax; } | |
| 1056 | |
| 1057 | |
| 1058 const Register KeyedStoreIC::ReceiverRegister() { | |
| 1059 return StoreIC::ReceiverRegister(); | |
| 1060 } | |
| 1061 | |
| 1062 | |
| 1063 const Register KeyedStoreIC::NameRegister() { | |
| 1064 return StoreIC::NameRegister(); | |
| 1065 } | |
| 1066 | |
| 1067 | |
| 1068 const Register KeyedStoreIC::ValueRegister() { | |
| 1069 return StoreIC::ValueRegister(); | |
| 1070 } | |
| 1071 | |
| 1072 | |
| 1052 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 1073 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
| 1053 // The return address is on the stack. | 1074 // The return address is on the stack. |
| 1054 | 1075 |
| 1055 __ PopReturnAddressTo(KeyedLoadIC_TempRegister()); | 1076 __ PopReturnAddressTo(KeyedLoadIC_TempRegister()); |
| 1056 __ Push(ReceiverRegister()); // receiver | 1077 __ Push(ReceiverRegister()); // receiver |
| 1057 __ Push(NameRegister()); // name | 1078 __ Push(NameRegister()); // name |
| 1058 __ PushReturnAddressFrom(KeyedLoadIC_TempRegister()); | 1079 __ PushReturnAddressFrom(KeyedLoadIC_TempRegister()); |
| 1059 | 1080 |
| 1060 // Perform tail call to the entry. | 1081 // Perform tail call to the entry. |
| 1061 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 1082 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 1062 } | 1083 } |
| 1063 | 1084 |
| 1064 | 1085 |
| 1065 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { | 1086 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { |
| 1066 // ----------- S t a t e ------------- | 1087 // The return address is on the stack. |
| 1067 // -- rax : value | |
| 1068 // -- rcx : name | |
| 1069 // -- rdx : receiver | |
| 1070 // -- rsp[0] : return address | |
| 1071 // ----------------------------------- | |
| 1072 | 1088 |
| 1073 // Get the receiver from the stack and probe the stub cache. | 1089 // Get the receiver from the stack and probe the stub cache. |
| 1074 Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC); | 1090 Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC); |
| 1075 masm->isolate()->stub_cache()->GenerateProbe( | 1091 masm->isolate()->stub_cache()->GenerateProbe( |
| 1076 masm, flags, rdx, rcx, rbx, no_reg); | 1092 masm, flags, ReceiverRegister(), NameRegister(), rbx, no_reg); |
| 1077 | 1093 |
| 1078 // Cache miss: Jump to runtime. | 1094 // Cache miss: Jump to runtime. |
| 1079 GenerateMiss(masm); | 1095 GenerateMiss(masm); |
| 1080 } | 1096 } |
| 1081 | 1097 |
| 1082 | 1098 |
| 1083 void StoreIC::GenerateMiss(MacroAssembler* masm) { | 1099 static void StoreIC_PushArgs(MacroAssembler* masm) { |
| 1084 // ----------- S t a t e ------------- | 1100 Register receiver = StoreIC::ReceiverRegister(); |
| 1085 // -- rax : value | 1101 Register name = StoreIC::NameRegister(); |
| 1086 // -- rcx : name | 1102 Register value = StoreIC::ValueRegister(); |
| 1087 // -- rdx : receiver | 1103 |
| 1088 // -- rsp[0] : return address | 1104 ASSERT(!rbx.is(receiver) && !rbx.is(name) && !rbx.is(value)); |
| 1089 // ----------------------------------- | |
| 1090 | 1105 |
| 1091 __ PopReturnAddressTo(rbx); | 1106 __ PopReturnAddressTo(rbx); |
| 1092 __ Push(rdx); // receiver | 1107 __ Push(receiver); |
| 1093 __ Push(rcx); // name | 1108 __ Push(name); |
| 1094 __ Push(rax); // value | 1109 __ Push(value); |
| 1095 __ PushReturnAddressFrom(rbx); | 1110 __ PushReturnAddressFrom(rbx); |
| 1111 } | |
| 1112 | |
| 1113 | |
| 1114 void StoreIC::GenerateMiss(MacroAssembler* masm) { | |
| 1115 // Return address is on the stack. | |
| 1116 StoreIC_PushArgs(masm); | |
| 1096 | 1117 |
| 1097 // Perform tail call to the entry. | 1118 // Perform tail call to the entry. |
| 1098 ExternalReference ref = | 1119 ExternalReference ref = |
| 1099 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate()); | 1120 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate()); |
| 1100 __ TailCallExternalReference(ref, 3, 1); | 1121 __ TailCallExternalReference(ref, 3, 1); |
| 1101 } | 1122 } |
| 1102 | 1123 |
| 1103 | 1124 |
| 1104 void StoreIC::GenerateNormal(MacroAssembler* masm) { | 1125 void StoreIC::GenerateNormal(MacroAssembler* masm) { |
| 1105 // ----------- S t a t e ------------- | 1126 // Return address is on the stack. |
| 1106 // -- rax : value | 1127 Register receiver = ReceiverRegister(); |
| 1107 // -- rcx : name | 1128 Register name = NameRegister(); |
| 1108 // -- rdx : receiver | 1129 Register value = ValueRegister(); |
| 1109 // -- rsp[0] : return address | |
| 1110 // ----------------------------------- | |
| 1111 | 1130 |
| 1112 Label miss; | 1131 Label miss; |
| 1113 | 1132 |
| 1114 GenerateNameDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss); | 1133 GenerateNameDictionaryReceiverCheck(masm, receiver, rbx, rdi, &miss); |
| 1115 | 1134 |
| 1116 GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9); | 1135 GenerateDictionaryStore(masm, &miss, rbx, name, value, r8, r9); |
| 1117 Counters* counters = masm->isolate()->counters(); | 1136 Counters* counters = masm->isolate()->counters(); |
| 1118 __ IncrementCounter(counters->store_normal_hit(), 1); | 1137 __ IncrementCounter(counters->store_normal_hit(), 1); |
| 1119 __ ret(0); | 1138 __ ret(0); |
| 1120 | 1139 |
| 1121 __ bind(&miss); | 1140 __ bind(&miss); |
| 1122 __ IncrementCounter(counters->store_normal_miss(), 1); | 1141 __ IncrementCounter(counters->store_normal_miss(), 1); |
| 1123 GenerateMiss(masm); | 1142 GenerateMiss(masm); |
| 1124 } | 1143 } |
| 1125 | 1144 |
| 1126 | 1145 |
| 1127 void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, | 1146 void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, |
| 1128 StrictMode strict_mode) { | 1147 StrictMode strict_mode) { |
| 1129 // ----------- S t a t e ------------- | 1148 // Return address is on the stack. |
| 1130 // -- rax : value | 1149 ASSERT(!rbx.is(ReceiverRegister()) && !rbx.is(NameRegister()) && |
| 1131 // -- rcx : name | 1150 !rbx.is(ValueRegister())); |
| 1132 // -- rdx : receiver | 1151 |
| 1133 // -- rsp[0] : return address | |
| 1134 // ----------------------------------- | |
| 1135 __ PopReturnAddressTo(rbx); | 1152 __ PopReturnAddressTo(rbx); |
| 1136 __ Push(rdx); | 1153 __ Push(ReceiverRegister()); |
| 1137 __ Push(rcx); | 1154 __ Push(NameRegister()); |
| 1138 __ Push(rax); | 1155 __ Push(ValueRegister()); |
| 1139 __ Push(Smi::FromInt(strict_mode)); | 1156 __ Push(Smi::FromInt(strict_mode)); |
| 1140 __ PushReturnAddressFrom(rbx); | 1157 __ PushReturnAddressFrom(rbx); |
| 1141 | 1158 |
| 1142 // Do tail-call to runtime routine. | 1159 // Do tail-call to runtime routine. |
| 1143 __ TailCallRuntime(Runtime::kSetProperty, 4, 1); | 1160 __ TailCallRuntime(Runtime::kSetProperty, 4, 1); |
| 1144 } | 1161 } |
| 1145 | 1162 |
| 1146 | 1163 |
| 1147 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, | 1164 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, |
| 1148 StrictMode strict_mode) { | 1165 StrictMode strict_mode) { |
| 1149 // ----------- S t a t e ------------- | 1166 // Return address is on the stack. |
| 1150 // -- rax : value | 1167 ASSERT(!rbx.is(ReceiverRegister()) && !rbx.is(NameRegister()) && |
| 1151 // -- rcx : key | 1168 !rbx.is(ValueRegister())); |
| 1152 // -- rdx : receiver | |
| 1153 // -- rsp[0] : return address | |
| 1154 // ----------------------------------- | |
| 1155 | 1169 |
| 1156 __ PopReturnAddressTo(rbx); | 1170 __ PopReturnAddressTo(rbx); |
| 1157 __ Push(rdx); // receiver | 1171 __ Push(ReceiverRegister()); |
| 1158 __ Push(rcx); // key | 1172 __ Push(NameRegister()); |
| 1159 __ Push(rax); // value | 1173 __ Push(ValueRegister()); |
| 1160 __ Push(Smi::FromInt(strict_mode)); // Strict mode. | 1174 __ Push(Smi::FromInt(strict_mode)); // Strict mode. |
| 1161 __ PushReturnAddressFrom(rbx); | 1175 __ PushReturnAddressFrom(rbx); |
| 1162 | 1176 |
| 1163 // Do tail-call to runtime routine. | 1177 // Do tail-call to runtime routine. |
| 1164 __ TailCallRuntime(Runtime::kSetProperty, 4, 1); | 1178 __ TailCallRuntime(Runtime::kSetProperty, 4, 1); |
| 1165 } | 1179 } |
| 1166 | 1180 |
| 1167 | 1181 |
| 1168 void StoreIC::GenerateSlow(MacroAssembler* masm) { | 1182 void StoreIC::GenerateSlow(MacroAssembler* masm) { |
| 1169 // ----------- S t a t e ------------- | 1183 // Return address is on the stack. |
| 1170 // -- rax : value | 1184 StoreIC_PushArgs(masm); |
| 1171 // -- rcx : key | |
| 1172 // -- rdx : receiver | |
| 1173 // -- rsp[0] : return address | |
| 1174 // ----------------------------------- | |
| 1175 | |
| 1176 __ PopReturnAddressTo(rbx); | |
| 1177 __ Push(rdx); // receiver | |
| 1178 __ Push(rcx); // key | |
| 1179 __ Push(rax); // value | |
| 1180 __ PushReturnAddressFrom(rbx); | |
| 1181 | 1185 |
| 1182 // Do tail-call to runtime routine. | 1186 // Do tail-call to runtime routine. |
| 1183 ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate()); | 1187 ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate()); |
| 1184 __ TailCallExternalReference(ref, 3, 1); | 1188 __ TailCallExternalReference(ref, 3, 1); |
| 1185 } | 1189 } |
| 1186 | 1190 |
| 1187 | 1191 |
| 1188 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { | 1192 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { |
| 1189 // ----------- S t a t e ------------- | 1193 // Return address is on the stack. |
| 1190 // -- rax : value | 1194 StoreIC_PushArgs(masm); |
| 1191 // -- rcx : key | |
| 1192 // -- rdx : receiver | |
| 1193 // -- rsp[0] : return address | |
| 1194 // ----------------------------------- | |
| 1195 | |
| 1196 __ PopReturnAddressTo(rbx); | |
| 1197 __ Push(rdx); // receiver | |
| 1198 __ Push(rcx); // key | |
| 1199 __ Push(rax); // value | |
| 1200 __ PushReturnAddressFrom(rbx); | |
| 1201 | 1195 |
| 1202 // Do tail-call to runtime routine. | 1196 // Do tail-call to runtime routine. |
| 1203 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); | 1197 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); |
| 1204 __ TailCallExternalReference(ref, 3, 1); | 1198 __ TailCallExternalReference(ref, 3, 1); |
| 1205 } | 1199 } |
| 1206 | 1200 |
| 1207 | 1201 |
| 1208 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 1202 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
| 1209 // ----------- S t a t e ------------- | 1203 // Return address is on the stack. |
| 1210 // -- rax : value | 1204 StoreIC_PushArgs(masm); |
| 1211 // -- rcx : key | |
| 1212 // -- rdx : receiver | |
| 1213 // -- rsp[0] : return address | |
| 1214 // ----------------------------------- | |
| 1215 | |
| 1216 __ PopReturnAddressTo(rbx); | |
| 1217 __ Push(rdx); // receiver | |
| 1218 __ Push(rcx); // key | |
| 1219 __ Push(rax); // value | |
| 1220 __ PushReturnAddressFrom(rbx); | |
| 1221 | 1205 |
| 1222 // Do tail-call to runtime routine. | 1206 // Do tail-call to runtime routine. |
| 1223 ExternalReference ref = | 1207 ExternalReference ref = |
| 1224 ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate()); | 1208 ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate()); |
| 1225 __ TailCallExternalReference(ref, 3, 1); | 1209 __ TailCallExternalReference(ref, 3, 1); |
| 1226 } | 1210 } |
| 1227 | 1211 |
| 1228 | 1212 |
| 1229 #undef __ | 1213 #undef __ |
| 1230 | 1214 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1293 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) | 1277 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) |
| 1294 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 1278 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
| 1295 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 1279 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
| 1296 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1280 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
| 1297 } | 1281 } |
| 1298 | 1282 |
| 1299 | 1283 |
| 1300 } } // namespace v8::internal | 1284 } } // namespace v8::internal |
| 1301 | 1285 |
| 1302 #endif // V8_TARGET_ARCH_X64 | 1286 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |