diff --git a/src/assembler.cc b/src/assembler.cc index e1cf13ff71..941f45c211 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -1115,19 +1115,7 @@ double power_double_int(double x, int y) { double power_double_double(double x, double y) { // The checks for special cases can be dropped in ia32 because it has already // been done in generated code before bailing out here. -#if !defined(V8_TARGET_ARCH_IA32) - int y_int = static_cast(y); - if (y == y_int) { - return power_double_int(x, y_int); // Returns 1.0 for exponent 0. - } - if (!isinf(x)) { - if (y == 0.5) return sqrt(x + 0.0); // -0 must be converted to +0. - if (y == -0.5) return 1.0 / sqrt(x + 0.0); - } -#endif - if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { - return OS::nan_value(); - } + if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) return OS::nan_value(); return pow(x, y); } diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 08bbbc036d..fa706fbf50 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -2948,8 +2948,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { const XMMRegister double_exponent = xmm1; const XMMRegister double_scratch = xmm4; - Label double_int_runtime, generic_runtime, done; - Label exponent_not_smi, int_exponent; + Label call_runtime, done, exponent_not_smi, int_exponent; // Save 1 in double_result - we need this several times later on. __ mov(scratch, Immediate(1)); @@ -2966,7 +2965,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ JumpIfSmi(base, &base_is_smi, Label::kNear); __ cmp(FieldOperand(base, HeapObject::kMapOffset), factory->heap_number_map()); - __ j(not_equal, &generic_runtime); + __ j(not_equal, &call_runtime); __ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset)); __ jmp(&unpack_exponent, Label::kNear); @@ -2983,7 +2982,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ bind(&exponent_not_smi); __ cmp(FieldOperand(exponent, HeapObject::kMapOffset), factory->heap_number_map()); - __ j(not_equal, &generic_runtime); + __ j(not_equal, &call_runtime); __ movdbl(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset)); } else if (exponent_type_ == TAGGED) { @@ -3002,7 +3001,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ cvttsd2si(exponent, Operand(double_exponent)); // Skip to runtime if possibly NaN (indicated by the indefinite integer). __ cmp(exponent, Immediate(0x80000000u)); - __ j(equal, &generic_runtime); + __ j(equal, &call_runtime); __ cvtsi2sd(double_scratch, exponent); // Already ruled out NaNs for exponent. __ ucomisd(double_exponent, double_scratch); @@ -3119,33 +3118,35 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ bind(&fast_power_failed); __ fninit(); __ add(esp, Immediate(kDoubleSize)); - __ jmp(&generic_runtime); + __ jmp(&call_runtime); } // Calculate power with integer exponent. __ bind(&int_exponent); const XMMRegister double_scratch2 = double_exponent; - __ mov(scratch, exponent); // Back up exponent. + __ mov(scratch, exponent); // Back up exponent. __ movsd(double_scratch, double_base); // Back up base. __ movsd(double_scratch2, double_result); // Load double_exponent with 1. // Get absolute value of exponent. - Label while_true, no_multiply; - const uint32_t kClearSignBitMask = 0x7FFFFFFF; - __ and_(exponent, Immediate(kClearSignBitMask)); + Label no_neg, while_true, no_multiply; + __ test(scratch, scratch); + __ j(positive, &no_neg, Label::kNear); + __ neg(scratch); + __ bind(&no_neg); __ bind(&while_true); - __ shr(exponent, 1); + __ shr(scratch, 1); __ j(not_carry, &no_multiply, Label::kNear); - __ mulsd(double_result, double_base); + __ mulsd(double_result, double_scratch); __ bind(&no_multiply); - __ mulsd(double_base, double_base); + __ mulsd(double_scratch, double_scratch); __ j(not_zero, &while_true); // scratch has the original value of the exponent - if the exponent is // negative, return 1/result. - __ test(scratch, scratch); + __ test(exponent, exponent); __ j(positive, &done); __ divsd(double_scratch2, double_result); __ movsd(double_result, double_scratch2); @@ -3153,47 +3154,36 @@ void MathPowStub::Generate(MacroAssembler* masm) { // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. __ xorps(double_scratch2, double_scratch2); __ ucomisd(double_scratch2, double_result); // Result cannot be NaN. - __ j(equal, &double_int_runtime); + // double_exponent aliased as double_scratch2 has already been overwritten + // and may not have contained the exponent value in the first place when the + // exponent is a smi. We reset it with exponent value before bailing out. + __ j(not_equal, &done); + __ cvtsi2sd(double_exponent, exponent); // Returning or bailing out. + Counters* counters = masm->isolate()->counters(); if (exponent_type_ == ON_STACK) { + // The arguments are still on the stack. + __ bind(&call_runtime); + __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); + // The stub is called from non-optimized code, which expects the result // as heap number in exponent. __ bind(&done); - __ AllocateHeapNumber(exponent, scratch, base, &generic_runtime); - __ movdbl(FieldOperand(exponent, HeapNumber::kValueOffset), double_result); + __ AllocateHeapNumber(eax, scratch, base, &call_runtime); + __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), double_result); + __ IncrementCounter(counters->math_pow(), 1); __ ret(2 * kPointerSize); - - // The arguments are still on the stack. - __ bind(&generic_runtime); - __ bind(&double_int_runtime); - __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); } else { - __ jmp(&done); - - Label return_from_runtime; - __ bind(&generic_runtime); + __ bind(&call_runtime); { AllowExternalCallThatCantCauseGC scope(masm); - __ PrepareCallCFunction(4, exponent); + __ PrepareCallCFunction(4, scratch); __ movdbl(Operand(esp, 0 * kDoubleSize), double_base); __ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent); __ CallCFunction( ExternalReference::power_double_double_function(masm->isolate()), 4); } - __ jmp(&return_from_runtime, Label::kNear); - - __ bind(&double_int_runtime); - { - AllowExternalCallThatCantCauseGC scope(masm); - __ PrepareCallCFunction(4, exponent); - __ movdbl(Operand(esp, 0 * kDoubleSize), double_scratch); - __ mov(Operand(esp, 1 * kDoubleSize), scratch); - __ CallCFunction( - ExternalReference::power_double_int_function(masm->isolate()), 4); - } - - __ bind(&return_from_runtime); // Return value is in st(0) on ia32. // Store it into the (fixed) result register. __ sub(esp, Immediate(kDoubleSize)); @@ -3202,6 +3192,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ add(esp, Immediate(kDoubleSize)); __ bind(&done); + __ IncrementCounter(counters->math_pow(), 1); __ ret(0); } } diff --git a/src/runtime.cc b/src/runtime.cc index 0813e7dac5..a3fd04336d 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -7398,7 +7398,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) { return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x); } - +// Slow version of Math.pow. We check for fast paths for special cases. +// Used if SSE2/VFP3 is not available. RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { NoHandleAllocation ha; ASSERT(args.length() == 2); @@ -7414,25 +7415,36 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { } CONVERT_DOUBLE_ARG_CHECKED(y, 1); - // Returning a smi would not confuse crankshaft as this part of code is only - // run if SSE2 was not available, in which case crankshaft is disabled. - if (y == 0) return Smi::FromInt(1); // Returns 1 if exponent is 0. - return isolate->heap()->AllocateHeapNumber(power_double_double(x, y)); + int y_int = static_cast(y); + double result; + if (y == y_int) { + result = power_double_int(x, y_int); // Returns 1 if exponent is 0. + } else if (y == 0.5) { + result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0. + } else if (y == -0.5) { + result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0. + } else { + result = power_double_double(x, y); + } + if (isnan(result)) return isolate->heap()->nan_value(); + return isolate->heap()->AllocateHeapNumber(result); } -// Fast version of Math.pow if we know that y is not an integer and -// y is not -0.5 or 0.5. Used as slowcase from codegen. +// Fast version of Math.pow if we know that y is not an integer and y is not +// -0.5 or 0.5. Used as slow case from fullcodegen. RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) { NoHandleAllocation ha; ASSERT(args.length() == 2); + isolate->counters()->math_pow()->Increment(); + CONVERT_DOUBLE_ARG_CHECKED(x, 0); CONVERT_DOUBLE_ARG_CHECKED(y, 1); if (y == 0) { return Smi::FromInt(1); - } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { - return isolate->heap()->nan_value(); } else { - return isolate->heap()->AllocateHeapNumber(pow(x, y)); + double result = power_double_double(x, y); + if (isnan(result)) return isolate->heap()->nan_value(); + return isolate->heap()->AllocateHeapNumber(result); } } diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 46a5487c71..bed24ac6eb 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2004,8 +2004,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { const XMMRegister double_exponent = xmm1; const XMMRegister double_scratch = xmm4; - Label double_int_runtime, generic_runtime, done; - Label exponent_not_smi, int_exponent; + Label call_runtime, done, exponent_not_smi, int_exponent; // Save 1 in double_result - we need this several times later on. __ movq(scratch, Immediate(1)); @@ -2021,7 +2020,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ JumpIfSmi(base, &base_is_smi, Label::kNear); __ CompareRoot(FieldOperand(base, HeapObject::kMapOffset), Heap::kHeapNumberMapRootIndex); - __ j(not_equal, &generic_runtime); + __ j(not_equal, &call_runtime); __ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset)); __ jmp(&unpack_exponent, Label::kNear); @@ -2038,7 +2037,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ bind(&exponent_not_smi); __ CompareRoot(FieldOperand(exponent, HeapObject::kMapOffset), Heap::kHeapNumberMapRootIndex); - __ j(not_equal, &generic_runtime); + __ j(not_equal, &call_runtime); __ movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset)); } else if (exponent_type_ == TAGGED) { __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); @@ -2055,7 +2054,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ cvttsd2si(exponent, double_exponent); // Skip to runtime if possibly NaN (indicated by the indefinite integer). __ cmpl(exponent, Immediate(0x80000000u)); - __ j(equal, &generic_runtime); + __ j(equal, &call_runtime); __ cvtlsi2sd(double_scratch, exponent); // Already ruled out NaNs for exponent. __ ucomisd(double_exponent, double_scratch); @@ -2169,7 +2168,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ bind(&fast_power_failed); __ fninit(); __ addq(rsp, Immediate(kDoubleSize)); - __ jmp(&generic_runtime); + __ jmp(&call_runtime); } // Calculate power with integer exponent. @@ -2181,9 +2180,11 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ movsd(double_scratch2, double_result); // Load double_exponent with 1. // Get absolute value of exponent. - Label while_true, no_multiply; - const uint32_t kClearSignBitMask = 0x7FFFFFFF; - __ andl(scratch, Immediate(kClearSignBitMask)); + Label no_neg, while_true, no_multiply; + __ testl(scratch, scratch); + __ j(positive, &no_neg, Label::kNear); + __ negl(scratch); + __ bind(&no_neg); __ bind(&while_true); __ shrl(scratch, Immediate(1)); @@ -2194,8 +2195,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ mulsd(double_scratch, double_scratch); __ j(not_zero, &while_true); - // scratch has the original value of the exponent - if the exponent is - // negative, return 1/result. + // If the exponent is negative, return 1/result. __ testl(exponent, exponent); __ j(greater, &done); __ divsd(double_scratch2, double_result); @@ -2204,27 +2204,28 @@ void MathPowStub::Generate(MacroAssembler* masm) { // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. __ xorps(double_scratch2, double_scratch2); __ ucomisd(double_scratch2, double_result); - __ j(equal, &double_int_runtime); + // double_exponent aliased as double_scratch2 has already been overwritten + // and may not have contained the exponent value in the first place when the + // input was a smi. We reset it with exponent value before bailing out. + __ j(not_equal, &done); + __ cvtlsi2sd(double_exponent, exponent); // Returning or bailing out. + Counters* counters = masm->isolate()->counters(); if (exponent_type_ == ON_STACK) { + // The arguments are still on the stack. + __ bind(&call_runtime); + __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); + // The stub is called from non-optimized code, which expects the result // as heap number in eax. __ bind(&done); - __ AllocateHeapNumber(rax, rcx, &generic_runtime); + __ AllocateHeapNumber(rax, rcx, &call_runtime); __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), double_result); + __ IncrementCounter(counters->math_pow(), 1); __ ret(2 * kPointerSize); - - // The arguments are still on the stack. - __ bind(&generic_runtime); - __ bind(&double_int_runtime); - __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); } else { - __ jmp(&done); - - Label return_from_runtime; - StubRuntimeCallHelper callhelper; - __ bind(&generic_runtime); + __ bind(&call_runtime); // Move base to the correct argument register. Exponent is already in xmm1. __ movsd(xmm0, double_base); ASSERT(double_exponent.is(xmm1)); @@ -2234,27 +2235,13 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ CallCFunction( ExternalReference::power_double_double_function(masm->isolate()), 2); } - __ jmp(&return_from_runtime, Label::kNear); - - __ bind(&double_int_runtime); - // Move base to the correct argument register. - __ movsd(xmm0, double_base); - // Exponent is already in the correct argument register: - // edi (not rdi) on Linux and edx on Windows. - { - AllowExternalCallThatCantCauseGC scope(masm); - __ PrepareCallCFunction(2); - __ CallCFunction( - ExternalReference::power_double_int_function(masm->isolate()), 2); - } - - __ bind(&return_from_runtime); // Return value is in xmm0. __ movsd(double_result, xmm0); // Restore context register. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ bind(&done); + __ IncrementCounter(counters->math_pow(), 1); __ ret(0); } }