Changeset 200208 in webkit
- Timestamp:
- Apr 28, 2016 1:50:08 PM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 1 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r200200 r200208 1 2016-04-28 Benjamin Poulain <bpoulain@apple.com> 2 3 [JSC] Unify Math.pow() accross all tiers 4 https://bugs.webkit.org/show_bug.cgi?id=157121 5 6 Reviewed by Geoffrey Garen. 7 8 My previous optimizations of DFG compile time have slowly 9 regressed Sunspider's math-partial-sums. 10 11 What is happenning is baseline used a thunk for Math.pow() 12 that has a special case for an exponent of -0.5, while 13 DFG/FTL have other special cases for other exponents. 14 The faster we get to DFG, the less time we spend in that fast 15 case for -0.5. 16 17 While looking into this, I discovered some correctness issues. Baseline 18 optimizes y=-0.5 by turning it into 1/sqrt(). DFG/FTL optimize constant 19 y=0.5 by turning it into sqrt(). The problem is sqrt() behaves differently 20 for -0 and -Infinity. With sqrt(), negative numbers are undefined, 21 and the result is NaN. With pow(), they have a result. 22 23 Something else that has bothered me for a while is that Math.pow() 24 with the same arguments give you different results in LLINT, Baseline, 25 and DFG/FTL. This seems a bit dangerous for numerical stability. 26 27 With this patch, I unify the behaviors for all tiers while keeping 28 the "special cases". 29 30 We have pow() that is super slow, but most callers don't need the 31 full power. We have: 32 -pow() with an exponent between 0 and 1000 is a fast path implemented 33 by multiplication only. 34 -pow(x, 0.5) is sqrt with special checks for negative values. 35 -pow(x, -0.5) is sqrt with special checks for negative values. 36 37 The C++ implementation handles all those optimizations too. This ensure 38 you get the same results from LLINT to FTL. 39 40 The thunk is eliminated, it was producing incorrect results and only 41 optimized Sunspider's partial-sums. 42 43 DFG gets the optimized integer, 0.5 and -0.5 cases since those are important 44 for somewhat-hot code. DFG falls back to the C++ code for any non-obvious case. 45 46 FTL gets the full C++ implementation inlined in B3. B3 knows how to eliminate 47 all the dead cases so you get the best if your code is hot enough to reach FTL. 48 49 * dfg/DFGFixupPhase.cpp: 50 (JSC::DFG::FixupPhase::fixupNode): Deleted. 51 * dfg/DFGNode.h: 52 (JSC::DFG::Node::convertToArithSqrt): Deleted. 53 * dfg/DFGNodeType.h: 54 * dfg/DFGSpeculativeJIT.cpp: 55 (JSC::DFG::compileArithPowIntegerFastPath): 56 (JSC::DFG::SpeculativeJIT::compileArithPow): 57 * dfg/DFGStrengthReductionPhase.cpp: 58 (JSC::DFG::StrengthReductionPhase::handleNode): 59 * ftl/FTLLowerDFGToB3.cpp: 60 (JSC::FTL::DFG::LowerDFGToB3::compileArithPow): 61 * jit/ThunkGenerators.cpp: 62 (JSC::powThunkGenerator): Deleted. 63 * jit/ThunkGenerators.h: 64 * runtime/MathCommon.cpp: 65 (JSC::operationMathPow): 66 * runtime/MathCommon.h: 67 * runtime/VM.cpp: 68 (JSC::thunkGeneratorForIntrinsic): Deleted. 69 * tests/stress/math-pow-stable-results.js: Added. 70 Getting consistent results when tiering up is new. 71 This test verify that results always remains the same as LLINT. 72 73 * tests/stress/math-pow-with-constants.js: 74 (testPowUsedAsSqrt): 75 (powUsedAsOneOverSqrt): 76 (testPowUsedAsOneOverSqrt): 77 (powUsedAsSquare): 78 (testPowUsedAsSquare): 79 1 80 2016-04-28 Mark Lam <mark.lam@apple.com> 2 81 -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r200149 r200208 350 350 351 351 case ArithPow: { 352 node->setResult(NodeResultDouble);353 352 if (node->child2()->shouldSpeculateInt32OrBooleanForArithmetic()) { 354 353 fixDoubleOrBooleanEdge(node->child1()); -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r200117 r200208 632 632 ASSERT(m_op == ToPrimitive); 633 633 m_op = ToString; 634 }635 636 void convertToArithSqrt()637 {638 ASSERT(m_op == ArithPow);639 child2() = Edge();640 m_op = ArithSqrt;641 634 } 642 635 -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r200149 r200208 154 154 macro(ArithMax, NodeResultNumber) \ 155 155 macro(ArithFRound, NodeResultNumber) \ 156 macro(ArithPow, NodeResult Number) \156 macro(ArithPow, NodeResultDouble) \ 157 157 macro(ArithRandom, NodeResultDouble | NodeMustGenerate) \ 158 158 macro(ArithRound, NodeResultNumber) \ -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r200149 r200208 4723 4723 { 4724 4724 MacroAssembler::JumpList skipFastPath; 4725 skipFastPath.append(assembler.branch32(MacroAssembler::Above, yOperand, MacroAssembler::TrustedImm32( 1000)));4725 skipFastPath.append(assembler.branch32(MacroAssembler::Above, yOperand, MacroAssembler::TrustedImm32(maxExponentForIntegerMathPow))); 4726 4726 4727 4727 static const double oneConstant = 1.0; … … 4771 4771 doubleResult(resultFpr, node); 4772 4772 return; 4773 } 4774 4775 if (node->child2()->isDoubleConstant()) { 4776 double exponent = node->child2()->asNumber(); 4777 static const double infinityConstant = std::numeric_limits<double>::infinity(); 4778 static const double minusInfinityConstant = -std::numeric_limits<double>::infinity(); 4779 if (exponent == 0.5) { 4780 SpeculateDoubleOperand xOperand(this, node->child1()); 4781 FPRTemporary result(this); 4782 FPRReg xOperandFpr = xOperand.fpr(); 4783 FPRReg resultFpr = result.fpr(); 4784 4785 m_jit.moveZeroToDouble(resultFpr); 4786 MacroAssembler::Jump xIsZeroOrNegativeZero = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr); 4787 4788 m_jit.loadDouble(TrustedImmPtr(&minusInfinityConstant), resultFpr); 4789 MacroAssembler::Jump xIsMinusInfinity = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr); 4790 m_jit.sqrtDouble(xOperandFpr, resultFpr); 4791 MacroAssembler::Jump doneWithSqrt = m_jit.jump(); 4792 4793 xIsMinusInfinity.link(&m_jit); 4794 if (isX86()) 4795 m_jit.loadDouble(TrustedImmPtr(&infinityConstant), resultFpr); 4796 else 4797 m_jit.absDouble(resultFpr, resultFpr); 4798 4799 xIsZeroOrNegativeZero.link(&m_jit); 4800 doneWithSqrt.link(&m_jit); 4801 doubleResult(resultFpr, node); 4802 return; 4803 } 4804 if (exponent == -0.5) { 4805 SpeculateDoubleOperand xOperand(this, node->child1()); 4806 FPRTemporary scratch(this); 4807 FPRTemporary result(this); 4808 FPRReg xOperandFpr = xOperand.fpr(); 4809 FPRReg scratchFPR = scratch.fpr(); 4810 FPRReg resultFpr = result.fpr(); 4811 4812 m_jit.moveZeroToDouble(resultFpr); 4813 MacroAssembler::Jump xIsZeroOrNegativeZero = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr); 4814 4815 m_jit.loadDouble(TrustedImmPtr(&minusInfinityConstant), resultFpr); 4816 MacroAssembler::Jump xIsMinusInfinity = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr); 4817 4818 static const double oneConstant = 1.; 4819 m_jit.loadDouble(TrustedImmPtr(&oneConstant), resultFpr); 4820 m_jit.sqrtDouble(xOperandFpr, scratchFPR); 4821 m_jit.divDouble(resultFpr, scratchFPR, resultFpr); 4822 MacroAssembler::Jump doneWithSqrt = m_jit.jump(); 4823 4824 xIsZeroOrNegativeZero.link(&m_jit); 4825 m_jit.loadDouble(TrustedImmPtr(&infinityConstant), resultFpr); 4826 MacroAssembler::Jump doneWithBaseZero = m_jit.jump(); 4827 4828 xIsMinusInfinity.link(&m_jit); 4829 m_jit.moveZeroToDouble(resultFpr); 4830 4831 doneWithBaseZero.link(&m_jit); 4832 doneWithSqrt.link(&m_jit); 4833 doubleResult(resultFpr, node); 4834 return; 4835 } 4773 4836 } 4774 4837 -
trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
r200117 r200208 171 171 if (yOperandValue == 1) { 172 172 convertToIdentityOverChild1(); 173 } else if (yOperandValue == 0.5) { 174 m_insertionSet.insertCheck(m_nodeIndex, m_node); 175 m_node->convertToArithSqrt(); 173 m_changed = true; 174 } else if (yOperandValue == 2) { 175 m_node->setOp(ArithMul); 176 m_node->child2() = m_node->child1(); 176 177 m_changed = true; 177 178 } -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r200149 r200208 1860 1860 LBasicBlock integerExponentPowBlock = m_out.newBlock(); 1861 1861 LBasicBlock doubleExponentPowBlockEntry = m_out.newBlock(); 1862 LBasicBlock nanExceptionBaseIsOne = m_out.newBlock(); 1862 1863 LBasicBlock nanExceptionExponentIsInfinity = m_out.newBlock(); 1863 LBasicBlock nanExceptionBaseIsOne = m_out.newBlock(); 1864 LBasicBlock testExponentIsOneHalf = m_out.newBlock(); 1865 LBasicBlock handleBaseZeroExponentIsOneHalf = m_out.newBlock(); 1866 LBasicBlock handleInfinityForExponentIsOneHalf = m_out.newBlock(); 1867 LBasicBlock exponentIsOneHalfNormal = m_out.newBlock(); 1868 LBasicBlock exponentIsOneHalfInfinity = m_out.newBlock(); 1869 LBasicBlock testExponentIsNegativeOneHalf = m_out.newBlock(); 1870 LBasicBlock testBaseZeroExponentIsNegativeOneHalf = m_out.newBlock(); 1871 LBasicBlock handleBaseZeroExponentIsNegativeOneHalf = m_out.newBlock(); 1872 LBasicBlock handleInfinityForExponentIsNegativeOneHalf = m_out.newBlock(); 1873 LBasicBlock exponentIsNegativeOneHalfNormal = m_out.newBlock(); 1874 LBasicBlock exponentIsNegativeOneHalfInfinity = m_out.newBlock(); 1864 1875 LBasicBlock powBlock = m_out.newBlock(); 1865 1876 LBasicBlock nanExceptionResultIsNaN = m_out.newBlock(); … … 1872 1883 1873 1884 LBasicBlock lastNext = m_out.appendTo(integerExponentIsSmallBlock, integerExponentPowBlock); 1874 LValue integerExponentBelow 1000 = m_out.below(integerExponent, m_out.constInt32(1000));1875 m_out.branch(integerExponentBelow 1000, usually(integerExponentPowBlock), rarely(doubleExponentPowBlockEntry));1885 LValue integerExponentBelowMax = m_out.belowOrEqual(integerExponent, m_out.constInt32(maxExponentForIntegerMathPow)); 1886 m_out.branch(integerExponentBelowMax, usually(integerExponentPowBlock), rarely(doubleExponentPowBlockEntry)); 1876 1887 1877 1888 m_out.appendTo(integerExponentPowBlock, doubleExponentPowBlockEntry); … … 1880 1891 1881 1892 // If y is NaN, the result is NaN. 1882 m_out.appendTo(doubleExponentPowBlockEntry, nanException ExponentIsInfinity);1893 m_out.appendTo(doubleExponentPowBlockEntry, nanExceptionBaseIsOne); 1883 1894 LValue exponentIsNaN; 1884 1895 if (provenType(m_node->child2()) & SpecDoubleNaN) … … 1886 1897 else 1887 1898 exponentIsNaN = m_out.booleanFalse; 1888 m_out.branch(exponentIsNaN, rarely(nanExceptionResultIsNaN), usually(nanException ExponentIsInfinity));1899 m_out.branch(exponentIsNaN, rarely(nanExceptionResultIsNaN), usually(nanExceptionBaseIsOne)); 1889 1900 1890 1901 // If abs(x) is 1 and y is +infinity, the result is NaN. 1891 1902 // If abs(x) is 1 and y is -infinity, the result is NaN. 1892 m_out.appendTo(nanExceptionExponentIsInfinity, nanExceptionBaseIsOne); 1903 1904 // Test if base == 1. 1905 m_out.appendTo(nanExceptionBaseIsOne, nanExceptionExponentIsInfinity); 1906 LValue absoluteBase = m_out.doubleAbs(base); 1907 LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1)); 1908 m_out.branch(absoluteBaseIsOne, rarely(nanExceptionExponentIsInfinity), usually(testExponentIsOneHalf)); 1909 1910 // Test if abs(y) == Infinity. 1911 m_out.appendTo(nanExceptionExponentIsInfinity, testExponentIsOneHalf); 1893 1912 LValue absoluteExponent = m_out.doubleAbs(exponent); 1894 1913 LValue absoluteExponentIsInfinity = m_out.doubleEqual(absoluteExponent, m_out.constDouble(std::numeric_limits<double>::infinity())); 1895 m_out.branch(absoluteExponentIsInfinity, rarely(nanExceptionBaseIsOne), usually(powBlock)); 1896 1897 m_out.appendTo(nanExceptionBaseIsOne, powBlock); 1898 LValue absoluteBase = m_out.doubleAbs(base); 1899 LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1)); 1900 m_out.branch(absoluteBaseIsOne, unsure(nanExceptionResultIsNaN), unsure(powBlock)); 1914 m_out.branch(absoluteExponentIsInfinity, rarely(nanExceptionResultIsNaN), usually(testExponentIsOneHalf)); 1915 1916 // If y == 0.5 or y == -0.5, handle it through SQRT. 1917 // We have be carefuly with -0 and -Infinity. 1918 1919 // Test if y == 0.5 1920 m_out.appendTo(testExponentIsOneHalf, handleBaseZeroExponentIsOneHalf); 1921 LValue exponentIsOneHalf = m_out.doubleEqual(exponent, m_out.constDouble(0.5)); 1922 m_out.branch(exponentIsOneHalf, rarely(handleBaseZeroExponentIsOneHalf), usually(testExponentIsNegativeOneHalf)); 1923 1924 // Handle x == -0. 1925 m_out.appendTo(handleBaseZeroExponentIsOneHalf, handleInfinityForExponentIsOneHalf); 1926 LValue baseIsZeroExponentIsOneHalf = m_out.doubleEqual(base, m_out.doubleZero); 1927 ValueFromBlock zeroResultExponentIsOneHalf = m_out.anchor(m_out.doubleZero); 1928 m_out.branch(baseIsZeroExponentIsOneHalf, rarely(continuation), usually(handleInfinityForExponentIsOneHalf)); 1929 1930 // Test if abs(x) == Infinity. 1931 m_out.appendTo(handleInfinityForExponentIsOneHalf, exponentIsOneHalfNormal); 1932 LValue absoluteBaseIsInfinityOneHalf = m_out.doubleEqual(absoluteBase, m_out.constDouble(std::numeric_limits<double>::infinity())); 1933 m_out.branch(absoluteBaseIsInfinityOneHalf, rarely(exponentIsOneHalfInfinity), usually(exponentIsOneHalfNormal)); 1934 1935 // The exponent is 0.5, the base is finite or NaN, we can use SQRT. 1936 m_out.appendTo(exponentIsOneHalfNormal, exponentIsOneHalfInfinity); 1937 ValueFromBlock sqrtResult = m_out.anchor(m_out.doubleSqrt(base)); 1938 m_out.jump(continuation); 1939 1940 // The exponent is 0.5, the base is infinite, the result is always infinite. 1941 m_out.appendTo(exponentIsOneHalfInfinity, testExponentIsNegativeOneHalf); 1942 ValueFromBlock sqrtInfinityResult = m_out.anchor(m_out.constDouble(std::numeric_limits<double>::infinity())); 1943 m_out.jump(continuation); 1944 1945 // Test if y == -0.5 1946 m_out.appendTo(testExponentIsNegativeOneHalf, testBaseZeroExponentIsNegativeOneHalf); 1947 LValue exponentIsNegativeOneHalf = m_out.doubleEqual(exponent, m_out.constDouble(-0.5)); 1948 m_out.branch(exponentIsNegativeOneHalf, rarely(testBaseZeroExponentIsNegativeOneHalf), usually(powBlock)); 1949 1950 // Handle x == -0. 1951 m_out.appendTo(testBaseZeroExponentIsNegativeOneHalf, handleBaseZeroExponentIsNegativeOneHalf); 1952 LValue baseIsZeroExponentIsNegativeOneHalf = m_out.doubleEqual(base, m_out.doubleZero); 1953 m_out.branch(baseIsZeroExponentIsNegativeOneHalf, rarely(handleBaseZeroExponentIsNegativeOneHalf), usually(handleInfinityForExponentIsNegativeOneHalf)); 1954 1955 m_out.appendTo(handleBaseZeroExponentIsNegativeOneHalf, handleInfinityForExponentIsNegativeOneHalf); 1956 ValueFromBlock oneOverSqrtZeroResult = m_out.anchor(m_out.constDouble(std::numeric_limits<double>::infinity())); 1957 m_out.jump(continuation); 1958 1959 // Test if abs(x) == Infinity. 1960 m_out.appendTo(handleInfinityForExponentIsNegativeOneHalf, exponentIsNegativeOneHalfNormal); 1961 LValue absoluteBaseIsInfinityNegativeOneHalf = m_out.doubleEqual(absoluteBase, m_out.constDouble(std::numeric_limits<double>::infinity())); 1962 m_out.branch(absoluteBaseIsInfinityNegativeOneHalf, rarely(exponentIsNegativeOneHalfInfinity), usually(exponentIsNegativeOneHalfNormal)); 1963 1964 // The exponent is -0.5, the base is finite or NaN, we can use 1/SQRT. 1965 m_out.appendTo(exponentIsNegativeOneHalfNormal, exponentIsNegativeOneHalfInfinity); 1966 LValue sqrtBase = m_out.doubleSqrt(base); 1967 ValueFromBlock oneOverSqrtResult = m_out.anchor(m_out.div(m_out.constDouble(1.), sqrtBase)); 1968 m_out.jump(continuation); 1969 1970 // The exponent is -0.5, the base is infinite, the result is always zero. 1971 m_out.appendTo(exponentIsNegativeOneHalfInfinity, powBlock); 1972 ValueFromBlock oneOverSqrtInfinityResult = m_out.anchor(m_out.doubleZero); 1973 m_out.jump(continuation); 1901 1974 1902 1975 m_out.appendTo(powBlock, nanExceptionResultIsNaN); … … 1909 1982 1910 1983 m_out.appendTo(continuation, lastNext); 1911 setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, powResult, pureNan));1984 setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, zeroResultExponentIsOneHalf, sqrtResult, sqrtInfinityResult, oneOverSqrtZeroResult, oneOverSqrtResult, oneOverSqrtInfinityResult, powResult, pureNan)); 1912 1985 } 1913 1986 } -
trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp
r199946 r200208 783 783 defineUnaryDoubleOpWrapper(trunc); 784 784 785 static const double oneConstant = 1.0;786 static const double negativeHalfConstant = -0.5;787 785 static const double halfConstant = 0.5; 788 786 … … 993 991 } 994 992 995 MacroAssemblerCodeRef powThunkGenerator(VM* vm)996 {997 SpecializedThunkJIT jit(vm, 2);998 if (!jit.supportsFloatingPoint())999 return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));1000 1001 jit.loadDouble(MacroAssembler::TrustedImmPtr(&oneConstant), SpecializedThunkJIT::fpRegT1);1002 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);1003 MacroAssembler::Jump nonIntExponent;1004 jit.loadInt32Argument(1, SpecializedThunkJIT::regT0, nonIntExponent);1005 jit.appendFailure(jit.branch32(MacroAssembler::LessThan, SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(0)));1006 1007 MacroAssembler::Jump exponentIsZero = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0);1008 MacroAssembler::Label startLoop(jit.label());1009 1010 MacroAssembler::Jump exponentIsEven = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(1));1011 jit.mulDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);1012 exponentIsEven.link(&jit);1013 jit.mulDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);1014 jit.rshift32(MacroAssembler::TrustedImm32(1), SpecializedThunkJIT::regT0);1015 jit.branchTest32(MacroAssembler::NonZero, SpecializedThunkJIT::regT0).linkTo(startLoop, &jit);1016 1017 exponentIsZero.link(&jit);1018 1019 {1020 SpecializedThunkJIT::JumpList doubleResult;1021 jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT0);1022 jit.returnInt32(SpecializedThunkJIT::regT0);1023 doubleResult.link(&jit);1024 jit.returnDouble(SpecializedThunkJIT::fpRegT1);1025 }1026 1027 if (jit.supportsFloatingPointSqrt()) {1028 nonIntExponent.link(&jit);1029 jit.loadDouble(MacroAssembler::TrustedImmPtr(&negativeHalfConstant), SpecializedThunkJIT::fpRegT3);1030 jit.loadDoubleArgument(1, SpecializedThunkJIT::fpRegT2, SpecializedThunkJIT::regT0);1031 jit.appendFailure(jit.branchDouble(MacroAssembler::DoubleLessThanOrEqual, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1));1032 jit.appendFailure(jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, SpecializedThunkJIT::fpRegT2, SpecializedThunkJIT::fpRegT3));1033 jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);1034 jit.divDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);1035 1036 SpecializedThunkJIT::JumpList doubleResult;1037 jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT0);1038 jit.returnInt32(SpecializedThunkJIT::regT0);1039 doubleResult.link(&jit);1040 jit.returnDouble(SpecializedThunkJIT::fpRegT1);1041 } else1042 jit.appendFailure(nonIntExponent);1043 1044 return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "pow");1045 }1046 1047 993 MacroAssemblerCodeRef imulThunkGenerator(VM* vm) 1048 994 { -
trunk/Source/JavaScriptCore/jit/ThunkGenerators.h
r199946 r200208 62 62 MacroAssemblerCodeRef roundThunkGenerator(VM*); 63 63 MacroAssemblerCodeRef sqrtThunkGenerator(VM*); 64 MacroAssemblerCodeRef powThunkGenerator(VM*);65 64 MacroAssemblerCodeRef imulThunkGenerator(VM*); 66 65 MacroAssemblerCodeRef randomThunkGenerator(VM*); -
trunk/Source/JavaScriptCore/runtime/MathCommon.cpp
r199943 r200208 1 1 /* 2 * Copyright (C) 2015 Apple Inc. All rights reserved.2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 415 415 if (std::isnan(y)) 416 416 return PNaN; 417 if (std::isinf(y) && fabs(x) == 1) 417 double absoluteBase = fabs(x); 418 if (absoluteBase == 1 && std::isinf(y)) 418 419 return PNaN; 420 421 if (y == 0.5) { 422 if (!absoluteBase) 423 return 0; 424 if (absoluteBase == std::numeric_limits<double>::infinity()) 425 return std::numeric_limits<double>::infinity(); 426 return sqrt(x); 427 } 428 429 if (y == -0.5) { 430 if (!absoluteBase) 431 return std::numeric_limits<double>::infinity(); 432 if (absoluteBase == std::numeric_limits<double>::infinity()) 433 return 0.; 434 return 1. / sqrt(x); 435 } 436 419 437 int32_t yAsInt = y; 420 if (static_cast<double>(yAsInt) != y || yAsInt < 0) 421 return mathPowInternal(x, y); 422 423 // If the exponent is a positive int32 integer, we do a fast exponentiation 424 double result = 1; 425 while (yAsInt) { 426 if (yAsInt & 1) 427 result *= x; 428 x *= x; 429 yAsInt >>= 1; 430 } 431 return result; 438 if (static_cast<double>(yAsInt) == y && yAsInt > 0 && yAsInt <= maxExponentForIntegerMathPow) { 439 // If the exponent is a small positive int32 integer, we do a fast exponentiation 440 double result = 1; 441 while (yAsInt) { 442 if (yAsInt & 1) 443 result *= x; 444 x *= x; 445 yAsInt >>= 1; 446 } 447 return result; 448 449 } 450 return mathPowInternal(x, y); 432 451 } 433 452 -
trunk/Source/JavaScriptCore/runtime/MathCommon.h
r199913 r200208 36 36 37 37 namespace JSC { 38 39 const int32_t maxExponentForIntegerMathPow = 1000; 38 40 double JIT_OPERATION operationMathPow(double x, double y) WTF_INTERNAL; 39 41 -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r200177 r200208 475 475 case SqrtIntrinsic: 476 476 return sqrtThunkGenerator; 477 case PowIntrinsic:478 return powThunkGenerator;479 477 case AbsIntrinsic: 480 478 return absThunkGenerator; -
trunk/Source/JavaScriptCore/tests/stress/math-pow-with-constants.js
r180360 r200208 45 45 46 46 function testPowUsedAsSqrt() { 47 for ( var i = 0; i < 10000; ++i) {48 varresult = powUsedAsSqrt(4);47 for (let i = 0; i < 1e4; ++i) { 48 let result = powUsedAsSqrt(4); 49 49 if (result !== Math.sqrt(4)) 50 50 throw "Error: powUsedAsSqrt(4) should be 2, was = " + result; 51 } 52 for (var i = 0; i < 10000; ++i) { 53 var result = powUsedAsSqrt(4.4); 51 result = powUsedAsSqrt(4.4); 54 52 if (result !== Math.sqrt(4.4)) 55 53 throw "Error: powUsedAsSqrt(4) should be " + Math.sqrt(4.4) + ", was = " + result; 56 } 57 54 if (powUsedAsSqrt(Infinity) !== Infinity) 55 throw "Failed powUsedAsSqrt(Infinity)"; 56 if (powUsedAsSqrt(-Infinity) !== Infinity) 57 throw "Failed powUsedAsSqrt(-Infinity)"; 58 let nanResult = powUsedAsSqrt(NaN) 59 if (nanResult === nanResult) 60 throw "Failed powUsedAsSqrt(NaN)"; 61 let zeroResult = powUsedAsSqrt(0.) 62 if (zeroResult || (1 / zeroResult) !== Infinity) 63 throw "Failed powUsedAsSqrt(0.)"; 64 let negativeZeroResult = powUsedAsSqrt(-0) 65 if (negativeZeroResult || (1 / negativeZeroResult) !== Infinity) 66 throw "Failed powUsedAsSqrt(-0)"; 67 } 58 68 } 59 69 testPowUsedAsSqrt(); 60 70 71 function powUsedAsOneOverSqrt(x) { 72 return Math.pow(x, -0.5); 73 } 74 noInline(powUsedAsOneOverSqrt); 75 76 function testPowUsedAsOneOverSqrt() { 77 for (let i = 0; i < 1e4; ++i) { 78 let result = powUsedAsOneOverSqrt(4); 79 if (result !== 0.5) 80 throw "Error: powUsedAsOneOverSqrt(4) should be 0.5, was = " + result; 81 result = powUsedAsOneOverSqrt(4.4); 82 if (result !== 1/Math.sqrt(4.4)) 83 throw "Error: powUsedAsOneOverSqrt(4) should be " + 1/Math.sqrt(4.4) + ", was = " + result; 84 if (powUsedAsOneOverSqrt(Infinity) !== 0) 85 throw "Failed powUsedAsOneOverSqrt(Infinity)"; 86 if (powUsedAsOneOverSqrt(-Infinity) !== 0) 87 throw "Failed powUsedAsOneOverSqrt(-Infinity)"; 88 let nanResult = powUsedAsOneOverSqrt(NaN) 89 if (nanResult === nanResult) 90 throw "Failed powUsedAsOneOverSqrt(NaN)"; 91 if (powUsedAsOneOverSqrt(0) !== Infinity) 92 throw "Failed powUsedAsOneOverSqrt(0)"; 93 if (powUsedAsOneOverSqrt(-0.) !== Infinity) 94 throw "Failed powUsedAsOneOverSqrt(-0.)"; 95 } 96 } 97 testPowUsedAsOneOverSqrt(); 98 99 function powUsedAsSquare(x) { 100 return Math.pow(x, 2); 101 } 102 noInline(powUsedAsSquare); 103 104 function testPowUsedAsSquare() { 105 for (let i = 0; i < 1e4; ++i) { 106 let result = powUsedAsSquare(2); 107 if (result !== 4) 108 throw "Error: powUsedAsSquare(4) should be 2, was = " + result; 109 result = powUsedAsSquare(4.4); 110 if (result !== 19.360000000000003) 111 throw "Error: powUsedAsSquare(4) should be " + 19.360000000000003 + ", was = " + result; 112 result = powUsedAsSquare(Math.PI); 113 if (result !== 9.869604401089358) 114 throw "Error: powUsedAsSquare(4) should be " + 9.869604401089358 + ", was = " + result; 115 if (powUsedAsSquare(Infinity) !== Infinity) 116 throw "Failed powUsedAsSquare(Infinity)"; 117 if (powUsedAsSquare(-Infinity) !== Infinity) 118 throw "Failed powUsedAsSquare(-Infinity)"; 119 let nanResult = powUsedAsSquare(NaN) 120 if (nanResult === nanResult) 121 throw "Failed powUsedAsSquare(NaN)"; 122 let zeroResult = powUsedAsSquare(0.) 123 if (zeroResult || (1 / zeroResult) !== Infinity) 124 throw "Failed powUsedAsSquare(0.)"; 125 let negativeZeroResult = powUsedAsSquare(-0) 126 if (negativeZeroResult || (1 / negativeZeroResult) !== Infinity) 127 throw "Failed powUsedAsSquare(-0)"; 128 } 129 } 130 testPowUsedAsSquare(); 61 131 62 132 function intIntConstantsSmallNumbers() {
Note: See TracChangeset
for help on using the changeset viewer.