Add a DFG node for the Pow Intrinsics
https://bugs.webkit.org/show_bug.cgi?id=141540
Patch by Benjamin Poulain <bpoulain@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.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@180098 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index c6a020e..0295fc7 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,89 @@
2015-02-13 Benjamin Poulain <bpoulain@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 <bpoulain@apple.com>
+
ArithSqrt should not be conditional on supportsFloatingPointSqrt
https://bugs.webkit.org/show_bug.cgi?id=141546
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
index 19aeab7..48d1ffa 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
@@ -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);
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h
index b00f297..f73c2a4 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.h
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h
@@ -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);
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index d7b5b0f..bf7d041 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -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();
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index b8237ea..85e2a1c 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -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)
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index ac6b8f7..dcdb7db 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -122,6 +122,7 @@
case ArithAbs:
case ArithMin:
case ArithMax:
+ case ArithPow:
case ArithSqrt:
case ArithFRound:
case ArithSin:
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index c6feafd..5dcad43 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -81,6 +81,7 @@
case ArithAbs:
case ArithMin:
case ArithMax:
+ case ArithPow:
case ArithSqrt:
case ArithFRound:
case ArithSin:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index e31a54d..c82b5fb 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -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:
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index bffb866..2718b7b 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -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;
}
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 65cb399..8a0ea81 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -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) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index d1a6e4d..e0c5444 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -321,7 +321,8 @@
}
break;
}
-
+
+ case ArithPow:
case ArithSqrt:
case ArithFRound:
case ArithSin:
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 8e8ae07..c84513a 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -150,6 +150,7 @@
case ArithAbs:
case ArithMin:
case ArithMax:
+ case ArithPow:
case ArithSqrt:
case ArithFRound:
case ArithSin:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 38e6617..7478865 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -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)
{
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 3b7c5d0..33c777e4 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -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*);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index b810593..6bf6b86 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -1996,6 +1996,11 @@
break;
}
+ case ArithPow: {
+ compileArithPow(node);
+ break;
+ }
+
case ArithAbs: {
switch (node->child1().useKind()) {
case Int32Use: {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index ce067a9..6b123a7 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2241,6 +2241,10 @@
break;
}
+ case ArithPow:
+ compileArithPow(node);
+ break;
+
case ArithSqrt:
compileArithSqrt(node);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
index ce1e294..5e30dfe 100644
--- a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
@@ -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()));
diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp
index d438cfc..7d7b506 100644
--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp
+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp
@@ -240,6 +240,7 @@
case ArithMod:
case ArithMin:
case ArithMax:
+ case ArithPow:
case CompareLess:
case CompareLessEq:
case CompareGreater:
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index 5b9f7aa..248bdf5 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -89,6 +89,7 @@
case ArithAbs:
case ArithSin:
case ArithCos:
+ case ArithPow:
case ArithSqrt:
case ArithFRound:
case ArithNegate:
diff --git a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
index d227792..f284e8d 100644
--- a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
+++ b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
@@ -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)) \
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index e57537c..62c2074 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -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()
diff --git a/Source/JavaScriptCore/ftl/FTLOutput.h b/Source/JavaScriptCore/ftl/FTLOutput.h
index c70d8cd..af82cbd 100644
--- a/Source/JavaScriptCore/ftl/FTLOutput.h
+++ b/Source/JavaScriptCore/ftl/FTLOutput.h
@@ -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);
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 244b4be..80903da 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -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();
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index 767ea5b..d4ec6a1 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -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;
diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp
index 64a5a7a..038d553 100644
--- a/Source/JavaScriptCore/runtime/MathObject.cpp
+++ b/Source/JavaScriptCore/runtime/MathObject.cpp
@@ -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
diff --git a/Source/JavaScriptCore/tests/stress/math-pow-basics.js b/Source/JavaScriptCore/tests/stress/math-pow-basics.js
new file mode 100644
index 0000000..ddf1988
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/math-pow-basics.js
@@ -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);
diff --git a/Source/JavaScriptCore/tests/stress/math-pow-integer-exponent-fastpath.js b/Source/JavaScriptCore/tests/stress/math-pow-integer-exponent-fastpath.js
new file mode 100644
index 0000000..d606c44
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/math-pow-integer-exponent-fastpath.js
@@ -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
diff --git a/Source/JavaScriptCore/tests/stress/math-pow-nan-behaviors.js b/Source/JavaScriptCore/tests/stress/math-pow-nan-behaviors.js
new file mode 100644
index 0000000..da7dd44
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/math-pow-nan-behaviors.js
@@ -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();
diff --git a/Source/JavaScriptCore/tests/stress/math-pow-with-constants.js b/Source/JavaScriptCore/tests/stress/math-pow-with-constants.js
new file mode 100644
index 0000000..a4c108c
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/math-pow-with-constants.js
@@ -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();