Title: [180098] trunk/Source/_javascript_Core
Revision
180098
Author
benja...@webkit.org
Date
2015-02-13 20:20:21 -0800 (Fri, 13 Feb 2015)

Log Message

Add a DFG node for the Pow Intrinsics
https://bugs.webkit.org/show_bug.cgi?id=141540

Patch by Benjamin Poulain <bpoul...@apple.com> on 2015-02-13
Reviewed by Filip Pizlo.

Add a DFG Node for PowIntrinsic. This patch covers the basic cases
need to avoid massive regression. I will iterate over the node to cover
the missing types.

With this patch I get the following progressions on benchmarks:
-LongSpider's math-partial-sums: +5%.
-Kraken's imaging-darkroom: +17%
-AsmBench's cray.c: +6.6%
-CompressionBench: +2.2% globally.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
Cover a couple of trivial cases:
-If the exponent is zero, the result is always one, regardless of the base.
-If both arguments are constants, compute the result at compile time.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
We only support 2 basic cases at this time:
-Math.pow(double, int)
-Math.pow(double, double).

I'll cover Math.pow(int, int) in a follow up.

* dfg/DFGNode.h:
(JSC::DFG::Node::convertToArithSqrt):
(JSC::DFG::Node::arithNodeFlags):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::compileArithPowIntegerFastPath):
(JSC::DFG::SpeculativeJIT::compileArithPow):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileArithPow):
* ftl/FTLOutput.h:
(JSC::FTL::Output::doublePow):
(JSC::FTL::Output::doublePowi):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* runtime/MathObject.cpp:
(JSC::mathProtoFuncPow):
(JSC::isDenormal): Deleted.
(JSC::isEdgeCase): Deleted.
(JSC::mathPow): Deleted.

* tests/stress/math-pow-basics.js: Added.
* tests/stress/math-pow-integer-exponent-fastpath.js: Added.
* tests/stress/math-pow-nan-behaviors.js: Added.
* tests/stress/math-pow-with-constants.js: Added.
Start some basic testing of Math.pow().
Due to the various transform, the value change when the code tiers up,
I covered this by checking for approximate values.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (180097 => 180098)


--- trunk/Source/_javascript_Core/ChangeLog	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-02-14 04:20:21 UTC (rev 180098)
@@ -1,5 +1,89 @@
 2015-02-13  Benjamin Poulain  <bpoul...@apple.com>
 
+        Add a DFG node for the Pow Intrinsics
+        https://bugs.webkit.org/show_bug.cgi?id=141540
+
+        Reviewed by Filip Pizlo.
+
+        Add a DFG Node for PowIntrinsic. This patch covers the basic cases
+        need to avoid massive regression. I will iterate over the node to cover
+        the missing types.
+
+        With this patch I get the following progressions on benchmarks:
+        -LongSpider's math-partial-sums: +5%.
+        -Kraken's imaging-darkroom: +17%
+        -AsmBench's cray.c: +6.6%
+        -CompressionBench: +2.2% globally.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        Cover a couple of trivial cases:
+        -If the exponent is zero, the result is always one, regardless of the base.
+        -If both arguments are constants, compute the result at compile time.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        We only support 2 basic cases at this time:
+        -Math.pow(double, int)
+        -Math.pow(double, double).
+
+        I'll cover Math.pow(int, int) in a follow up.
+
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToArithSqrt):
+        (JSC::DFG::Node::arithNodeFlags):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        (JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::compileArithPowIntegerFastPath):
+        (JSC::DFG::SpeculativeJIT::compileArithPow):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStrengthReductionPhase.cpp:
+        (JSC::DFG::StrengthReductionPhase::handleNode):
+        * dfg/DFGValidate.cpp:
+        (JSC::DFG::Validate::validate):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLIntrinsicRepository.h:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileArithPow):
+        * ftl/FTLOutput.h:
+        (JSC::FTL::Output::doublePow):
+        (JSC::FTL::Output::doublePowi):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * runtime/MathObject.cpp:
+        (JSC::mathProtoFuncPow):
+        (JSC::isDenormal): Deleted.
+        (JSC::isEdgeCase): Deleted.
+        (JSC::mathPow): Deleted.
+
+        * tests/stress/math-pow-basics.js: Added.
+        * tests/stress/math-pow-integer-exponent-fastpath.js: Added.
+        * tests/stress/math-pow-nan-behaviors.js: Added.
+        * tests/stress/math-pow-with-constants.js: Added.
+        Start some basic testing of Math.pow().
+        Due to the various transform, the value change when the code tiers up,
+        I covered this by checking for approximate values.
+
+2015-02-13  Benjamin Poulain  <bpoul...@apple.com>
+
         ArithSqrt should not be conditional on supportsFloatingPointSqrt
         https://bugs.webkit.org/show_bug.cgi?id=141546
 

Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -508,6 +508,15 @@
     return value;
 }
 
+SpeculatedType typeOfDoublePow(SpeculatedType xValue, SpeculatedType yValue)
+{
+    // Math.pow() always return NaN if the exponent is NaN, unlike std::pow().
+    // We always set a pure NaN in that case.
+    if (yValue & SpecDoubleNaN)
+        xValue |= SpecDoublePureNaN;
+    return polluteDouble(xValue);
+}
+
 SpeculatedType typeOfDoubleBinaryOp(SpeculatedType a, SpeculatedType b)
 {
     return polluteDouble(a | b);

Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.h (180097 => 180098)


--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -416,6 +416,7 @@
 SpeculatedType typeOfDoubleNegation(SpeculatedType);
 SpeculatedType typeOfDoubleAbs(SpeculatedType);
 SpeculatedType typeOfDoubleFRound(SpeculatedType);
+SpeculatedType typeOfDoublePow(SpeculatedType, SpeculatedType);
 
 // This conservatively models the behavior of arbitrary double operations.
 SpeculatedType typeOfDoubleBinaryOp(SpeculatedType, SpeculatedType);

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -31,6 +31,7 @@
 #include "DFGAbstractInterpreter.h"
 #include "GetByIdStatus.h"
 #include "GetterSetter.h"
+#include "JITOperations.h"
 #include "Operations.h"
 #include "PutByIdStatus.h"
 #include "StringObject.h"
@@ -718,6 +719,24 @@
         }
         break;
     }
+
+    case ArithPow: {
+        JSValue childY = forNode(node->child2()).value();
+        if (childY && childY.isNumber()) {
+            if (!childY.asNumber()) {
+                setConstant(node, jsDoubleNumber(1));
+                break;
+            }
+
+            JSValue childX = forNode(node->child1()).value();
+            if (childX && childX.isNumber()) {
+                setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber())));
+                break;
+            }
+        }
+        forNode(node).setType(typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type));
+        break;
+    }
             
     case ArithSqrt: {
         JSValue child = forNode(node->child1()).value();

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -1684,6 +1684,18 @@
             return false;
         }
     }
+
+    case PowIntrinsic: {
+        if (argumentCountIncludingThis < 3) {
+            // Math.pow() and Math.pow(x) return NaN.
+            set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN)));
+            return true;
+        }
+        VirtualRegister xOperand = virtualRegisterForArgument(1, registerOffset);
+        VirtualRegister yOperand = virtualRegisterForArgument(2, registerOffset);
+        set(VirtualRegister(resultOperand), addToGraph(ArithPow, get(xOperand), get(yOperand)));
+        return true;
+    }
         
     case ArrayPushIntrinsic: {
         if (argumentCountIncludingThis != 2)

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -122,6 +122,7 @@
     case ArithAbs:
     case ArithMin:
     case ArithMax:
+    case ArithPow:
     case ArithSqrt:
     case ArithFRound:
     case ArithSin:

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -81,6 +81,7 @@
     case ArithAbs:
     case ArithMin:
     case ArithMax:
+    case ArithPow:
     case ArithSqrt:
     case ArithFRound:
     case ArithSin:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -337,6 +337,19 @@
             node->setResult(NodeResultDouble);
             break;
         }
+
+        case ArithPow: {
+            node->setResult(NodeResultDouble);
+            if (node->child2()->shouldSpeculateInt32OrBooleanForArithmetic()) {
+                fixDoubleOrBooleanEdge(node->child1());
+                fixIntOrBooleanEdge(node->child2());
+                break;
+            }
+
+            fixDoubleOrBooleanEdge(node->child1());
+            fixDoubleOrBooleanEdge(node->child2());
+            break;
+        }
             
         case ArithSqrt:
         case ArithFRound:

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -565,6 +565,13 @@
         ASSERT(m_op == ToPrimitive);
         m_op = ToString;
     }
+
+    void convertToArithSqrt()
+    {
+        ASSERT(m_op == ArithPow);
+        child2() = Edge();
+        m_op = ArithSqrt;
+    }
     
     JSValue asJSValue()
     {
@@ -775,7 +782,7 @@
     NodeFlags arithNodeFlags()
     {
         NodeFlags result = m_flags & NodeArithFlagsMask;
-        if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == DoubleAsInt32)
+        if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == DoubleAsInt32)
             return result;
         return result & ~NodeBytecodeNeedsNegZero;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -134,6 +134,7 @@
     macro(ArithMin, NodeResultNumber) \
     macro(ArithMax, NodeResultNumber) \
     macro(ArithFRound, NodeResultNumber) \
+    macro(ArithPow, NodeResultNumber) \
     macro(ArithSqrt, NodeResultNumber) \
     macro(ArithSin, NodeResultNumber) \
     macro(ArithCos, NodeResultNumber) \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -321,7 +321,8 @@
             }
             break;
         }
-            
+
+        case ArithPow:
         case ArithSqrt:
         case ArithFRound:
         case ArithSin:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -150,6 +150,7 @@
     case ArithAbs:
     case ArithMin:
     case ArithMax:
+    case ArithPow:
     case ArithSqrt:
     case ArithFRound:
     case ArithSin:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -3560,6 +3560,92 @@
     }
 }
 
+// For small positive integers , it is worth doing a tiny inline loop to exponentiate the base.
+// Every register is clobbered by this helper.
+static MacroAssembler::Jump compileArithPowIntegerFastPath(JITCompiler& assembler, FPRReg xOperand, GPRReg yOperand, FPRReg result)
+{
+    MacroAssembler::JumpList skipFastPath;
+    skipFastPath.append(assembler.branch32(MacroAssembler::LessThan, yOperand, MacroAssembler::TrustedImm32(0)));
+    skipFastPath.append(assembler.branch32(MacroAssembler::GreaterThan, yOperand, MacroAssembler::TrustedImm32(1000)));
+
+    static const double _oneConstant_ = 1.0;
+    assembler.loadDouble(MacroAssembler::TrustedImmPtr(&oneConstant), result);
+
+    MacroAssembler::Label startLoop(assembler.label());
+    MacroAssembler::Jump exponentIsEven = assembler.branchTest32(MacroAssembler::Zero, yOperand, MacroAssembler::TrustedImm32(1));
+    assembler.mulDouble(xOperand, result);
+    exponentIsEven.link(&assembler);
+    assembler.mulDouble(xOperand, xOperand);
+    assembler.rshift32(MacroAssembler::TrustedImm32(1), yOperand);
+    assembler.branchTest32(MacroAssembler::NonZero, yOperand).linkTo(startLoop, &assembler);
+
+    MacroAssembler::Jump skipSlowPath = assembler.jump();
+    skipFastPath.link(&assembler);
+
+    return skipSlowPath;
+}
+
+void SpeculativeJIT::compileArithPow(Node* node)
+{
+    if (node->child2().useKind() == Int32Use) {
+        SpeculateDoubleOperand xOperand(this, node->child1());
+        SpeculateInt32Operand yOperand(this, node->child2());
+        FPRReg xOperandfpr = xOperand.fpr();
+        GPRReg yOperandGpr = yOperand.gpr();
+        FPRTemporary yOperandfpr(this);
+
+        flushRegisters();
+
+        FPRResult result(this);
+        FPRReg resultFpr = result.fpr();
+
+        FPRTemporary xOperandCopy(this);
+        FPRReg xOperandCopyFpr = xOperandCopy.fpr();
+        m_jit.moveDouble(xOperandfpr, xOperandCopyFpr);
+
+        GPRTemporary counter(this);
+        GPRReg counterGpr = counter.gpr();
+        m_jit.move(yOperandGpr, counterGpr);
+
+        MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, counterGpr, resultFpr);
+        m_jit.convertInt32ToDouble(yOperandGpr, yOperandfpr.fpr());
+        callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr.fpr());
+
+        skipFallback.link(&m_jit);
+        doubleResult(resultFpr, node);
+        return;
+    }
+
+    SpeculateDoubleOperand xOperand(this, node->child1());
+    SpeculateDoubleOperand yOperand(this, node->child2());
+    FPRReg xOperandfpr = xOperand.fpr();
+    FPRReg yOperandfpr = yOperand.fpr();
+
+    flushRegisters();
+
+    FPRResult result(this);
+    FPRReg resultFpr = result.fpr();
+
+    FPRTemporary xOperandCopy(this);
+    FPRReg xOperandCopyFpr = xOperandCopy.fpr();
+
+    FPRTemporary scratch(this);
+    FPRReg scratchFpr = scratch.fpr();
+
+    GPRTemporary yOperandInteger(this);
+    GPRReg yOperandIntegerGpr = yOperandInteger.gpr();
+    MacroAssembler::JumpList failedExponentConversionToInteger;
+    m_jit.branchConvertDoubleToInt32(yOperandfpr, yOperandIntegerGpr, failedExponentConversionToInteger, scratchFpr, false);
+
+    m_jit.moveDouble(xOperandfpr, xOperandCopyFpr);
+    MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, yOperandInteger.gpr(), resultFpr);
+    failedExponentConversionToInteger.link(&m_jit);
+
+    callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr);
+    skipFallback.link(&m_jit);
+    doubleResult(resultFpr, node);
+}
+
 // Returns true if the compare is fused with a subsequent branch.
 bool SpeculativeJIT::compare(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_EJJ operation)
 {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -2134,6 +2134,7 @@
     void compileArithMul(Node*);
     void compileArithDiv(Node*);
     void compileArithMod(Node*);
+    void compileArithPow(Node*);
     void compileArithSqrt(Node*);
     void compileConstantStoragePointer(Node*);
     void compileGetIndexedPropertyStorage(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -1996,6 +1996,11 @@
         break;
     }
 
+    case ArithPow: {
+        compileArithPow(node);
+        break;
+    }
+
     case ArithAbs: {
         switch (node->child1().useKind()) {
         case Int32Use: {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -2241,6 +2241,10 @@
         break;
     }
 
+    case ArithPow:
+        compileArithPow(node);
+        break;
+
     case ArithSqrt:
         compileArithSqrt(node);
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -132,7 +132,20 @@
                 }
             }
             break;
-            
+
+        case ArithPow:
+            if (m_node->child2()->isNumberConstant()) {
+                double yOperandValue = m_node->child2()->asNumber();
+                if (yOperandValue == 1) {
+                    convertToIdentityOverChild1();
+                } else if (yOperandValue == 0.5) {
+                    m_insertionSet.insertNode(m_nodeIndex, SpecNone, Phantom, m_node->origin, m_node->children);
+                    m_node->convertToArithSqrt();
+                    m_changed = true;
+                }
+            }
+            break;
+
         case GetArrayLength:
             if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node))
                 foldTypedArrayPropertyToConstant(view, jsNumber(view->length()));

Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -240,6 +240,7 @@
                 case ArithMod:
                 case ArithMin:
                 case ArithMax:
+                case ArithPow:
                 case CompareLess:
                 case CompareLessEq:
                 case CompareGreater:

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -89,6 +89,7 @@
     case ArithAbs:
     case ArithSin:
     case ArithCos:
+    case ArithPow:
     case ArithSqrt:
     case ArithFRound:
     case ArithNegate:

Modified: trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h (180097 => 180098)


--- trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -40,6 +40,8 @@
     macro(doubleAbs, "llvm.fabs.f64", functionType(doubleType, doubleType)) \
     macro(doubleSin, "llvm.sin.f64", functionType(doubleType, doubleType)) \
     macro(doubleCos, "llvm.cos.f64", functionType(doubleType, doubleType)) \
+    macro(doublePow, "llvm.pow.f64", functionType(doubleType, doubleType, doubleType)) \
+    macro(doublePowi, "llvm.powi.f64", functionType(doubleType, doubleType, int32)) \
     macro(doubleSqrt, "llvm.sqrt.f64", functionType(doubleType, doubleType)) \
     macro(frameAddress, "llvm.frameaddress", functionType(pointerType(int8), int32)) \
     macro(mulWithOverflow32, "llvm.smul.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -436,6 +436,9 @@
         case ArithCos:
             compileArithCos();
             break;
+        case ArithPow:
+            compileArithPow();
+            break;
         case ArithSqrt:
             compileArithSqrt();
             break;
@@ -1595,6 +1598,64 @@
 
     void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); }
 
+    void compileArithPow()
+    {
+        // FIXME: investigate llvm.powi to better understand its performance characteristics.
+        // It might be better to have the inline loop in DFG too.
+        if (m_node->child2().useKind() == Int32Use)
+            setDouble(m_out.doublePowi(lowDouble(m_node->child1()), lowInt32(m_node->child2())));
+        else {
+            LValue base = lowDouble(m_node->child1());
+            LValue exponent = lowDouble(m_node->child2());
+
+            LBasicBlock integerExponentIsSmallBlock = FTL_NEW_BLOCK(m_out, ("ArithPow test integer exponent is small."));
+            LBasicBlock integerExponentPowBlock = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, (int)double)."));
+            LBasicBlock doubleExponentPowBlock = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, double)."));
+            LBasicBlock powBlock = FTL_NEW_BLOCK(m_out, ("ArithPow regular pow"));
+            LBasicBlock nanException = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithPow continuation"));
+
+            LValue integerExponent = m_out.fpToInt32(exponent);
+            LValue integerExponentConvertedToDouble = m_out.intToDouble(integerExponent);
+            LValue exponentIsInteger = m_out.doubleEqual(exponent, integerExponentConvertedToDouble);
+            m_out.branch(exponentIsInteger, unsure(integerExponentIsSmallBlock), unsure(doubleExponentPowBlock));
+
+            LBasicBlock lastNext = m_out.appendTo(integerExponentIsSmallBlock, integerExponentPowBlock);
+            LValue integerExponentBelow1000 = m_out.below(integerExponent, m_out.constInt32(1000));
+            m_out.branch(integerExponentBelow1000, usually(integerExponentPowBlock), rarely(doubleExponentPowBlock));
+
+            m_out.appendTo(integerExponentPowBlock, doubleExponentPowBlock);
+            ValueFromBlock powDoubleIntResult = m_out.anchor(m_out.doublePowi(base, integerExponent));
+            m_out.jump(continuation);
+
+            m_out.appendTo(doubleExponentPowBlock, powBlock);
+            // If y is NaN, the result is NaN.
+            // FIXME: shouldn't we only check that if the type of child2() might have NaN?
+            LValue exponentIsNaN = m_out.doubleNotEqualOrUnordered(exponent, exponent);
+
+            // If abs(x) is 1 and y is +infinity, the result is NaN.
+            // If abs(x) is 1 and y is -infinity, the result is NaN.
+            LValue absoluteExponent = m_out.doubleAbs(exponent);
+            LValue absoluteExponentIsInfinity = m_out.doubleEqual(absoluteExponent, m_out.constDouble(std::numeric_limits<double>::infinity()));
+            LValue absoluteBase = m_out.doubleAbs(base);
+            LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1));
+            LValue _oneBaseInfiniteExponent_ = m_out.bitAnd(absoluteExponentIsInfinity, absoluteBaseIsOne);
+
+            m_out.branch(m_out.bitOr(exponentIsNaN, oneBaseInfiniteExponent), rarely(nanException), usually(powBlock));
+
+            m_out.appendTo(powBlock, nanException);
+            ValueFromBlock powResult = m_out.anchor(m_out.doublePow(base, exponent));
+            m_out.jump(continuation);
+
+            m_out.appendTo(nanException, continuation);
+            ValueFromBlock pureNan = m_out.anchor(m_out.constDouble(PNaN));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, powResult, pureNan));
+        }
+    }
+
     void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
     
     void compileArithFRound()

Modified: trunk/Source/_javascript_Core/ftl/FTLOutput.h (180097 => 180098)


--- trunk/Source/_javascript_Core/ftl/FTLOutput.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/ftl/FTLOutput.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -177,6 +177,16 @@
         return call(doubleCosIntrinsic(), value);
     }
 
+    LValue doublePow(LValue xOperand, LValue yOperand)
+    {
+        return call(doublePowIntrinsic(), xOperand, yOperand);
+    }
+
+    LValue doublePowi(LValue xOperand, LValue yOperand)
+    {
+        return call(doublePowiIntrinsic(), xOperand, yOperand);
+    }
+
     LValue doubleSqrt(LValue value)
     {
         return call(doubleSqrtIntrinsic(), value);

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -1213,6 +1213,395 @@
 }
 #endif
 
+#if PLATFORM(IOS) && CPU(ARM_THUMB2)
+
+// The following code is taken from netlib.org:
+//   http://www.netlib.org/fdlibm/fdlibm.h
+//   http://www.netlib.org/fdlibm/e_pow.c
+//   http://www.netlib.org/fdlibm/s_scalbn.c
+//
+// And was originally distributed under the following license:
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ *              n
+ * Method:  Let x =  2   * (1+f)
+ *    1. Compute and return log2(x) in two pieces:
+ *        log2(x) = w1 + w2,
+ *       where w1 has 53-24 = 29 bit trailing zeros.
+ *    2. Perform y*log2(x) = n+y' by simulating muti-precision 
+ *       arithmetic, where |y'|<=0.5.
+ *    3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ *    1.  (anything) ** 0  is 1
+ *    2.  (anything) ** 1  is itself
+ *    3.  (anything) ** NAN is NAN
+ *    4.  NAN ** (anything except 0) is NAN
+ *    5.  +-(|x| > 1) **  +INF is +INF
+ *    6.  +-(|x| > 1) **  -INF is +0
+ *    7.  +-(|x| < 1) **  +INF is +0
+ *    8.  +-(|x| < 1) **  -INF is +INF
+ *    9.  +-1         ** +-INF is NAN
+ *    10. +0 ** (+anything except 0, NAN)               is +0
+ *    11. -0 ** (+anything except 0, NAN, odd integer)  is +0
+ *    12. +0 ** (-anything except 0, NAN)               is +INF
+ *    13. -0 ** (-anything except 0, NAN, odd integer)  is +INF
+ *    14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ *    15. +INF ** (+anything except 0,NAN) is +INF
+ *    16. +INF ** (-anything except 0,NAN) is +0
+ *    17. -INF ** (anything)  = -0 ** (-anything)
+ *    18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ *    19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ *    pow(x,y) returns x**y nearly rounded. In particular
+ *            pow(integer,integer)
+ *    always returns the correct integer provided it is 
+ *    representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#define __HI(x) *(1+(int*)&x)
+#define __LO(x) *(int*)&x
+
+static const double
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero    =  0.0,
+_one_    =  1.0,
+two    =  2.0,
+two53    =  9007199254740992.0,    /* 0x43400000, 0x00000000 */
+huge    =  1.0e300,
+tiny    =  1.0e-300,
+        /* for scalbn */
+two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+    /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1  =  5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2  =  4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3  =  3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4  =  2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5  =  2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6  =  2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+inline double fdlibmScalbn (double x, int n)
+{
+    int  k,hx,lx;
+    hx = __HI(x);
+    lx = __LO(x);
+        k = (hx&0x7ff00000)>>20;        /* extract exponent */
+        if (k==0) {                /* 0 or subnormal x */
+            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+        x *= two54; 
+        hx = __HI(x);
+        k = ((hx&0x7ff00000)>>20) - 54; 
+            if (n< -50000) return tiny*x;     /*underflow*/
+        }
+        if (k==0x7ff) return x+x;        /* NaN or Inf */
+        k = k+n; 
+        if (k >  0x7fe) return huge*copysign(huge,x); /* overflow  */
+        if (k > 0)                 /* normal result */
+        {__HI(x) = (hx&0x800fffff)|(k<<20); return x;}
+        if (k <= -54) {
+            if (n > 50000)     /* in case integer overflow in n+k */
+        return huge*copysign(huge,x);    /*overflow*/
+        else return tiny*copysign(tiny,x);     /*underflow*/
+        }
+        k += 54;                /* subnormal result */
+        __HI(x) = (hx&0x800fffff)|(k<<20);
+        return x*twom54;
+}
+
+static double fdlibmPow(double x, double y)
+{
+    double z,ax,z_h,z_l,p_h,p_l;
+    double y1,t1,t2,r,s,t,u,v,w;
+    int i0,i1,i,j,k,yisint,n;
+    int hx,hy,ix,iy;
+    unsigned lx,ly;
+
+    i0 = ((*(int*)&one)>>29)^1; i1=1-i0;
+    hx = __HI(x); lx = __LO(x);
+    hy = __HI(y); ly = __LO(y);
+    ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
+
+    /* y==zero: x**0 = 1 */
+    if((iy|ly)==0) return one;     
+
+    /* +-NaN return x+y */
+    if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+       iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) 
+        return x+y;    
+
+    /* determine if y is an odd int when x < 0
+     * yisint = 0    ... y is not an integer
+     * yisint = 1    ... y is an odd int
+     * yisint = 2    ... y is an even int
+     */
+    yisint  = 0;
+    if(hx<0) {    
+        if(iy>=0x43400000) yisint = 2; /* even integer y */
+        else if(iy>=0x3ff00000) {
+        k = (iy>>20)-0x3ff;       /* exponent */
+        if(k>20) {
+            j = ly>>(52-k);
+            if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1);
+        } else if(ly==0) {
+            j = iy>>(20-k);
+            if((j<<(20-k))==iy) yisint = 2-(j&1);
+        }
+        }        
+    } 
+
+    /* special value of y */
+    if(ly==0) {     
+        if (iy==0x7ff00000) {    /* y is +-inf */
+            if(((ix-0x3ff00000)|lx)==0)
+            return  y - y;    /* inf**+-1 is NaN */
+            else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+            return (hy>=0)? y: zero;
+            else            /* (|x|<1)**-,+inf = inf,0 */
+            return (hy<0)?-y: zero;
+        } 
+        if(iy==0x3ff00000) {    /* y is  +-1 */
+        if(hy<0) return one/x; else return x;
+        }
+        if(hy==0x40000000) return x*x; /* y is  2 */
+        if(hy==0x3fe00000) {    /* y is  0.5 */
+        if(hx>=0)    /* x >= +0 */
+        return sqrt(x);    
+        }
+    }
+
+    ax   = fabs(x);
+    /* special value of x */
+    if(lx==0) {
+        if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+        z = ax;            /*x is +-0,+-inf,+-1*/
+        if(hy<0) z = one/z;    /* z = (1/|x|) */
+        if(hx<0) {
+            if(((ix-0x3ff00000)|yisint)==0) {
+            z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+            } else if(yisint==1) 
+            z = -z;        /* (x<0)**odd = -(|x|**odd) */
+        }
+        return z;
+        }
+    }
+    
+    n = (hx>>31)+1;
+
+    /* (x<0)**(non-int) is NaN */
+    if((n|yisint)==0) return (x-x)/(x-x);
+
+    s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+    if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+    /* |y| is huge */
+    if(iy>0x41e00000) { /* if |y| > 2**31 */
+        if(iy>0x43f00000){    /* if |y| > 2**64, must o/uflow */
+        if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+        if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+        }
+    /* over/underflow if x is not close to one */
+        if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
+        if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
+    /* now |1-x| is tiny <= 2**-20, suffice to compute 
+       log(x) by x-x^2/2+x^3/3-x^4/4 */
+        t = ax-one;        /* t has 20 trailing zeros */
+        w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+        u = ivln2_h*t;    /* ivln2_h has 21 sig. bits */
+        v = t*ivln2_l-w*ivln2;
+        t1 = u+v;
+        __LO(t1) = 0;
+        t2 = v-(t1-u);
+    } else {
+        double ss,s2,s_h,s_l,t_h,t_l;
+        n = 0;
+    /* take care subnormal number */
+        if(ix<0x00100000)
+        {ax *= two53; n -= 53; ix = __HI(ax); }
+        n  += ((ix)>>20)-0x3ff;
+        j  = ix&0x000fffff;
+    /* determine interval */
+        ix = j|0x3ff00000;        /* normalize ix */
+        if(j<=0x3988E) k=0;        /* |x|<sqrt(3/2) */
+        else if(j<0xBB67A) k=1;    /* |x|<sqrt(3)   */
+        else {k=0;n+=1;ix -= 0x00100000;}
+        __HI(ax) = ix;
+
+    /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+        u = ax-bp[k];        /* bp[0]=1.0, bp[1]=1.5 */
+        v = one/(ax+bp[k]);
+        ss = u*v;
+        s_h = ss;
+        __LO(s_h) = 0;
+    /* t_h=ax+bp[k] High */
+        t_h = zero;
+        __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18); 
+        t_l = ax - (t_h-bp[k]);
+        s_l = v*((u-s_h*t_h)-s_h*t_l);
+    /* compute log(ax) */
+        s2 = ss*ss;
+        r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+        r += s_l*(s_h+ss);
+        s2  = s_h*s_h;
+        t_h = 3.0+s2+r;
+        __LO(t_h) = 0;
+        t_l = r-((t_h-3.0)-s2);
+    /* u+v = ss*(1+...) */
+        u = s_h*t_h;
+        v = s_l*t_h+t_l*ss;
+    /* 2/(3log2)*(ss+...) */
+        p_h = u+v;
+        __LO(p_h) = 0;
+        p_l = v-(p_h-u);
+        z_h = cp_h*p_h;        /* cp_h+cp_l = 2/(3*log2) */
+        z_l = cp_l*p_h+p_l*cp+dp_l[k];
+    /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+        t = (double)n;
+        t1 = (((z_h+z_l)+dp_h[k])+t);
+        __LO(t1) = 0;
+        t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+    }
+
+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+    y1  = y;
+    __LO(y1) = 0;
+    p_l = (y-y1)*t1+y*t2;
+    p_h = y1*t1;
+    z = p_l+p_h;
+    j = __HI(z);
+    i = __LO(z);
+    if (j>=0x40900000) {                /* z >= 1024 */
+        if(((j-0x40900000)|i)!=0)            /* if z > 1024 */
+        return s*huge*huge;            /* overflow */
+        else {
+        if(p_l+ovt>z-p_h) return s*huge*huge;    /* overflow */
+        }
+    } else if((j&0x7fffffff)>=0x4090cc00 ) {    /* z <= -1075 */
+        if(((j-0xc090cc00)|i)!=0)         /* z < -1075 */
+        return s*tiny*tiny;        /* underflow */
+        else {
+        if(p_l<=z-p_h) return s*tiny*tiny;    /* underflow */
+        }
+    }
+    /*
+     * compute 2**(p_h+p_l)
+     */
+    i = j&0x7fffffff;
+    k = (i>>20)-0x3ff;
+    n = 0;
+    if(i>0x3fe00000) {        /* if |z| > 0.5, set n = [z+0.5] */
+        n = j+(0x00100000>>(k+1));
+        k = ((n&0x7fffffff)>>20)-0x3ff;    /* new k for n */
+        t = zero;
+        __HI(t) = (n&~(0x000fffff>>k));
+        n = ((n&0x000fffff)|0x00100000)>>(20-k);
+        if(j<0) n = -n;
+        p_h -= t;
+    } 
+    t = p_l+p_h;
+    __LO(t) = 0;
+    u = t*lg2_h;
+    v = (p_l-(t-p_h))*lg2+t*lg2_l;
+    z = u+v;
+    w = v-(z-u);
+    t  = z*z;
+    t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+    r  = (z*t1)/(t1-two)-(w+z*w);
+    z  = one-(r-z);
+    j  = __HI(z);
+    j += (n<<20);
+    if((j>>20)<=0) z = fdlibmScalbn(z,n);    /* subnormal output */
+    else __HI(z) += (n<<20);
+    return s*z;
+}
+
+static ALWAYS_INLINE bool isDenormal(double x)
+{
+    static const uint64_t signbit = 0x8000000000000000ULL;
+    static const uint64_t minNormal = 0x0001000000000000ULL;
+    return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1;
+}
+
+static ALWAYS_INLINE bool isEdgeCase(double x)
+{
+    static const uint64_t signbit = 0x8000000000000000ULL;
+    static const uint64_t infinity = 0x7fffffffffffffffULL;
+    return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1;
+}
+
+static ALWAYS_INLINE double mathPowInternal(double x, double y)
+{
+    if (!isDenormal(x) && !isDenormal(y)) {
+        double libmResult = pow(x, y);
+        if (libmResult || isEdgeCase(x) || isEdgeCase(y))
+            return libmResult;
+    }
+    return fdlibmPow(x, y);
+}
+
+#else
+
+ALWAYS_INLINE double mathPowInternal(double x, double y)
+{
+    return pow(x, y);
+}
+
+#endif
+
+double JSC_HOST_CALL operationMathPow(double x, double y)
+{
+    if (std::isnan(y))
+        return PNaN;
+    if (std::isinf(y) && fabs(x) == 1)
+        return PNaN;
+    return mathPowInternal(x, y);
+}
+
 void JIT_OPERATION operationPutByIndex(ExecState* exec, EncodedJSValue encodedArrayValue, int32_t index, EncodedJSValue encodedValue)
 {
     VM& vm = exec->vm();

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (180097 => 180098)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2015-02-14 04:20:21 UTC (rev 180098)
@@ -281,6 +281,7 @@
 #if ENABLE(DFG_JIT)
 SlowPathReturnType JIT_OPERATION operationOptimize(ExecState*, int32_t) WTF_INTERNAL;
 #endif
+double JSC_HOST_CALL operationMathPow(double x, double y) WTF_INTERNAL;
 void JIT_OPERATION operationPutByIndex(ExecState*, EncodedJSValue, int32_t, EncodedJSValue);
 #if USE(JSVALUE64)
 void JIT_OPERATION operationPutGetterSetter(ExecState*, EncodedJSValue, Identifier*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/runtime/MathObject.cpp (180097 => 180098)


--- trunk/Source/_javascript_Core/runtime/MathObject.cpp	2015-02-14 04:16:57 UTC (rev 180097)
+++ trunk/Source/_javascript_Core/runtime/MathObject.cpp	2015-02-14 04:20:21 UTC (rev 180098)
@@ -21,6 +21,7 @@
 #include "config.h"
 #include "MathObject.h"
 
+#include "JITOperations.h"
 #include "Lookup.h"
 #include "ObjectPrototype.h"
 #include "JSCInlines.h"
@@ -242,43 +243,6 @@
     return JSValue::encode(jsNumber(result));
 }
 
-#if PLATFORM(IOS) && CPU(ARM_THUMB2)
-
-static double fdlibmPow(double x, double y);
-
-static ALWAYS_INLINE bool isDenormal(double x)
-{
-        static const uint64_t signbit = 0x8000000000000000ULL;
-        static const uint64_t minNormal = 0x0001000000000000ULL;
-        return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1;
-}
-
-static ALWAYS_INLINE bool isEdgeCase(double x)
-{
-        static const uint64_t signbit = 0x8000000000000000ULL;
-        static const uint64_t infinity = 0x7fffffffffffffffULL;
-        return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1;
-}
-
-static ALWAYS_INLINE double mathPow(double x, double y)
-{
-    if (!isDenormal(x) && !isDenormal(y)) {
-        double libmResult = pow(x,y);
-        if (libmResult || isEdgeCase(x) || isEdgeCase(y))
-            return libmResult;
-    }
-    return fdlibmPow(x,y);
-}
-
-#else
-
-ALWAYS_INLINE double mathPow(double x, double y)
-{
-    return pow(x, y);
-}
-
-#endif
-
 EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec)
 {
     // ECMA 15.8.2.1.13
@@ -286,11 +250,7 @@
     double arg = exec->argument(0).toNumber(exec);
     double arg2 = exec->argument(1).toNumber(exec);
 
-    if (std::isnan(arg2))
-        return JSValue::encode(jsNaN());
-    if (std::isinf(arg2) && fabs(arg) == 1)
-        return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(mathPow(arg, arg2)));
+    return JSValue::encode(JSValue(operationMathPow(arg, arg2)));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec)
@@ -407,354 +367,4 @@
     return JSValue::encode(jsNumber(exec->argument(0).toIntegerPreserveNaN(exec)));
 }
 
-
-#if PLATFORM(IOS) && CPU(ARM_THUMB2)
-
-// The following code is taken from netlib.org:
-//   http://www.netlib.org/fdlibm/fdlibm.h
-//   http://www.netlib.org/fdlibm/e_pow.c
-//   http://www.netlib.org/fdlibm/s_scalbn.c
-//
-// And was originally distributed under the following license:
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice 
- * is preserved.
- * ====================================================
- */
-/*
- * ====================================================
- * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice 
- * is preserved.
- * ====================================================
- */
-
-/* __ieee754_pow(x,y) return x**y
- *
- *              n
- * Method:  Let x =  2   * (1+f)
- *    1. Compute and return log2(x) in two pieces:
- *        log2(x) = w1 + w2,
- *       where w1 has 53-24 = 29 bit trailing zeros.
- *    2. Perform y*log2(x) = n+y' by simulating muti-precision 
- *       arithmetic, where |y'|<=0.5.
- *    3. Return x**y = 2**n*exp(y'*log2)
- *
- * Special cases:
- *    1.  (anything) ** 0  is 1
- *    2.  (anything) ** 1  is itself
- *    3.  (anything) ** NAN is NAN
- *    4.  NAN ** (anything except 0) is NAN
- *    5.  +-(|x| > 1) **  +INF is +INF
- *    6.  +-(|x| > 1) **  -INF is +0
- *    7.  +-(|x| < 1) **  +INF is +0
- *    8.  +-(|x| < 1) **  -INF is +INF
- *    9.  +-1         ** +-INF is NAN
- *    10. +0 ** (+anything except 0, NAN)               is +0
- *    11. -0 ** (+anything except 0, NAN, odd integer)  is +0
- *    12. +0 ** (-anything except 0, NAN)               is +INF
- *    13. -0 ** (-anything except 0, NAN, odd integer)  is +INF
- *    14. -0 ** (odd integer) = -( +0 ** (odd integer) )
- *    15. +INF ** (+anything except 0,NAN) is +INF
- *    16. +INF ** (-anything except 0,NAN) is +0
- *    17. -INF ** (anything)  = -0 ** (-anything)
- *    18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
- *    19. (-anything except 0 and inf) ** (non-integer) is NAN
- *
- * Accuracy:
- *    pow(x,y) returns x**y nearly rounded. In particular
- *            pow(integer,integer)
- *    always returns the correct integer provided it is 
- *    representable.
- *
- * Constants :
- * The hexadecimal values are the intended ones for the following 
- * constants. The decimal values may be used, provided that the 
- * compiler will convert from decimal to binary accurately enough 
- * to produce the hexadecimal values shown.
- */
-
-#define __HI(x) *(1+(int*)&x)
-#define __LO(x) *(int*)&x
-
-static const double
-bp[] = {1.0, 1.5,},
-dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
-dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
-zero    =  0.0,
-_one_    =  1.0,
-two    =  2.0,
-two53    =  9007199254740992.0,    /* 0x43400000, 0x00000000 */
-huge    =  1.0e300,
-tiny    =  1.0e-300,
-        /* for scalbn */
-two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
-twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
-    /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
-L1  =  5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
-L2  =  4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
-L3  =  3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
-L4  =  2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
-L5  =  2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
-L6  =  2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
-P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
-P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
-P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
-P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
-P5   =  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
-lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
-lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
-lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
-ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
-cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
-cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
-cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
-ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
-ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
-ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
-
-inline double fdlibmScalbn (double x, int n)
-{
-    int  k,hx,lx;
-    hx = __HI(x);
-    lx = __LO(x);
-        k = (hx&0x7ff00000)>>20;        /* extract exponent */
-        if (k==0) {                /* 0 or subnormal x */
-            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
-        x *= two54; 
-        hx = __HI(x);
-        k = ((hx&0x7ff00000)>>20) - 54; 
-            if (n< -50000) return tiny*x;     /*underflow*/
-        }
-        if (k==0x7ff) return x+x;        /* NaN or Inf */
-        k = k+n; 
-        if (k >  0x7fe) return huge*copysign(huge,x); /* overflow  */
-        if (k > 0)                 /* normal result */
-        {__HI(x) = (hx&0x800fffff)|(k<<20); return x;}
-        if (k <= -54) {
-            if (n > 50000)     /* in case integer overflow in n+k */
-        return huge*copysign(huge,x);    /*overflow*/
-        else return tiny*copysign(tiny,x);     /*underflow*/
-        }
-        k += 54;                /* subnormal result */
-        __HI(x) = (hx&0x800fffff)|(k<<20);
-        return x*twom54;
-}
-
-double fdlibmPow(double x, double y)
-{
-    double z,ax,z_h,z_l,p_h,p_l;
-    double y1,t1,t2,r,s,t,u,v,w;
-    int i0,i1,i,j,k,yisint,n;
-    int hx,hy,ix,iy;
-    unsigned lx,ly;
-
-    i0 = ((*(int*)&one)>>29)^1; i1=1-i0;
-    hx = __HI(x); lx = __LO(x);
-    hy = __HI(y); ly = __LO(y);
-    ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
-
-    /* y==zero: x**0 = 1 */
-    if((iy|ly)==0) return one;     
-
-    /* +-NaN return x+y */
-    if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
-       iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) 
-        return x+y;    
-
-    /* determine if y is an odd int when x < 0
-     * yisint = 0    ... y is not an integer
-     * yisint = 1    ... y is an odd int
-     * yisint = 2    ... y is an even int
-     */
-    yisint  = 0;
-    if(hx<0) {    
-        if(iy>=0x43400000) yisint = 2; /* even integer y */
-        else if(iy>=0x3ff00000) {
-        k = (iy>>20)-0x3ff;       /* exponent */
-        if(k>20) {
-            j = ly>>(52-k);
-            if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1);
-        } else if(ly==0) {
-            j = iy>>(20-k);
-            if((j<<(20-k))==iy) yisint = 2-(j&1);
-        }
-        }        
-    } 
-
-    /* special value of y */
-    if(ly==0) {     
-        if (iy==0x7ff00000) {    /* y is +-inf */
-            if(((ix-0x3ff00000)|lx)==0)
-            return  y - y;    /* inf**+-1 is NaN */
-            else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
-            return (hy>=0)? y: zero;
-            else            /* (|x|<1)**-,+inf = inf,0 */
-            return (hy<0)?-y: zero;
-        } 
-        if(iy==0x3ff00000) {    /* y is  +-1 */
-        if(hy<0) return one/x; else return x;
-        }
-        if(hy==0x40000000) return x*x; /* y is  2 */
-        if(hy==0x3fe00000) {    /* y is  0.5 */
-        if(hx>=0)    /* x >= +0 */
-        return sqrt(x);    
-        }
-    }
-
-    ax   = fabs(x);
-    /* special value of x */
-    if(lx==0) {
-        if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
-        z = ax;            /*x is +-0,+-inf,+-1*/
-        if(hy<0) z = one/z;    /* z = (1/|x|) */
-        if(hx<0) {
-            if(((ix-0x3ff00000)|yisint)==0) {
-            z = (z-z)/(z-z); /* (-1)**non-int is NaN */
-            } else if(yisint==1) 
-            z = -z;        /* (x<0)**odd = -(|x|**odd) */
-        }
-        return z;
-        }
-    }
-    
-    n = (hx>>31)+1;
-
-    /* (x<0)**(non-int) is NaN */
-    if((n|yisint)==0) return (x-x)/(x-x);
-
-    s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
-    if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
-
-    /* |y| is huge */
-    if(iy>0x41e00000) { /* if |y| > 2**31 */
-        if(iy>0x43f00000){    /* if |y| > 2**64, must o/uflow */
-        if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
-        if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
-        }
-    /* over/underflow if x is not close to one */
-        if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
-        if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
-    /* now |1-x| is tiny <= 2**-20, suffice to compute 
-       log(x) by x-x^2/2+x^3/3-x^4/4 */
-        t = ax-one;        /* t has 20 trailing zeros */
-        w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
-        u = ivln2_h*t;    /* ivln2_h has 21 sig. bits */
-        v = t*ivln2_l-w*ivln2;
-        t1 = u+v;
-        __LO(t1) = 0;
-        t2 = v-(t1-u);
-    } else {
-        double ss,s2,s_h,s_l,t_h,t_l;
-        n = 0;
-    /* take care subnormal number */
-        if(ix<0x00100000)
-        {ax *= two53; n -= 53; ix = __HI(ax); }
-        n  += ((ix)>>20)-0x3ff;
-        j  = ix&0x000fffff;
-    /* determine interval */
-        ix = j|0x3ff00000;        /* normalize ix */
-        if(j<=0x3988E) k=0;        /* |x|<sqrt(3/2) */
-        else if(j<0xBB67A) k=1;    /* |x|<sqrt(3)   */
-        else {k=0;n+=1;ix -= 0x00100000;}
-        __HI(ax) = ix;
-
-    /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
-        u = ax-bp[k];        /* bp[0]=1.0, bp[1]=1.5 */
-        v = one/(ax+bp[k]);
-        ss = u*v;
-        s_h = ss;
-        __LO(s_h) = 0;
-    /* t_h=ax+bp[k] High */
-        t_h = zero;
-        __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18); 
-        t_l = ax - (t_h-bp[k]);
-        s_l = v*((u-s_h*t_h)-s_h*t_l);
-    /* compute log(ax) */
-        s2 = ss*ss;
-        r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
-        r += s_l*(s_h+ss);
-        s2  = s_h*s_h;
-        t_h = 3.0+s2+r;
-        __LO(t_h) = 0;
-        t_l = r-((t_h-3.0)-s2);
-    /* u+v = ss*(1+...) */
-        u = s_h*t_h;
-        v = s_l*t_h+t_l*ss;
-    /* 2/(3log2)*(ss+...) */
-        p_h = u+v;
-        __LO(p_h) = 0;
-        p_l = v-(p_h-u);
-        z_h = cp_h*p_h;        /* cp_h+cp_l = 2/(3*log2) */
-        z_l = cp_l*p_h+p_l*cp+dp_l[k];
-    /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
-        t = (double)n;
-        t1 = (((z_h+z_l)+dp_h[k])+t);
-        __LO(t1) = 0;
-        t2 = z_l-(((t1-t)-dp_h[k])-z_h);
-    }
-
-    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
-    y1  = y;
-    __LO(y1) = 0;
-    p_l = (y-y1)*t1+y*t2;
-    p_h = y1*t1;
-    z = p_l+p_h;
-    j = __HI(z);
-    i = __LO(z);
-    if (j>=0x40900000) {                /* z >= 1024 */
-        if(((j-0x40900000)|i)!=0)            /* if z > 1024 */
-        return s*huge*huge;            /* overflow */
-        else {
-        if(p_l+ovt>z-p_h) return s*huge*huge;    /* overflow */
-        }
-    } else if((j&0x7fffffff)>=0x4090cc00 ) {    /* z <= -1075 */
-        if(((j-0xc090cc00)|i)!=0)         /* z < -1075 */
-        return s*tiny*tiny;        /* underflow */
-        else {
-        if(p_l<=z-p_h) return s*tiny*tiny;    /* underflow */
-        }
-    }
-    /*
-     * compute 2**(p_h+p_l)
-     */
-    i = j&0x7fffffff;
-    k = (i>>20)-0x3ff;
-    n = 0;
-    if(i>0x3fe00000) {        /* if |z| > 0.5, set n = [z+0.5] */
-        n = j+(0x00100000>>(k+1));
-        k = ((n&0x7fffffff)>>20)-0x3ff;    /* new k for n */
-        t = zero;
-        __HI(t) = (n&~(0x000fffff>>k));
-        n = ((n&0x000fffff)|0x00100000)>>(20-k);
-        if(j<0) n = -n;
-        p_h -= t;
-    } 
-    t = p_l+p_h;
-    __LO(t) = 0;
-    u = t*lg2_h;
-    v = (p_l-(t-p_h))*lg2+t*lg2_l;
-    z = u+v;
-    w = v-(z-u);
-    t  = z*z;
-    t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
-    r  = (z*t1)/(t1-two)-(w+z*w);
-    z  = one-(r-z);
-    j  = __HI(z);
-    j += (n<<20);
-    if((j>>20)<=0) z = fdlibmScalbn(z,n);    /* subnormal output */
-    else __HI(z) += (n<<20);
-    return s*z;
-}
-
-#endif
-
 } // namespace JSC

Added: trunk/Source/_javascript_Core/tests/stress/math-pow-basics.js (0 => 180098)


--- trunk/Source/_javascript_Core/tests/stress/math-pow-basics.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/math-pow-basics.js	2015-02-14 04:20:21 UTC (rev 180098)
@@ -0,0 +1,286 @@
+function valuesAreClose(a, b) {
+    return Math.abs(a / b) - 1 < 1e-10;
+}
+
+// Some random values.
+function mathPowDoubleDouble1(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble1);
+
+function mathPowDoubleInt1(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt1);
+
+function test1(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble1(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble1(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt1(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt1(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test1);
+test1(376.76522764377296, 10.81699226051569, 7.333951929109252e+27, 5.76378989575089e+25);
+
+function mathPowDoubleDouble2(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble2);
+
+function mathPowDoubleInt2(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt2);
+function test2(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble2(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble2(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt2(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt2(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test2);
+test2(376.76522764377296, -5.81699226051569, 1.035180331187579e-15, 1.3171824310400265e-13);
+
+function mathPowDoubleDouble3(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble3);
+
+function mathPowDoubleInt3(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt3);
+function test3(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble3(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble3(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt3(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt3(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test3);
+test3(-37.676522764377296, 10.0, 5763789895750892, 5763789895750892);
+
+// Exponent zero.
+function mathPowDoubleDouble4(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble4);
+
+function mathPowDoubleInt4(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt4);
+function test4(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble4(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble4(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt4(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt4(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test4);
+test4(-37.676522764377296, 0, 1, 1);
+
+// Exponent minus zero.
+function mathPowDoubleDouble5(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble5);
+
+function mathPowDoubleInt5(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt5);
+function test5(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble5(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble5(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt5(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test5);
+test5(-37.676522764377296, -0, 1, 1);
+
+// Exponent 1.
+function mathPowDoubleDouble6(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble6);
+
+function mathPowDoubleInt6(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt6);
+function test6(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble6(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble6(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt6(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt6(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test6);
+test6(-37.676522764377296, 1.0, -37.676522764377296, -37.676522764377296);
+
+// Exponent -1.
+function mathPowDoubleDouble7(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble7);
+
+function mathPowDoubleInt7(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt7);
+function test7(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble7(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble7(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble7(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleDouble7(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test7);
+test6(-37.676522764377296, -1.0, -0.026541727490454296, -0.026541727490454296);
+
+// Let's square things.
+function mathPowDoubleDouble8(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble8);
+
+function mathPowDoubleInt8(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt8);
+function test8(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble8(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble8(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt8(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt8(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test8);
+test7(-37.676522764377296, 2.0, 1419.5203676146407, 1419.5203676146407);
+
+function mathPowDoubleDouble9(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble9);
+
+function mathPowDoubleInt9(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt9);
+function test9(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble9(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble9(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt9(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt9(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test9);
+test8(37.676522764377296, 2.0, 1419.5203676146407, 1419.5203676146407);
+
+// Let's cube things.
+function mathPowDoubleDouble10(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble10);
+
+function mathPowDoubleInt10(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt10);
+function test10(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble10(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt10(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test9);
+test9(-37.676522764377296, 3.0, -53482.591444930236, -53482.591444930236);
+
+function mathPowDoubleDouble11(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDouble11);
+
+function mathPowDoubleInt11(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleInt11);
+function test11(x, y, expected1, expected2) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDouble11(x, y);
+        if (!valuesAreClose(result, expected1))
+            throw "Error: bad result, mathPowDoubleDouble(" + x + ", " + y + ") = " + result + " expected a value close to " + expected1;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleInt11(x, integerY);
+        if (!valuesAreClose(result, expected2))
+            throw "Error: bad result, mathPowDoubleInt(" + x + ", " + integerY + ") = " + result + " expected a value close to " + expected2;
+    }
+}
+noInline(test10);
+test10(37.676522764377296, 3.0, 53482.591444930236, 53482.591444930236);

Added: trunk/Source/_javascript_Core/tests/stress/math-pow-integer-exponent-fastpath.js (0 => 180098)


--- trunk/Source/_javascript_Core/tests/stress/math-pow-integer-exponent-fastpath.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/math-pow-integer-exponent-fastpath.js	2015-02-14 04:20:21 UTC (rev 180098)
@@ -0,0 +1,56 @@
+function valuesAreClose(a, b) {
+    return Math.abs(a / b) - 1 < 1e-10;
+}
+
+// Small exponent values are handled through a simpler inline loop. Test that it is not observable.
+function mathPowDoubleDoubleTestExponentFifty(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDoubleTestExponentFifty);
+
+function mathPowDoubleIntTestExponentFifty(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleIntTestExponentFifty);
+function testExponentFifty(x, y, expected) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDoubleTestExponentFifty(x, y);
+        if (!valuesAreClose(result, expected))
+            throw "Error: bad result, Math.pow(" + x + ", " + y + ") = " + result + " expected value close to " + expected;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleIntTestExponentFifty(x, integerY);
+        if (!valuesAreClose(result, expected))
+            throw "Error: bad result, Math.pow(" + x + ", " + integerY + ") = " + result + " expected value close to " + expected;
+    }
+}
+noInline(testExponentFifty);
+testExponentFifty(53.70901164133102, 50.0, 3.179494118120144e+86);
+testExponentFifty(53.70901164133102, -10.0, 5.006432842621192e-18);
+
+function mathPowDoubleDoubleTestExponentTenThousands(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleDoubleTestExponentTenThousands);
+
+function mathPowDoubleIntTestExponentTenThousands(x, y) {
+    return Math.pow(x, y)
+}
+noInline(mathPowDoubleIntTestExponentTenThousands);
+function testExponentTenThousands(x, y, expected) {
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleDoubleTestExponentTenThousands(x, y);
+        if (!valuesAreClose(result, expected))
+            throw "Error: bad result, Math.pow(" + x + ", " + y + ") = " + result + " expected value close to " + expected;
+    }
+    var integerY = y | 0;
+    for (var i = 0; i < 10000; ++i) {
+        var result = mathPowDoubleIntTestExponentTenThousands(x, integerY);
+        if (!valuesAreClose(result, expected))
+            throw "Error: bad result, Math.pow(" + x + ", " + integerY + ") = " + result + " expected value close to " + expected;
+    }
+}
+noInline(testExponentTenThousands);
+testExponentTenThousands(1.001, 10000.0, 21916.681339048373);
+testExponentTenThousands(1.001, -1.0, 0.9990009990009991);
\ No newline at end of file

Added: trunk/Source/_javascript_Core/tests/stress/math-pow-nan-behaviors.js (0 => 180098)


--- trunk/Source/_javascript_Core/tests/stress/math-pow-nan-behaviors.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/math-pow-nan-behaviors.js	2015-02-14 04:20:21 UTC (rev 180098)
@@ -0,0 +1,85 @@
+// If y is NaN, the result is NaN.
+function testIntegerBaseWithNaNExponent() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(5, NaN);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(5, NaN) = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(i, NaN);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(i, NaN) = " + result + " with i = " + i;
+    }
+}
+noInline(testIntegerBaseWithNaNExponent);
+testIntegerBaseWithNaNExponent();
+
+function testFloatingPointBaseWithNaNExponent() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(5.5, NaN);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(5.5, NaN) = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(i + 1, NaN);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(i + 0.5, NaN) = " + result + " with i = " + i;
+    }
+}
+noInline(testFloatingPointBaseWithNaNExponent);
+testFloatingPointBaseWithNaNExponent();
+
+// If y is +0, the result is 1, even if x is NaN.
+// If y is −0, the result is 1, even if x is NaN.
+// If x is NaN and y is nonzero, the result is NaN.
+function testNaNBase() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(NaN, i + 1);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(NaN, i + 1) = " + result + " with i = " + i;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(NaN, i + 1.5);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(NaN, i + 1.5) = " + result + " with i = " + i;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(NaN, 0);
+        if (result !== 1)
+            throw "Error: bad result, Math.pow(NaN, 0) = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(NaN, -0);
+        if (result !== 1)
+            throw "Error: bad result, Math.pow(NaN, -0) = " + result;
+    }
+}
+noInline(testNaNBase);
+testNaNBase();
+
+// If abs(x) is 1 and y is +∞, the result is NaN.
+// If abs(x) is 1 and y is −∞, the result is NaN.
+function infiniteExponents() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(1, Number.POSITIVE_INFINITY);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(1, Number.POSITIVE_INFINITY) = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(-1, Number.POSITIVE_INFINITY);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(-1, Number.POSITIVE_INFINITY) = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(1, Number.NEGATIVE_INFINITY);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(1, Number.NEGATIVE_INFINITY) = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = Math.pow(-1, Number.NEGATIVE_INFINITY);
+        if (!isNaN(result))
+            throw "Error: bad result, Math.pow(-1, Number.NEGATIVE_INFINITY) = " + result;
+    }
+}
+noInline(infiniteExponents);
+infiniteExponents();

Added: trunk/Source/_javascript_Core/tests/stress/math-pow-with-constants.js (0 => 180098)


--- trunk/Source/_javascript_Core/tests/stress/math-pow-with-constants.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/math-pow-with-constants.js	2015-02-14 04:20:21 UTC (rev 180098)
@@ -0,0 +1,115 @@
+function exponentIsZero(x) {
+    return Math.pow(x, 0);
+}
+noInline(exponentIsZero);
+
+function testExponentIsZero() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = exponentIsZero(5);
+        if (result !== 1)
+            throw "Error: zeroExponent(5) should be 1, was = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = exponentIsZero(5.5);
+        if (result !== 1)
+            throw "Error: zeroExponent(5.5) should be 1, was = " + result;
+    }
+}
+testExponentIsZero();
+
+
+function exponentIsOne(x) {
+    return Math.pow(x, 1);
+}
+noInline(exponentIsOne);
+
+function testExponentIsOne() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = exponentIsOne(5);
+        if (result !== 5)
+            throw "Error: exponentIsOne(5) should be 5, was = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = exponentIsOne(5.5);
+        if (result !== 5.5)
+            throw "Error: exponentIsOne(5.5) should be 5.5, was = " + result;
+    }
+}
+testExponentIsOne();
+
+
+function powUsedAsSqrt(x) {
+    return Math.pow(x, 0.5);
+}
+noInline(powUsedAsSqrt);
+
+function testPowUsedAsSqrt() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = powUsedAsSqrt(4);
+        if (result !== Math.sqrt(4))
+            throw "Error: powUsedAsSqrt(4) should be 2, was = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = powUsedAsSqrt(4.4);
+        if (result !== Math.sqrt(4.4))
+            throw "Error: powUsedAsSqrt(4) should be " + Math.sqrt(4.4) + ", was = " + result;
+    }
+
+}
+testPowUsedAsSqrt();
+
+
+function intIntConstantsSmallNumbers() {
+    return Math.pow(42, 3);
+}
+function intIntConstantsLargeNumbers() {
+    // The result does not fit in a integer.
+    return Math.pow(42, 42);
+}
+function intIntSmallConstants() {
+    return Math.pow(42, 3);
+}
+function intDoubleConstants() {
+    return Math.pow(14, 42.5);
+}
+function doubleDoubleConstants() {
+    return Math.pow(13.5, 42.5);
+}
+function doubleIntConstants() {
+    return Math.pow(13.5, 52);
+}
+noInline(intIntConstantsSmallNumbers);
+noInline(intIntConstantsLargeNumbers);
+noInline(intDoubleConstants);
+noInline(doubleDoubleConstants);
+noInline(doubleIntConstants);
+
+function testBaseAndExponentConstantLiterals()
+{
+    for (var i = 0; i < 10000; ++i) {
+        var result = intIntConstantsSmallNumbers();
+        if (result !== 74088)
+            throw "Error: intIntConstantsSmallNumbers() should be 74088, was = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = intIntConstantsLargeNumbers();
+        if (result !== 1.5013093754529656e+68)
+            throw "Error: intIntConstantsLargeNumbers() should be 1.5013093754529656e+68, was = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = intDoubleConstants();
+        if (result !== 5.1338303882015765e+48)
+            throw "Error: intDoubleConstants() should be 5.1338303882015765e+48, was = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = doubleDoubleConstants();
+        if (result !== 1.0944228729647829e+48)
+            throw "Error: doubleDoubleConstants() should be 1.0944228729647829e+48, was = " + result;
+    }
+    for (var i = 0; i < 10000; ++i) {
+        var result = doubleIntConstants();
+        if (result !== 5.989022735311158e+58)
+            throw "Error: doubleIntConstants() should be 5.989022735311158e+58, was = " + result;
+    }
+}
+testBaseAndExponentConstantLiterals();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to