OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 3698 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3709 } | 3709 } |
3710 } | 3710 } |
3711 | 3711 |
3712 | 3712 |
3713 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | 3713 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
3714 __ Push(r1, r0); | 3714 __ Push(r1, r0); |
3715 } | 3715 } |
3716 | 3716 |
3717 | 3717 |
3718 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 3718 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
3719 // Argument is a number and is on stack and in r0. | 3719 // Untagged case: double input in d2, double result goes |
3720 Label runtime_call; | 3720 // into d2. |
3721 // Tagged case: tagged input on top of stack and in r0, | |
3722 // tagged result (heap number) goes into r0. | |
3723 | |
3721 Label input_not_smi; | 3724 Label input_not_smi; |
3722 Label loaded; | 3725 Label loaded; |
3726 Label calculate; | |
3727 Label invalid_cache; | |
3728 const Register scratch0 = r9; | |
3729 const Register scratch1 = r7; | |
3730 const Register cache_entry = r0; | |
3731 const bool tagged = (argument_type_ == TAGGED); | |
3723 | 3732 |
3724 if (CpuFeatures::IsSupported(VFP3)) { | 3733 if (CpuFeatures::IsSupported(VFP3)) { |
3725 // Load argument and check if it is a smi. | 3734 CpuFeatures::Scope scope(VFP3); |
3726 __ JumpIfNotSmi(r0, &input_not_smi); | 3735 if (tagged) { |
3736 // Argument is a number and is on stack and in r0. | |
3737 // Load argument and check if it is a smi. | |
3738 __ JumpIfNotSmi(r0, &input_not_smi); | |
3727 | 3739 |
3728 CpuFeatures::Scope scope(VFP3); | 3740 // Input is a smi. Convert to double and load the low and high words |
3729 // Input is a smi. Convert to double and load the low and high words | 3741 // of the double into r2, r3. |
3730 // of the double into r2, r3. | 3742 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); |
3731 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); | 3743 __ b(&loaded); |
3732 __ b(&loaded); | |
3733 | 3744 |
3734 __ bind(&input_not_smi); | 3745 __ bind(&input_not_smi); |
3735 // Check if input is a HeapNumber. | 3746 // Check if input is a HeapNumber. |
3736 __ CheckMap(r0, | 3747 __ CheckMap(r0, |
3737 r1, | 3748 r1, |
3738 Heap::kHeapNumberMapRootIndex, | 3749 Heap::kHeapNumberMapRootIndex, |
3739 &runtime_call, | 3750 &calculate, |
3740 true); | 3751 true); |
3741 // Input is a HeapNumber. Load it to a double register and store the | 3752 // Input is a HeapNumber. Load it to a double register and store the |
3742 // low and high words into r2, r3. | 3753 // low and high words into r2, r3. |
3743 __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset)); | 3754 __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
3744 | 3755 __ vmov(r2, r3, d0); |
3756 } else { | |
3757 // Input is untagged double in d2. Output goes to d2. | |
3758 __ vmov(r2, r3, d2); | |
3759 } | |
3745 __ bind(&loaded); | 3760 __ bind(&loaded); |
3746 // r2 = low 32 bits of double value | 3761 // r2 = low 32 bits of double value |
3747 // r3 = high 32 bits of double value | 3762 // r3 = high 32 bits of double value |
3748 // Compute hash (the shifts are arithmetic): | 3763 // Compute hash (the shifts are arithmetic): |
3749 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); | 3764 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); |
3750 __ eor(r1, r2, Operand(r3)); | 3765 __ eor(r1, r2, Operand(r3)); |
3751 __ eor(r1, r1, Operand(r1, ASR, 16)); | 3766 __ eor(r1, r1, Operand(r1, ASR, 16)); |
3752 __ eor(r1, r1, Operand(r1, ASR, 8)); | 3767 __ eor(r1, r1, Operand(r1, ASR, 8)); |
3753 ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); | 3768 ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); |
3754 __ And(r1, r1, Operand(TranscendentalCache::kCacheSize - 1)); | 3769 __ And(r1, r1, Operand(TranscendentalCache::kCacheSize - 1)); |
3755 | 3770 |
3756 // r2 = low 32 bits of double value. | 3771 // r2 = low 32 bits of double value. |
3757 // r3 = high 32 bits of double value. | 3772 // r3 = high 32 bits of double value. |
3758 // r1 = TranscendentalCache::hash(double value). | 3773 // r1 = TranscendentalCache::hash(double value). |
3759 __ mov(r0, | 3774 __ mov(cache_entry, |
3760 Operand(ExternalReference::transcendental_cache_array_address())); | 3775 Operand(ExternalReference::transcendental_cache_array_address())); |
3761 // r0 points to cache array. | 3776 // r0 points to cache array. |
3762 __ ldr(r0, MemOperand(r0, type_ * sizeof(TranscendentalCache::caches_[0]))); | 3777 __ ldr(cache_entry, MemOperand(cache_entry, |
3778 type_ * sizeof(TranscendentalCache::caches_[0]))); | |
3763 // r0 points to the cache for the type type_. | 3779 // r0 points to the cache for the type type_. |
3764 // If NULL, the cache hasn't been initialized yet, so go through runtime. | 3780 // If NULL, the cache hasn't been initialized yet, so go through runtime. |
3765 __ cmp(r0, Operand(0, RelocInfo::NONE)); | 3781 __ cmp(cache_entry, Operand(0, RelocInfo::NONE)); |
3766 __ b(eq, &runtime_call); | 3782 __ b(eq, &invalid_cache); |
3767 | 3783 |
3768 #ifdef DEBUG | 3784 #ifdef DEBUG |
3769 // Check that the layout of cache elements match expectations. | 3785 // Check that the layout of cache elements match expectations. |
3770 { TranscendentalCache::Element test_elem[2]; | 3786 { TranscendentalCache::Element test_elem[2]; |
3771 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); | 3787 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); |
3772 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); | 3788 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); |
3773 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); | 3789 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); |
3774 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); | 3790 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); |
3775 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); | 3791 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); |
3776 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. | 3792 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. |
3777 CHECK_EQ(0, elem_in0 - elem_start); | 3793 CHECK_EQ(0, elem_in0 - elem_start); |
3778 CHECK_EQ(kIntSize, elem_in1 - elem_start); | 3794 CHECK_EQ(kIntSize, elem_in1 - elem_start); |
3779 CHECK_EQ(2 * kIntSize, elem_out - elem_start); | 3795 CHECK_EQ(2 * kIntSize, elem_out - elem_start); |
3780 } | 3796 } |
3781 #endif | 3797 #endif |
3782 | 3798 |
3783 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. | 3799 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. |
3784 __ add(r1, r1, Operand(r1, LSL, 1)); | 3800 __ add(r1, r1, Operand(r1, LSL, 1)); |
3785 __ add(r0, r0, Operand(r1, LSL, 2)); | 3801 __ add(cache_entry, cache_entry, Operand(r1, LSL, 2)); |
3786 // Check if cache matches: Double value is stored in uint32_t[2] array. | 3802 // Check if cache matches: Double value is stored in uint32_t[2] array. |
3787 __ ldm(ia, r0, r4.bit()| r5.bit() | r6.bit()); | 3803 __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit()); |
3788 __ cmp(r2, r4); | 3804 __ cmp(r2, r4); |
3789 __ b(ne, &runtime_call); | 3805 __ b(ne, &calculate); |
3790 __ cmp(r3, r5); | 3806 __ cmp(r3, r5); |
3791 __ b(ne, &runtime_call); | 3807 __ b(ne, &calculate); |
3792 // Cache hit. Load result, pop argument and return. | 3808 // Cache hit. Load result, cleanup and return. |
3793 __ mov(r0, Operand(r6)); | 3809 if (tagged) { |
3794 __ pop(); | 3810 // Pop input value from stack and load result into r0. |
3811 __ pop(); | |
3812 __ mov(r0, Operand(r6)); | |
3813 } else { | |
3814 // Load result into d2. | |
3815 __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); | |
3816 } | |
3817 __ Ret(); | |
3818 } // if (CpuFeatures::IsSupported(VFP3)) | |
3819 | |
3820 __ bind(&calculate); | |
3821 if (tagged) { | |
3822 __ bind(&invalid_cache); | |
3823 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | |
3824 } else { | |
3825 if (!CpuFeatures::IsSupported(VFP3)) UNREACHABLE(); | |
3826 CpuFeatures::Scope scope(VFP3); | |
3827 | |
3828 Label no_update; | |
3829 Label skip_cache; | |
3830 const Register heap_number_map = r5; | |
3831 | |
3832 // Call C function to calculate the result and update the cache. | |
3833 // Register r0 holds precalculated cache entry address; preserve | |
3834 // it on the stack and pop it into register cache_entry after the | |
3835 // call. | |
3836 __ push(cache_entry); | |
3837 GenerateCallCFunction(masm, scratch0); | |
3838 __ GetCFunctionDoubleResult(d2); | |
3839 | |
3840 // Try to update the cache. If we cannot allocate a | |
3841 // heap number, we return the result without updating. | |
3842 __ pop(cache_entry); | |
3843 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); | |
3844 __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &no_update); | |
3845 __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); | |
3846 __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit()); | |
3847 __ Ret(); | |
3848 | |
3849 __ bind(&invalid_cache); | |
3850 // The cache is invalid. Call runtime which will recreate the | |
3851 // cache. | |
3852 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); | |
3853 __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache); | |
3854 __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); | |
3855 __ EnterInternalFrame(); | |
3856 __ push(r0); | |
3857 __ CallRuntime(RuntimeFunction(), 1); | |
3858 __ LeaveInternalFrame(); | |
3859 __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); | |
3860 __ Ret(); | |
3861 | |
3862 __ bind(&skip_cache); | |
3863 // Call C function to calculate the result and answer directly | |
3864 // without updating the cache. | |
3865 GenerateCallCFunction(masm, scratch0); | |
3866 __ GetCFunctionDoubleResult(d2); | |
3867 __ bind(&no_update); | |
3868 | |
3869 // We return the value in d2 without adding it to the cache, but | |
3870 // we cause a scavenging GC so that future allocations will succeed. | |
3871 __ EnterInternalFrame(); | |
3872 | |
3873 // Allocate an aligned object larger than a HeapNumber. | |
3874 ASSERT(4 * kPointerSize >= HeapNumber::kSize); | |
3875 __ mov(scratch0, Operand(4 * kPointerSize)); | |
Søren Thygesen Gjesse
2011/03/04 07:44:18
Why not HeapNumber::kSize instead of 4 * kPointerS
| |
3876 __ push(scratch0); | |
3877 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); | |
3878 __ LeaveInternalFrame(); | |
3795 __ Ret(); | 3879 __ Ret(); |
3796 } | 3880 } |
3797 | |
3798 __ bind(&runtime_call); | |
3799 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | |
3800 } | 3881 } |
3801 | 3882 |
3802 | 3883 |
3884 void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm, | |
3885 Register scratch) { | |
3886 __ push(lr); | |
3887 __ PrepareCallCFunction(2, scratch); | |
3888 __ vmov(r0, r1, d2); | |
3889 switch (type_) { | |
3890 case TranscendentalCache::SIN: | |
3891 __ CallCFunction(ExternalReference::math_sin_double_function(), 2); | |
3892 break; | |
3893 case TranscendentalCache::COS: | |
3894 __ CallCFunction(ExternalReference::math_cos_double_function(), 2); | |
3895 break; | |
3896 case TranscendentalCache::LOG: | |
3897 __ CallCFunction(ExternalReference::math_log_double_function(), 2); | |
3898 break; | |
3899 default: | |
3900 UNIMPLEMENTED(); | |
3901 break; | |
3902 } | |
3903 __ pop(lr); | |
3904 } | |
3905 | |
3906 | |
3803 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 3907 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
3804 switch (type_) { | 3908 switch (type_) { |
3805 // Add more cases when necessary. | 3909 // Add more cases when necessary. |
3806 case TranscendentalCache::SIN: return Runtime::kMath_sin; | 3910 case TranscendentalCache::SIN: return Runtime::kMath_sin; |
3807 case TranscendentalCache::COS: return Runtime::kMath_cos; | 3911 case TranscendentalCache::COS: return Runtime::kMath_cos; |
3808 case TranscendentalCache::LOG: return Runtime::kMath_log; | 3912 case TranscendentalCache::LOG: return Runtime::kMath_log; |
3809 default: | 3913 default: |
3810 UNIMPLEMENTED(); | 3914 UNIMPLEMENTED(); |
3811 return Runtime::kAbort; | 3915 return Runtime::kAbort; |
3812 } | 3916 } |
(...skipping 2961 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6774 __ strb(untagged_value, MemOperand(external_pointer, untagged_key)); | 6878 __ strb(untagged_value, MemOperand(external_pointer, untagged_key)); |
6775 __ Ret(); | 6879 __ Ret(); |
6776 } | 6880 } |
6777 | 6881 |
6778 | 6882 |
6779 #undef __ | 6883 #undef __ |
6780 | 6884 |
6781 } } // namespace v8::internal | 6885 } } // namespace v8::internal |
6782 | 6886 |
6783 #endif // V8_TARGET_ARCH_ARM | 6887 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |