| 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 #if V8_TARGET_ARCH_ARM | 5 #if V8_TARGET_ARCH_ARM |
| 6 | 6 |
| 7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
| 8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| (...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 __ mov(r0, Operand(ExternalReference::isolate_address(isolate()))); | 687 __ mov(r0, Operand(ExternalReference::isolate_address(isolate()))); |
| 688 __ CallCFunction( | 688 __ CallCFunction( |
| 689 ExternalReference::store_buffer_overflow_function(isolate()), | 689 ExternalReference::store_buffer_overflow_function(isolate()), |
| 690 argument_count); | 690 argument_count); |
| 691 if (save_doubles()) { | 691 if (save_doubles()) { |
| 692 __ RestoreFPRegs(sp, scratch); | 692 __ RestoreFPRegs(sp, scratch); |
| 693 } | 693 } |
| 694 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). | 694 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). |
| 695 } | 695 } |
| 696 | 696 |
| 697 | |
| 698 void MathPowStub::Generate(MacroAssembler* masm) { | 697 void MathPowStub::Generate(MacroAssembler* masm) { |
| 699 const Register base = r1; | |
| 700 const Register exponent = MathPowTaggedDescriptor::exponent(); | 698 const Register exponent = MathPowTaggedDescriptor::exponent(); |
| 701 DCHECK(exponent.is(r2)); | 699 DCHECK(exponent.is(r2)); |
| 702 const Register heapnumbermap = r5; | |
| 703 const Register heapnumber = r0; | |
| 704 const DwVfpRegister double_base = d0; | 700 const DwVfpRegister double_base = d0; |
| 705 const DwVfpRegister double_exponent = d1; | 701 const DwVfpRegister double_exponent = d1; |
| 706 const DwVfpRegister double_result = d2; | 702 const DwVfpRegister double_result = d2; |
| 707 const DwVfpRegister double_scratch = d3; | 703 const DwVfpRegister double_scratch = d3; |
| 708 const SwVfpRegister single_scratch = s6; | 704 const SwVfpRegister single_scratch = s6; |
| 709 const Register scratch = r9; | 705 const Register scratch = r9; |
| 710 const Register scratch2 = r4; | 706 const Register scratch2 = r4; |
| 711 | 707 |
| 712 Label call_runtime, done, int_exponent; | 708 Label call_runtime, done, int_exponent; |
| 713 if (exponent_type() == ON_STACK) { | 709 if (exponent_type() == TAGGED) { |
| 714 Label base_is_smi, unpack_exponent; | |
| 715 // The exponent and base are supplied as arguments on the stack. | |
| 716 // This can only happen if the stub is called from non-optimized code. | |
| 717 // Load input parameters from stack to double registers. | |
| 718 __ ldr(base, MemOperand(sp, 1 * kPointerSize)); | |
| 719 __ ldr(exponent, MemOperand(sp, 0 * kPointerSize)); | |
| 720 | |
| 721 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex); | |
| 722 | |
| 723 __ UntagAndJumpIfSmi(scratch, base, &base_is_smi); | |
| 724 __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset)); | |
| 725 __ cmp(scratch, heapnumbermap); | |
| 726 __ b(ne, &call_runtime); | |
| 727 | |
| 728 __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset)); | |
| 729 __ jmp(&unpack_exponent); | |
| 730 | |
| 731 __ bind(&base_is_smi); | |
| 732 __ vmov(single_scratch, scratch); | |
| 733 __ vcvt_f64_s32(double_base, single_scratch); | |
| 734 __ bind(&unpack_exponent); | |
| 735 | |
| 736 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); | |
| 737 | |
| 738 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); | |
| 739 __ cmp(scratch, heapnumbermap); | |
| 740 __ b(ne, &call_runtime); | |
| 741 __ vldr(double_exponent, | |
| 742 FieldMemOperand(exponent, HeapNumber::kValueOffset)); | |
| 743 } else if (exponent_type() == TAGGED) { | |
| 744 // Base is already in double_base. | 710 // Base is already in double_base. |
| 745 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); | 711 __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent); |
| 746 | 712 |
| 747 __ vldr(double_exponent, | 713 __ vldr(double_exponent, |
| 748 FieldMemOperand(exponent, HeapNumber::kValueOffset)); | 714 FieldMemOperand(exponent, HeapNumber::kValueOffset)); |
| 749 } | 715 } |
| 750 | 716 |
| 751 if (exponent_type() != INTEGER) { | 717 if (exponent_type() != INTEGER) { |
| 752 Label int_exponent_convert; | 718 Label int_exponent_convert; |
| 753 // Detect integer exponents stored as double. | 719 // Detect integer exponents stored as double. |
| 754 __ vcvt_u32_f64(single_scratch, double_exponent); | 720 __ vcvt_u32_f64(single_scratch, double_exponent); |
| 755 // We do not check for NaN or Infinity here because comparing numbers on | 721 // We do not check for NaN or Infinity here because comparing numbers on |
| 756 // ARM correctly distinguishes NaNs. We end up calling the built-in. | 722 // ARM correctly distinguishes NaNs. We end up calling the built-in. |
| 757 __ vcvt_f64_u32(double_scratch, single_scratch); | 723 __ vcvt_f64_u32(double_scratch, single_scratch); |
| 758 __ VFPCompareAndSetFlags(double_scratch, double_exponent); | 724 __ VFPCompareAndSetFlags(double_scratch, double_exponent); |
| 759 __ b(eq, &int_exponent_convert); | 725 __ b(eq, &int_exponent_convert); |
| 760 | 726 |
| 761 if (exponent_type() == ON_STACK) { | |
| 762 // Detect square root case. Crankshaft detects constant +/-0.5 at | |
| 763 // compile time and uses DoMathPowHalf instead. We then skip this check | |
| 764 // for non-constant cases of +/-0.5 as these hardly occur. | |
| 765 Label not_plus_half; | |
| 766 | |
| 767 // Test for 0.5. | |
| 768 __ vmov(double_scratch, 0.5, scratch); | |
| 769 __ VFPCompareAndSetFlags(double_exponent, double_scratch); | |
| 770 __ b(ne, ¬_plus_half); | |
| 771 | |
| 772 // Calculates square root of base. Check for the special case of | |
| 773 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). | |
| 774 __ vmov(double_scratch, -V8_INFINITY, scratch); | |
| 775 __ VFPCompareAndSetFlags(double_base, double_scratch); | |
| 776 __ vneg(double_result, double_scratch, eq); | |
| 777 __ b(eq, &done); | |
| 778 | |
| 779 // Add +0 to convert -0 to +0. | |
| 780 __ vadd(double_scratch, double_base, kDoubleRegZero); | |
| 781 __ vsqrt(double_result, double_scratch); | |
| 782 __ jmp(&done); | |
| 783 | |
| 784 __ bind(¬_plus_half); | |
| 785 __ vmov(double_scratch, -0.5, scratch); | |
| 786 __ VFPCompareAndSetFlags(double_exponent, double_scratch); | |
| 787 __ b(ne, &call_runtime); | |
| 788 | |
| 789 // Calculates square root of base. Check for the special case of | |
| 790 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). | |
| 791 __ vmov(double_scratch, -V8_INFINITY, scratch); | |
| 792 __ VFPCompareAndSetFlags(double_base, double_scratch); | |
| 793 __ vmov(double_result, kDoubleRegZero, eq); | |
| 794 __ b(eq, &done); | |
| 795 | |
| 796 // Add +0 to convert -0 to +0. | |
| 797 __ vadd(double_scratch, double_base, kDoubleRegZero); | |
| 798 __ vmov(double_result, 1.0, scratch); | |
| 799 __ vsqrt(double_scratch, double_scratch); | |
| 800 __ vdiv(double_result, double_result, double_scratch); | |
| 801 __ jmp(&done); | |
| 802 } | |
| 803 | |
| 804 __ push(lr); | 727 __ push(lr); |
| 805 { | 728 { |
| 806 AllowExternalCallThatCantCauseGC scope(masm); | 729 AllowExternalCallThatCantCauseGC scope(masm); |
| 807 __ PrepareCallCFunction(0, 2, scratch); | 730 __ PrepareCallCFunction(0, 2, scratch); |
| 808 __ MovToFloatParameters(double_base, double_exponent); | 731 __ MovToFloatParameters(double_base, double_exponent); |
| 809 __ CallCFunction( | 732 __ CallCFunction( |
| 810 ExternalReference::power_double_double_function(isolate()), | 733 ExternalReference::power_double_double_function(isolate()), 0, 2); |
| 811 0, 2); | |
| 812 } | 734 } |
| 813 __ pop(lr); | 735 __ pop(lr); |
| 814 __ MovFromFloatResult(double_result); | 736 __ MovFromFloatResult(double_result); |
| 815 __ jmp(&done); | 737 __ jmp(&done); |
| 816 | 738 |
| 817 __ bind(&int_exponent_convert); | 739 __ bind(&int_exponent_convert); |
| 818 __ vcvt_u32_f64(single_scratch, double_exponent); | 740 __ vcvt_u32_f64(single_scratch, double_exponent); |
| 819 __ vmov(scratch, single_scratch); | 741 __ vmov(scratch, single_scratch); |
| 820 } | 742 } |
| 821 | 743 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 851 // Test whether result is zero. Bail out to check for subnormal result. | 773 // Test whether result is zero. Bail out to check for subnormal result. |
| 852 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. | 774 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. |
| 853 __ VFPCompareAndSetFlags(double_result, 0.0); | 775 __ VFPCompareAndSetFlags(double_result, 0.0); |
| 854 __ b(ne, &done); | 776 __ b(ne, &done); |
| 855 // double_exponent may not containe the exponent value if the input was a | 777 // double_exponent may not containe the exponent value if the input was a |
| 856 // smi. We set it with exponent value before bailing out. | 778 // smi. We set it with exponent value before bailing out. |
| 857 __ vmov(single_scratch, exponent); | 779 __ vmov(single_scratch, exponent); |
| 858 __ vcvt_f64_s32(double_exponent, single_scratch); | 780 __ vcvt_f64_s32(double_exponent, single_scratch); |
| 859 | 781 |
| 860 // Returning or bailing out. | 782 // Returning or bailing out. |
| 861 if (exponent_type() == ON_STACK) { | 783 __ push(lr); |
| 862 // The arguments are still on the stack. | 784 { |
| 863 __ bind(&call_runtime); | 785 AllowExternalCallThatCantCauseGC scope(masm); |
| 864 __ TailCallRuntime(Runtime::kMathPowRT); | 786 __ PrepareCallCFunction(0, 2, scratch); |
| 787 __ MovToFloatParameters(double_base, double_exponent); |
| 788 __ CallCFunction(ExternalReference::power_double_double_function(isolate()), |
| 789 0, 2); |
| 790 } |
| 791 __ pop(lr); |
| 792 __ MovFromFloatResult(double_result); |
| 865 | 793 |
| 866 // The stub is called from non-optimized code, which expects the result | 794 __ bind(&done); |
| 867 // as heap number in exponent. | 795 __ Ret(); |
| 868 __ bind(&done); | |
| 869 __ AllocateHeapNumber( | |
| 870 heapnumber, scratch, scratch2, heapnumbermap, &call_runtime); | |
| 871 __ vstr(double_result, | |
| 872 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); | |
| 873 DCHECK(heapnumber.is(r0)); | |
| 874 __ Ret(2); | |
| 875 } else { | |
| 876 __ push(lr); | |
| 877 { | |
| 878 AllowExternalCallThatCantCauseGC scope(masm); | |
| 879 __ PrepareCallCFunction(0, 2, scratch); | |
| 880 __ MovToFloatParameters(double_base, double_exponent); | |
| 881 __ CallCFunction( | |
| 882 ExternalReference::power_double_double_function(isolate()), | |
| 883 0, 2); | |
| 884 } | |
| 885 __ pop(lr); | |
| 886 __ MovFromFloatResult(double_result); | |
| 887 | |
| 888 __ bind(&done); | |
| 889 __ Ret(); | |
| 890 } | |
| 891 } | 796 } |
| 892 | 797 |
| 893 | |
| 894 bool CEntryStub::NeedsImmovableCode() { | 798 bool CEntryStub::NeedsImmovableCode() { |
| 895 return true; | 799 return true; |
| 896 } | 800 } |
| 897 | 801 |
| 898 | 802 |
| 899 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 803 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
| 900 CEntryStub::GenerateAheadOfTime(isolate); | 804 CEntryStub::GenerateAheadOfTime(isolate); |
| 901 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 805 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 902 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 806 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
| 903 CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate); | 807 CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate); |
| (...skipping 4435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5339 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, | 5243 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, |
| 5340 kStackUnwindSpace, NULL, return_value_operand, NULL); | 5244 kStackUnwindSpace, NULL, return_value_operand, NULL); |
| 5341 } | 5245 } |
| 5342 | 5246 |
| 5343 #undef __ | 5247 #undef __ |
| 5344 | 5248 |
| 5345 } // namespace internal | 5249 } // namespace internal |
| 5346 } // namespace v8 | 5250 } // namespace v8 |
| 5347 | 5251 |
| 5348 #endif // V8_TARGET_ARCH_ARM | 5252 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |