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 2423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2434 // ----------- S t a t e ------------- | 2434 // ----------- S t a t e ------------- |
2435 // -- rax : value | 2435 // -- rax : value |
2436 // -- rcx : key | 2436 // -- rcx : key |
2437 // -- rdx : receiver | 2437 // -- rdx : receiver |
2438 // -- rsp[0] : return address | 2438 // -- rsp[0] : return address |
2439 // ----------------------------------- | 2439 // ----------------------------------- |
2440 | 2440 |
2441 ElementsKind elements_kind = receiver_map->elements_kind(); | 2441 ElementsKind elements_kind = receiver_map->elements_kind(); |
2442 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; | 2442 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; |
2443 Handle<Code> stub = | 2443 Handle<Code> stub = |
2444 KeyedStoreElementStub(is_js_array, elements_kind).GetCode(); | 2444 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode(); |
2445 | 2445 |
2446 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); | 2446 __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK); |
2447 | 2447 |
2448 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2448 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
2449 __ jmp(ic, RelocInfo::CODE_TARGET); | 2449 __ jmp(ic, RelocInfo::CODE_TARGET); |
2450 | 2450 |
2451 // Return the generated code. | 2451 // Return the generated code. |
2452 return GetCode(NORMAL, factory()->empty_string()); | 2452 return GetCode(NORMAL, factory()->empty_string()); |
2453 } | 2453 } |
2454 | 2454 |
(...skipping 1037 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3492 __ bind(&miss_force_generic); | 3492 __ bind(&miss_force_generic); |
3493 Handle<Code> miss_ic = | 3493 Handle<Code> miss_ic = |
3494 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); | 3494 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
3495 __ jmp(miss_ic, RelocInfo::CODE_TARGET); | 3495 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
3496 } | 3496 } |
3497 | 3497 |
3498 | 3498 |
3499 void KeyedStoreStubCompiler::GenerateStoreFastElement( | 3499 void KeyedStoreStubCompiler::GenerateStoreFastElement( |
3500 MacroAssembler* masm, | 3500 MacroAssembler* masm, |
3501 bool is_js_array, | 3501 bool is_js_array, |
3502 ElementsKind elements_kind) { | 3502 ElementsKind elements_kind, |
| 3503 KeyedAccessGrowMode grow_mode) { |
3503 // ----------- S t a t e ------------- | 3504 // ----------- S t a t e ------------- |
3504 // -- rax : value | 3505 // -- rax : value |
3505 // -- rcx : key | 3506 // -- rcx : key |
3506 // -- rdx : receiver | 3507 // -- rdx : receiver |
3507 // -- rsp[0] : return address | 3508 // -- rsp[0] : return address |
3508 // ----------------------------------- | 3509 // ----------------------------------- |
3509 Label miss_force_generic, transition_elements_kind; | 3510 Label miss_force_generic, transition_elements_kind, finish_store, grow; |
| 3511 Label check_capacity, slow; |
3510 | 3512 |
3511 // This stub is meant to be tail-jumped to, the receiver must already | 3513 // This stub is meant to be tail-jumped to, the receiver must already |
3512 // have been verified by the caller to not be a smi. | 3514 // have been verified by the caller to not be a smi. |
3513 | 3515 |
3514 // Check that the key is a smi. | 3516 // Check that the key is a smi. |
3515 __ JumpIfNotSmi(rcx, &miss_force_generic); | 3517 __ JumpIfNotSmi(rcx, &miss_force_generic); |
3516 | 3518 |
| 3519 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
| 3520 __ JumpIfNotSmi(rax, &transition_elements_kind); |
| 3521 } |
| 3522 |
3517 // Get the elements array and make sure it is a fast element array, not 'cow'. | 3523 // Get the elements array and make sure it is a fast element array, not 'cow'. |
3518 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | 3524 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
3519 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), | |
3520 Heap::kFixedArrayMapRootIndex); | |
3521 __ j(not_equal, &miss_force_generic); | |
3522 | |
3523 // Check that the key is within bounds. | 3525 // Check that the key is within bounds. |
3524 if (is_js_array) { | 3526 if (is_js_array) { |
3525 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); | 3527 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); |
3526 __ j(above_equal, &miss_force_generic); | 3528 if (grow_mode == ALLOW_JSARRAY_GROWTH) { |
| 3529 __ j(above_equal, &grow); |
| 3530 } else { |
| 3531 __ j(above_equal, &miss_force_generic); |
| 3532 } |
3527 } else { | 3533 } else { |
3528 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); | 3534 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); |
3529 __ j(above_equal, &miss_force_generic); | 3535 __ j(above_equal, &miss_force_generic); |
3530 } | 3536 } |
3531 | 3537 |
| 3538 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), |
| 3539 Heap::kFixedArrayMapRootIndex); |
| 3540 __ j(not_equal, &miss_force_generic); |
| 3541 |
| 3542 __ bind(&finish_store); |
3532 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { | 3543 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
3533 __ JumpIfNotSmi(rax, &transition_elements_kind); | |
3534 __ SmiToInteger32(rcx, rcx); | 3544 __ SmiToInteger32(rcx, rcx); |
3535 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), | 3545 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), |
3536 rax); | 3546 rax); |
3537 } else { | 3547 } else { |
3538 // Do the store and update the write barrier. | 3548 // Do the store and update the write barrier. |
3539 ASSERT(elements_kind == FAST_ELEMENTS); | 3549 ASSERT(elements_kind == FAST_ELEMENTS); |
3540 __ SmiToInteger32(rcx, rcx); | 3550 __ SmiToInteger32(rcx, rcx); |
3541 __ lea(rcx, | 3551 __ lea(rcx, |
3542 FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize)); | 3552 FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize)); |
3543 __ movq(Operand(rcx, 0), rax); | 3553 __ movq(Operand(rcx, 0), rax); |
3544 // Make sure to preserve the value in register rax. | 3554 // Make sure to preserve the value in register rax. |
3545 __ movq(rdx, rax); | 3555 __ movq(rbx, rax); |
3546 __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs); | 3556 __ RecordWrite(rdi, rcx, rbx, kDontSaveFPRegs); |
3547 } | 3557 } |
3548 | 3558 |
3549 // Done. | 3559 // Done. |
3550 __ ret(0); | 3560 __ ret(0); |
3551 | 3561 |
3552 // Handle store cache miss. | 3562 // Handle store cache miss. |
3553 __ bind(&miss_force_generic); | 3563 __ bind(&miss_force_generic); |
3554 Handle<Code> ic_force_generic = | 3564 Handle<Code> ic_force_generic = |
3555 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3565 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
3556 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 3566 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
3557 | 3567 |
3558 __ bind(&transition_elements_kind); | 3568 __ bind(&transition_elements_kind); |
3559 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); | 3569 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); |
3560 __ jmp(ic_miss, RelocInfo::CODE_TARGET); | 3570 __ jmp(ic_miss, RelocInfo::CODE_TARGET); |
| 3571 |
| 3572 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) { |
| 3573 // Grow the array by a single element if possible. |
| 3574 __ bind(&grow); |
| 3575 |
| 3576 // Make sure the array is only growing by a single element, anything else |
| 3577 // must be handled by the runtime. Flags are already set by previous |
| 3578 // compare. |
| 3579 __ j(not_equal, &miss_force_generic); |
| 3580 |
| 3581 // Check for the empty array, and preallocate a small backing store if |
| 3582 // possible. |
| 3583 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 3584 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex); |
| 3585 __ j(not_equal, &check_capacity); |
| 3586 |
| 3587 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); |
| 3588 __ AllocateInNewSpace(size, rdi, rbx, r8, &slow, TAG_OBJECT); |
| 3589 |
| 3590 // rax: value |
| 3591 // rcx: key |
| 3592 // rdx: receiver |
| 3593 // rdi: elements |
| 3594 // Make sure that the backing store can hold additional elements. |
| 3595 __ Move(FieldOperand(rdi, JSObject::kMapOffset), |
| 3596 masm->isolate()->factory()->fixed_array_map()); |
| 3597 __ Move(FieldOperand(rdi, FixedArray::kLengthOffset), |
| 3598 Smi::FromInt(JSArray::kPreallocatedArrayElements)); |
| 3599 __ LoadRoot(rbx, Heap::kTheHoleValueRootIndex); |
| 3600 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) { |
| 3601 __ movq(FieldOperand(rdi, FixedArray::SizeFor(i)), rbx); |
| 3602 } |
| 3603 |
| 3604 // Store the element at index zero. |
| 3605 __ movq(FieldOperand(rdi, FixedArray::SizeFor(0)), rax); |
| 3606 |
| 3607 // Install the new backing store in the JSArray. |
| 3608 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi); |
| 3609 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx, |
| 3610 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 3611 |
| 3612 // Increment the length of the array. |
| 3613 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1)); |
| 3614 __ ret(0); |
| 3615 |
| 3616 __ bind(&check_capacity); |
| 3617 // Check for cow elements, in general they are not handled by this stub. |
| 3618 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), |
| 3619 Heap::kFixedCOWArrayMapRootIndex); |
| 3620 __ j(equal, &miss_force_generic); |
| 3621 |
| 3622 // rax: value |
| 3623 // rcx: key |
| 3624 // rdx: receiver |
| 3625 // rdi: elements |
| 3626 // Make sure that the backing store can hold additional elements. |
| 3627 __ cmpq(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); |
| 3628 __ j(above_equal, &slow); |
| 3629 |
| 3630 // Grow the array and finish the store. |
| 3631 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset), |
| 3632 Smi::FromInt(1)); |
| 3633 __ jmp(&finish_store); |
| 3634 |
| 3635 __ bind(&slow); |
| 3636 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
| 3637 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
| 3638 } |
3561 } | 3639 } |
3562 | 3640 |
3563 | 3641 |
3564 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( | 3642 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
3565 MacroAssembler* masm, | 3643 MacroAssembler* masm, |
3566 bool is_js_array) { | 3644 bool is_js_array, |
| 3645 KeyedAccessGrowMode grow_mode) { |
3567 // ----------- S t a t e ------------- | 3646 // ----------- S t a t e ------------- |
3568 // -- rax : value | 3647 // -- rax : value |
3569 // -- rcx : key | 3648 // -- rcx : key |
3570 // -- rdx : receiver | 3649 // -- rdx : receiver |
3571 // -- rsp[0] : return address | 3650 // -- rsp[0] : return address |
3572 // ----------------------------------- | 3651 // ----------------------------------- |
3573 Label miss_force_generic, transition_elements_kind; | 3652 Label miss_force_generic, transition_elements_kind, finish_store; |
| 3653 Label grow, slow, check_capacity; |
3574 | 3654 |
3575 // This stub is meant to be tail-jumped to, the receiver must already | 3655 // This stub is meant to be tail-jumped to, the receiver must already |
3576 // have been verified by the caller to not be a smi. | 3656 // have been verified by the caller to not be a smi. |
3577 | 3657 |
3578 // Check that the key is a smi. | 3658 // Check that the key is a smi. |
3579 __ JumpIfNotSmi(rcx, &miss_force_generic); | 3659 __ JumpIfNotSmi(rcx, &miss_force_generic); |
3580 | 3660 |
3581 // Get the elements array. | 3661 // Get the elements array. |
3582 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | 3662 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
3583 __ AssertFastElements(rdi); | 3663 __ AssertFastElements(rdi); |
3584 | 3664 |
3585 // Check that the key is within bounds. | 3665 // Check that the key is within bounds. |
3586 if (is_js_array) { | 3666 if (is_js_array) { |
3587 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); | 3667 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); |
| 3668 if (grow_mode == ALLOW_JSARRAY_GROWTH) { |
| 3669 __ j(above_equal, &grow); |
| 3670 } else { |
| 3671 __ j(above_equal, &miss_force_generic); |
| 3672 } |
3588 } else { | 3673 } else { |
3589 __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); | 3674 __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); |
| 3675 __ j(above_equal, &miss_force_generic); |
3590 } | 3676 } |
3591 __ j(above_equal, &miss_force_generic); | |
3592 | 3677 |
3593 // Handle smi values specially | 3678 // Handle smi values specially |
| 3679 __ bind(&finish_store); |
3594 __ SmiToInteger32(rcx, rcx); | 3680 __ SmiToInteger32(rcx, rcx); |
3595 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, | 3681 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, |
3596 &transition_elements_kind); | 3682 &transition_elements_kind); |
3597 __ ret(0); | 3683 __ ret(0); |
3598 | 3684 |
3599 // Handle store cache miss, replacing the ic with the generic stub. | 3685 // Handle store cache miss, replacing the ic with the generic stub. |
3600 __ bind(&miss_force_generic); | 3686 __ bind(&miss_force_generic); |
3601 Handle<Code> ic_force_generic = | 3687 Handle<Code> ic_force_generic = |
3602 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3688 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
3603 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 3689 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
3604 | 3690 |
3605 __ bind(&transition_elements_kind); | 3691 __ bind(&transition_elements_kind); |
3606 // Restore smi-tagging of rcx. | 3692 // Restore smi-tagging of rcx. |
3607 __ Integer32ToSmi(rcx, rcx); | 3693 __ Integer32ToSmi(rcx, rcx); |
3608 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); | 3694 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); |
3609 __ jmp(ic_miss, RelocInfo::CODE_TARGET); | 3695 __ jmp(ic_miss, RelocInfo::CODE_TARGET); |
| 3696 |
| 3697 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) { |
| 3698 // Grow the array by a single element if possible. |
| 3699 __ bind(&grow); |
| 3700 |
| 3701 // Make sure the array is only growing by a single element, anything else |
| 3702 // must be handled by the runtime. Flags are already set by previous |
| 3703 // compare. |
| 3704 __ j(not_equal, &miss_force_generic); |
| 3705 |
| 3706 // Transition on values that can't be stored in a FixedDoubleArray. |
| 3707 Label value_is_smi; |
| 3708 __ JumpIfSmi(rax, &value_is_smi); |
| 3709 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
| 3710 Heap::kHeapNumberMapRootIndex); |
| 3711 __ j(not_equal, &transition_elements_kind); |
| 3712 __ bind(&value_is_smi); |
| 3713 |
| 3714 // Check for the empty array, and preallocate a small backing store if |
| 3715 // possible. |
| 3716 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 3717 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex); |
| 3718 __ j(not_equal, &check_capacity); |
| 3719 |
| 3720 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); |
| 3721 __ AllocateInNewSpace(size, rdi, rbx, r8, &slow, TAG_OBJECT); |
| 3722 |
| 3723 // rax: value |
| 3724 // rcx: key |
| 3725 // rdx: receiver |
| 3726 // rdi: elements |
| 3727 // Initialize the new FixedDoubleArray. Leave elements unitialized for |
| 3728 // efficiency, they are guaranteed to be initialized before use. |
| 3729 __ Move(FieldOperand(rdi, JSObject::kMapOffset), |
| 3730 masm->isolate()->factory()->fixed_double_array_map()); |
| 3731 __ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset), |
| 3732 Smi::FromInt(JSArray::kPreallocatedArrayElements)); |
| 3733 |
| 3734 // Install the new backing store in the JSArray. |
| 3735 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi); |
| 3736 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx, |
| 3737 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 3738 |
| 3739 // Increment the length of the array. |
| 3740 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1)); |
| 3741 __ jmp(&finish_store); |
| 3742 |
| 3743 __ bind(&check_capacity); |
| 3744 // rax: value |
| 3745 // rcx: key |
| 3746 // rdx: receiver |
| 3747 // rdi: elements |
| 3748 // Make sure that the backing store can hold additional elements. |
| 3749 __ cmpq(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); |
| 3750 __ j(above_equal, &slow); |
| 3751 |
| 3752 // Grow the array and finish the store. |
| 3753 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset), |
| 3754 Smi::FromInt(1)); |
| 3755 __ jmp(&finish_store); |
| 3756 |
| 3757 __ bind(&slow); |
| 3758 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
| 3759 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
| 3760 } |
3610 } | 3761 } |
3611 | 3762 |
3612 | 3763 |
3613 #undef __ | 3764 #undef __ |
3614 | 3765 |
3615 } } // namespace v8::internal | 3766 } } // namespace v8::internal |
3616 | 3767 |
3617 #endif // V8_TARGET_ARCH_X64 | 3768 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |