[JSC] Math unary functions should be handled by DFG
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 May 2017 11:40:46 +0000 (11:40 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 May 2017 11:40:46 +0000 (11:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=171269

Reviewed by Saam Barati.

JSTests:

* stress/arith-acos-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueACosNoArgument):
(testNoArgument):
(opaqueAllTypesACos):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueACosForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueACosForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueACosForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueACosWithException):
(testException):
* stress/arith-acosh-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueACoshNoArgument):
(testNoArgument):
(opaqueAllTypesACosh):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueACoshForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueACoshForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueACoshForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueACoshWithException):
(testException):
* stress/arith-asin-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueASinNoArgument):
(testNoArgument):
(opaqueAllTypesASin):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueASinForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueASinForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueASinForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueASinWithException):
(testException):
* stress/arith-asinh-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueASinhNoArgument):
(testNoArgument):
(opaqueAllTypesASinh):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueASinhForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueASinhForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueASinhForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueASinhWithException):
(testException):
* stress/arith-atan-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueATanNoArgument):
(testNoArgument):
(opaqueAllTypesATan):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueATanForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueATanForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueATanForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueATanWithException):
(testException):
* stress/arith-atanh-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueATanhNoArgument):
(testNoArgument):
(opaqueAllTypesATanh):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueATanhForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueATanhForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueATanhForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueATanhWithException):
(testException):
* stress/arith-cbrt-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueCbrtNoArgument):
(testNoArgument):
(opaqueAllTypesCbrt):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueCbrtForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueCbrtForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueCbrtForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueCbrtWithException):
(testException):
* stress/arith-cosh-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueCoshNoArgument):
(testNoArgument):
(opaqueAllTypesCosh):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueCoshForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueCoshForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueCoshForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueCoshWithException):
(testException):
* stress/arith-expm1-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueExpm1NoArgument):
(testNoArgument):
(opaqueAllTypesExpm1):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueExpm1ForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueExpm1ForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueExpm1ForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueExpm1WithException):
(testException):
* stress/arith-log10-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueLog10NoArgument):
(testNoArgument):
(opaqueAllTypesLog10):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueLog10ForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueLog10ForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueLog10ForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueLog10WithException):
(testException):
* stress/arith-log2-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueLog2NoArgument):
(testNoArgument):
(opaqueAllTypesLog2):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueLog2ForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueLog2ForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueLog2ForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueLog2WithException):
(testException):
* stress/arith-sinh-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueSinhNoArgument):
(testNoArgument):
(opaqueAllTypesSinh):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueSinhForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueSinhForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueSinhForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueSinhWithException):
(testException):
* stress/arith-tan-on-various-types.js:
(isIdentical):
* stress/arith-tanh-on-various-types.js: Added.
(let.validInputTypedTestCases.validInputTestCases.map):
(isIdentical):
(opaqueTanhNoArgument):
(testNoArgument):
(opaqueAllTypesTanh):
(testAllTypesCall):
(testSingleTypeCall):
(testConstant):
(opaqueTanhForSideEffects):
(testSideEffect.let.testObject.valueOf):
(testSideEffect):
(opaqueTanhForCSE):
(testCSE.let.testObject.valueOf):
(testCSE):
(opaqueTanhForDCE):
(testDCE.let.testObject.valueOf):
(testDCE):
(testException.opaqueTanhWithException):
(testException):

Source/JavaScriptCore:

ArithSin, ArithCos, and ArithLog are just calling a C runtime function.
While handling them in DFG is not very effective for performance, they
can drop some type checks & value conversions and mark them as pure
operations. It is effective if they are involved in some complex
optimization phase. Actually, ArithLog is effective in kraken.

While a few of Math functions have DFG nodes, basically math functions
are pure. And large part of these functions are just calling a C runtime
function. This patch generalizes these nodes in DFG as ArithUnary. And
we annotate many unary math functions with Intrinsics and convert them
to ArithUnary in DFG. It also cleans up duplicate code in ArithSin,
ArithCos, and ArithLog. If your math function has some good DFG / FTL
optimization rather than calling a C runtime function, you should add
a specialized DFG node, like ArithSqrt.

We also create a new namespace JSC::Math. Inside it, we collect math functions.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGArithMode.cpp:
(JSC::DFG::arithUnaryFunction):
(JSC::DFG::arithUnaryOperation):
(WTF::printInternal):
* dfg/DFGArithMode.h:
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasArithUnaryType):
(JSC::DFG::Node::arithUnaryType):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithUnary):
(JSC::DFG::SpeculativeJIT::compileArithCos): Deleted.
(JSC::DFG::SpeculativeJIT::compileArithTan): Deleted.
(JSC::DFG::SpeculativeJIT::compileArithSin): Deleted.
(JSC::DFG::SpeculativeJIT::compileArithLog): Deleted.
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileArithUnary):
(JSC::FTL::DFG::LowerDFGToB3::compileArithSin): Deleted.
(JSC::FTL::DFG::LowerDFGToB3::compileArithCos): Deleted.
(JSC::FTL::DFG::LowerDFGToB3::compileArithTan): Deleted.
(JSC::FTL::DFG::LowerDFGToB3::compileArithLog): Deleted.
* ftl/FTLOutput.cpp:
(JSC::FTL::Output::doubleUnary):
(JSC::FTL::Output::doubleSin): Deleted.
(JSC::FTL::Output::doubleCos): Deleted.
(JSC::FTL::Output::doubleTan): Deleted.
(JSC::FTL::Output::doubleLog): Deleted.
* ftl/FTLOutput.h:
* runtime/Intrinsic.h:
* runtime/MathCommon.cpp:
(JSC::Math::log1p):
* runtime/MathCommon.h:
* runtime/MathObject.cpp:
(JSC::MathObject::finishCreation):
(JSC::mathProtoFuncACos):
(JSC::mathProtoFuncASin):
(JSC::mathProtoFuncATan):
(JSC::mathProtoFuncCos):
(JSC::mathProtoFuncExp):
(JSC::mathProtoFuncLog):
(JSC::mathProtoFuncSin):
(JSC::mathProtoFuncTan):
(JSC::mathProtoFuncACosh):
(JSC::mathProtoFuncASinh):
(JSC::mathProtoFuncATanh):
(JSC::mathProtoFuncCbrt):
(JSC::mathProtoFuncCosh):
(JSC::mathProtoFuncExpm1):
(JSC::mathProtoFuncLog1p):
(JSC::mathProtoFuncLog10):
(JSC::mathProtoFuncLog2):
(JSC::mathProtoFuncSinh):
(JSC::mathProtoFuncTanh):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@216178 268f45cc-cd09-0410-ab3c-d52691b4dbfc

44 files changed:
JSTests/ChangeLog
JSTests/stress/arith-acos-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-acosh-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-asin-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-asinh-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-atan-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-atanh-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-cbrt-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-cosh-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-expm1-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-log10-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-log2-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-sinh-on-various-types.js [new file with mode: 0644]
JSTests/stress/arith-tan-on-various-types.js
JSTests/stress/arith-tanh-on-various-types.js [new file with mode: 0644]
JSTests/stress/math-unary-no-arg.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGArithMode.cpp
Source/JavaScriptCore/dfg/DFGArithMode.h
Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/ftl/FTLOutput.cpp
Source/JavaScriptCore/ftl/FTLOutput.h
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/MathCommon.cpp
Source/JavaScriptCore/runtime/MathCommon.h
Source/JavaScriptCore/runtime/MathObject.cpp

index 5ff0a8d..a4dd092 100644 (file)
@@ -1,3 +1,273 @@
+2017-05-04  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] Math unary functions should be handled by DFG
+        https://bugs.webkit.org/show_bug.cgi?id=171269
+
+        Reviewed by Saam Barati.
+
+        * stress/arith-acos-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueACosNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesACos):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueACosForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueACosForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueACosForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueACosWithException):
+        (testException):
+        * stress/arith-acosh-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueACoshNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesACosh):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueACoshForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueACoshForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueACoshForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueACoshWithException):
+        (testException):
+        * stress/arith-asin-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueASinNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesASin):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueASinForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueASinForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueASinForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueASinWithException):
+        (testException):
+        * stress/arith-asinh-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueASinhNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesASinh):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueASinhForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueASinhForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueASinhForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueASinhWithException):
+        (testException):
+        * stress/arith-atan-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueATanNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesATan):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueATanForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueATanForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueATanForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueATanWithException):
+        (testException):
+        * stress/arith-atanh-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueATanhNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesATanh):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueATanhForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueATanhForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueATanhForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueATanhWithException):
+        (testException):
+        * stress/arith-cbrt-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueCbrtNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesCbrt):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueCbrtForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueCbrtForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueCbrtForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueCbrtWithException):
+        (testException):
+        * stress/arith-cosh-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueCoshNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesCosh):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueCoshForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueCoshForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueCoshForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueCoshWithException):
+        (testException):
+        * stress/arith-expm1-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueExpm1NoArgument):
+        (testNoArgument):
+        (opaqueAllTypesExpm1):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueExpm1ForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueExpm1ForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueExpm1ForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueExpm1WithException):
+        (testException):
+        * stress/arith-log10-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueLog10NoArgument):
+        (testNoArgument):
+        (opaqueAllTypesLog10):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueLog10ForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueLog10ForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueLog10ForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueLog10WithException):
+        (testException):
+        * stress/arith-log2-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueLog2NoArgument):
+        (testNoArgument):
+        (opaqueAllTypesLog2):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueLog2ForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueLog2ForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueLog2ForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueLog2WithException):
+        (testException):
+        * stress/arith-sinh-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueSinhNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesSinh):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueSinhForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueSinhForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueSinhForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueSinhWithException):
+        (testException):
+        * stress/arith-tan-on-various-types.js:
+        (isIdentical):
+        * stress/arith-tanh-on-various-types.js: Added.
+        (let.validInputTypedTestCases.validInputTestCases.map):
+        (isIdentical):
+        (opaqueTanhNoArgument):
+        (testNoArgument):
+        (opaqueAllTypesTanh):
+        (testAllTypesCall):
+        (testSingleTypeCall):
+        (testConstant):
+        (opaqueTanhForSideEffects):
+        (testSideEffect.let.testObject.valueOf):
+        (testSideEffect):
+        (opaqueTanhForCSE):
+        (testCSE.let.testObject.valueOf):
+        (testCSE):
+        (opaqueTanhForDCE):
+        (testDCE.let.testObject.valueOf):
+        (testDCE):
+        (testException.opaqueTanhWithException):
+        (testException):
+
 2017-05-03  Keith Miller  <keith_miller@apple.com>
 
         Array.prototype.sort should also allow a null comparator
diff --git a/JSTests/stress/arith-acos-on-various-types.js b/JSTests/stress/arith-acos-on-various-types.js
new file mode 100644 (file)
index 0000000..7f72615
--- /dev/null
@@ -0,0 +1,236 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let acosOfHalf = Math.acos(0.5);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "" + Math.acos(0)],
+    ["1", "0"],
+    ["0", "" + Math.acos(0)],
+    ["-0.", "" + Math.acos(0)],
+    ["0.5", "" + acosOfHalf],
+    ["Math.PI", "" + Math.acos(Math.PI)],
+    ["Infinity", "NaN"],
+    ["-Infinity", "NaN"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"0.5\"", "" + acosOfHalf],
+    ["{ valueOf: () => { return 0.5; } }", "" + acosOfHalf],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.acos() without arguments.
+function opaqueACosNoArgument() {
+    return Math.acos();
+}
+noInline(opaqueACosNoArgument);
+noOSRExitFuzzing(opaqueACosNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueACosNoArgument();
+        if (output === output) {
+            throw "Failed opaqueACosNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueACosNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.acos() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesACos(argument) {
+    return Math.acos(argument);
+}
+noInline(opaqueAllTypesACos);
+noOSRExitFuzzing(opaqueAllTypesACos);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesACos(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesACos) > 2)
+        throw "We should have detected acos() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.acos() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueACos(argument) {
+                return Math.acos(argument);
+            }
+            noInline(opaqueACos);
+            noOSRExitFuzzing(opaqueACos);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueACos(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueACos) > 1)
+                throw "We should have compiled a single acos for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.acos() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueACosOnConstant() {
+                return Math.acos(${testCaseInput[0]});
+            }
+            noInline(opaqueACosOnConstant);
+            noOSRExitFuzzing(opaqueACosOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueACosOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueACosOnConstant) > 1)
+                throw "We should have compiled a single acos for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueACosForSideEffects(argument) {
+    return Math.acos(argument);
+}
+noInline(opaqueACosForSideEffects);
+noOSRExitFuzzing(opaqueACosForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let acosResult = Math.acos(0.2);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueACosForSideEffects(testObject) !== acosResult)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueACosForSideEffects) > 1)
+        throw "opaqueACosForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify acos() is not subject to CSE if the argument has side effects.
+function opaqueACosForCSE(argument) {
+    return Math.acos(argument) + Math.acos(argument) + Math.acos(argument);
+}
+noInline(opaqueACosForCSE);
+noOSRExitFuzzing(opaqueACosForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let acosResult = Math.acos(0.2);
+    let threeacosResult = acosResult + acosResult + acosResult;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueACosForCSE(testObject) !== threeacosResult)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueACosForCSE) > 1)
+        throw "opaqueACosForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify acos() is not subject to DCE if the argument has side effects.
+function opaqueACosForDCE(argument) {
+    Math.acos(argument);
+}
+noInline(opaqueACosForDCE);
+noOSRExitFuzzing(opaqueACosForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueACosForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueACosForDCE) > 1)
+        throw "opaqueACosForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueACosWithException(argument) {
+        let result = Math.acos(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueACosWithException);
+
+    let testObject = { valueOf: () => {  return 0.1; } };
+    let acosResult = Math.acos(0.1);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueACosWithException(testObject) !== acosResult)
+            throw "Incorrect result in opaqueACosWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 0.1; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueACosWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueACosWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-acosh-on-various-types.js b/JSTests/stress/arith-acosh-on-various-types.js
new file mode 100644 (file)
index 0000000..a6886de
--- /dev/null
@@ -0,0 +1,235 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let acoshOfFour = Math.acosh(4);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "NaN"],
+    ["0", "NaN"],
+    ["-0.", "NaN"],
+    ["4", "" + acoshOfFour],
+    ["Math.PI", "" + Math.acosh(Math.PI)],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "NaN"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"4\"", "" + acoshOfFour],
+    ["{ valueOf: () => { return 4; } }", "" + acoshOfFour],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.acosh() without arguments.
+function opaqueACoshNoArgument() {
+    return Math.acosh();
+}
+noInline(opaqueACoshNoArgument);
+noOSRExitFuzzing(opaqueACoshNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueACoshNoArgument();
+        if (output === output) {
+            throw "Failed opaqueACoshNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueACoshNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.acosh() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesACosh(argument) {
+    return Math.acosh(argument);
+}
+noInline(opaqueAllTypesACosh);
+noOSRExitFuzzing(opaqueAllTypesACosh);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesACosh(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesACosh) > 2)
+        throw "We should have detected acosh() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.acosh() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueACosh(argument) {
+                return Math.acosh(argument);
+            }
+            noInline(opaqueACosh);
+            noOSRExitFuzzing(opaqueACosh);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueACosh(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueACosh) > 1)
+                throw "We should have compiled a single acosh for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.acosh() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueACoshOnConstant() {
+                return Math.acosh(${testCaseInput[0]});
+            }
+            noInline(opaqueACoshOnConstant);
+            noOSRExitFuzzing(opaqueACoshOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueACoshOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueACoshOnConstant) > 1)
+                throw "We should have compiled a single acosh for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueACoshForSideEffects(argument) {
+    return Math.acosh(argument);
+}
+noInline(opaqueACoshForSideEffects);
+noOSRExitFuzzing(opaqueACoshForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let acosh16 = Math.acosh(16);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueACoshForSideEffects(testObject) !== acosh16)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueACoshForSideEffects) > 1)
+        throw "opaqueACoshForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify acosh() is not subject to CSE if the argument has side effects.
+function opaqueACoshForCSE(argument) {
+    return Math.acosh(argument) + Math.acosh(argument) + Math.acosh(argument);
+}
+noInline(opaqueACoshForCSE);
+noOSRExitFuzzing(opaqueACoshForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let acosh16 = Math.acosh(16);
+    let threeACosh16 = acosh16 + acosh16 + acosh16;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueACoshForCSE(testObject) !== threeACosh16)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueACoshForCSE) > 1)
+        throw "opaqueACoshForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify acosh() is not subject to DCE if the argument has side effects.
+function opaqueACoshForDCE(argument) {
+    Math.acosh(argument);
+}
+noInline(opaqueACoshForDCE);
+noOSRExitFuzzing(opaqueACoshForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueACoshForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueACoshForDCE) > 1)
+        throw "opaqueACoshForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueACoshWithException(argument) {
+        let result = Math.acosh(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueACoshWithException);
+
+    let testObject = { valueOf: () => {  return 64; } };
+    let acosh64 = Math.acosh(64);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueACoshWithException(testObject) !== acosh64)
+            throw "Incorrect result in opaqueACoshWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 64; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueACoshWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueACoshWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-asin-on-various-types.js b/JSTests/stress/arith-asin-on-various-types.js
new file mode 100644 (file)
index 0000000..d224a12
--- /dev/null
@@ -0,0 +1,236 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let asinOfHalf = Math.asin(0.5);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["1", "" + Math.asin(1)],
+    ["0", "0"],
+    ["-0.", "-0"],
+    ["0.5", "" + asinOfHalf],
+    ["Math.PI", "" + Math.asin(Math.PI)],
+    ["Infinity", "NaN"],
+    ["-Infinity", "NaN"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"0.5\"", "" + asinOfHalf],
+    ["{ valueOf: () => { return 0.5; } }", "" + asinOfHalf],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.asin() without arguments.
+function opaqueASinNoArgument() {
+    return Math.asin();
+}
+noInline(opaqueASinNoArgument);
+noOSRExitFuzzing(opaqueASinNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueASinNoArgument();
+        if (output === output) {
+            throw "Failed opaqueASinNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueASinNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.asin() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesASin(argument) {
+    return Math.asin(argument);
+}
+noInline(opaqueAllTypesASin);
+noOSRExitFuzzing(opaqueAllTypesASin);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesASin(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesASin) > 2)
+        throw "We should have detected asin() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.asin() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueASin(argument) {
+                return Math.asin(argument);
+            }
+            noInline(opaqueASin);
+            noOSRExitFuzzing(opaqueASin);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueASin(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueASin) > 1)
+                throw "We should have compiled a single asin for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.asin() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueASinOnConstant() {
+                return Math.asin(${testCaseInput[0]});
+            }
+            noInline(opaqueASinOnConstant);
+            noOSRExitFuzzing(opaqueASinOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueASinOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueASinOnConstant) > 1)
+                throw "We should have compiled a single asin for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueASinForSideEffects(argument) {
+    return Math.asin(argument);
+}
+noInline(opaqueASinForSideEffects);
+noOSRExitFuzzing(opaqueASinForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let asinResult = Math.asin(0.2);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueASinForSideEffects(testObject) !== asinResult)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueASinForSideEffects) > 1)
+        throw "opaqueASinForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify asin() is not subject to CSE if the argument has side effects.
+function opaqueASinForCSE(argument) {
+    return Math.asin(argument) + Math.asin(argument) + Math.asin(argument);
+}
+noInline(opaqueASinForCSE);
+noOSRExitFuzzing(opaqueASinForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let asinResult = Math.asin(0.2);
+    let threeasinResult = asinResult + asinResult + asinResult;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueASinForCSE(testObject) !== threeasinResult)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueASinForCSE) > 1)
+        throw "opaqueASinForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify asin() is not subject to DCE if the argument has side effects.
+function opaqueASinForDCE(argument) {
+    Math.asin(argument);
+}
+noInline(opaqueASinForDCE);
+noOSRExitFuzzing(opaqueASinForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueASinForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueASinForDCE) > 1)
+        throw "opaqueASinForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueASinWithException(argument) {
+        let result = Math.asin(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueASinWithException);
+
+    let testObject = { valueOf: () => {  return 0.1; } };
+    let asinResult = Math.asin(0.1);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueASinWithException(testObject) !== asinResult)
+            throw "Incorrect result in opaqueASinWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 0.1; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueASinWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueASinWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-asinh-on-various-types.js b/JSTests/stress/arith-asinh-on-various-types.js
new file mode 100644 (file)
index 0000000..1a12cbe
--- /dev/null
@@ -0,0 +1,235 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let asinhOfFour = Math.asinh(4);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["0", "0"],
+    ["-0.", "-0"],
+    ["4", "" + asinhOfFour],
+    ["Math.PI", "" + Math.asinh(Math.PI)],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "-Infinity"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"4\"", "" + asinhOfFour],
+    ["{ valueOf: () => { return 4; } }", "" + asinhOfFour],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.asinh() without arguments.
+function opaqueASinhNoArgument() {
+    return Math.asinh();
+}
+noInline(opaqueASinhNoArgument);
+noOSRExitFuzzing(opaqueASinhNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueASinhNoArgument();
+        if (output === output) {
+            throw "Failed opaqueASinhNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueASinhNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.asinh() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesASinh(argument) {
+    return Math.asinh(argument);
+}
+noInline(opaqueAllTypesASinh);
+noOSRExitFuzzing(opaqueAllTypesASinh);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesASinh(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesASinh) > 2)
+        throw "We should have detected asinh() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.asinh() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueASinh(argument) {
+                return Math.asinh(argument);
+            }
+            noInline(opaqueASinh);
+            noOSRExitFuzzing(opaqueASinh);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueASinh(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueASinh) > 1)
+                throw "We should have compiled a single asinh for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.asinh() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueASinhOnConstant() {
+                return Math.asinh(${testCaseInput[0]});
+            }
+            noInline(opaqueASinhOnConstant);
+            noOSRExitFuzzing(opaqueASinhOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueASinhOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueASinhOnConstant) > 1)
+                throw "We should have compiled a single asinh for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueASinhForSideEffects(argument) {
+    return Math.asinh(argument);
+}
+noInline(opaqueASinhForSideEffects);
+noOSRExitFuzzing(opaqueASinhForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let asinh16 = Math.asinh(16);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueASinhForSideEffects(testObject) !== asinh16)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueASinhForSideEffects) > 1)
+        throw "opaqueASinhForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify asinh() is not subject to CSE if the argument has side effects.
+function opaqueASinhForCSE(argument) {
+    return Math.asinh(argument) + Math.asinh(argument) + Math.asinh(argument);
+}
+noInline(opaqueASinhForCSE);
+noOSRExitFuzzing(opaqueASinhForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let asinh16 = Math.asinh(16);
+    let threeASinh16 = asinh16 + asinh16 + asinh16;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueASinhForCSE(testObject) !== threeASinh16)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueASinhForCSE) > 1)
+        throw "opaqueASinhForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify asinh() is not subject to DCE if the argument has side effects.
+function opaqueASinhForDCE(argument) {
+    Math.asinh(argument);
+}
+noInline(opaqueASinhForDCE);
+noOSRExitFuzzing(opaqueASinhForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueASinhForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueASinhForDCE) > 1)
+        throw "opaqueASinhForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueASinhWithException(argument) {
+        let result = Math.asinh(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueASinhWithException);
+
+    let testObject = { valueOf: () => {  return 64; } };
+    let asinh64 = Math.asinh(64);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueASinhWithException(testObject) !== asinh64)
+            throw "Incorrect result in opaqueASinhWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 64; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueASinhWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueASinhWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-atan-on-various-types.js b/JSTests/stress/arith-atan-on-various-types.js
new file mode 100644 (file)
index 0000000..6c57d76
--- /dev/null
@@ -0,0 +1,235 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let atanOfFour = Math.atan(4);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["0", "0"],
+    ["-0.", "-0"],
+    ["4", "" + atanOfFour],
+    ["Math.PI", "" + Math.atan(Math.PI)],
+    ["Infinity", "" + Math.atan(Infinity)],
+    ["-Infinity", "-" + Math.atan(Infinity)],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"4\"", "" + atanOfFour],
+    ["{ valueOf: () => { return 4; } }", "" + atanOfFour],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.atan() without arguments.
+function opaqueATanNoArgument() {
+    return Math.atan();
+}
+noInline(opaqueATanNoArgument);
+noOSRExitFuzzing(opaqueATanNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueATanNoArgument();
+        if (output === output) {
+            throw "Failed opaqueATanNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueATanNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.atan() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesATan(argument) {
+    return Math.atan(argument);
+}
+noInline(opaqueAllTypesATan);
+noOSRExitFuzzing(opaqueAllTypesATan);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesATan(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesATan) > 2)
+        throw "We should have detected atan() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.atan() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueATan(argument) {
+                return Math.atan(argument);
+            }
+            noInline(opaqueATan);
+            noOSRExitFuzzing(opaqueATan);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueATan(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueATan) > 1)
+                throw "We should have compiled a single atan for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.atan() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueATanOnConstant() {
+                return Math.atan(${testCaseInput[0]});
+            }
+            noInline(opaqueATanOnConstant);
+            noOSRExitFuzzing(opaqueATanOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueATanOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueATanOnConstant) > 1)
+                throw "We should have compiled a single atan for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueATanForSideEffects(argument) {
+    return Math.atan(argument);
+}
+noInline(opaqueATanForSideEffects);
+noOSRExitFuzzing(opaqueATanForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let AtanResult = Math.atan(16);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueATanForSideEffects(testObject) !== AtanResult)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueATanForSideEffects) > 1)
+        throw "opaqueATanForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify atan() is not subject to CSE if the argument has side effects.
+function opaqueATanForCSE(argument) {
+    return Math.atan(argument) + Math.atan(argument) + Math.atan(argument);
+}
+noInline(opaqueATanForCSE);
+noOSRExitFuzzing(opaqueATanForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let AtanResult = Math.atan(16);
+    let threeAtanResult = AtanResult + AtanResult + AtanResult;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueATanForCSE(testObject) !== threeAtanResult)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueATanForCSE) > 1)
+        throw "opaqueATanForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify atan() is not subject to DCE if the argument has side effects.
+function opaqueATanForDCE(argument) {
+    Math.atan(argument);
+}
+noInline(opaqueATanForDCE);
+noOSRExitFuzzing(opaqueATanForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueATanForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueATanForDCE) > 1)
+        throw "opaqueATanForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueATanWithException(argument) {
+        let result = Math.atan(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueATanWithException);
+
+    let testObject = { valueOf: () => {  return 64; } };
+    let atanResult = Math.atan(64);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueATanWithException(testObject) !== atanResult)
+            throw "Incorrect result in opaqueATanWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 64; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueATanWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueATanWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-atanh-on-various-types.js b/JSTests/stress/arith-atanh-on-various-types.js
new file mode 100644 (file)
index 0000000..6fe51a4
--- /dev/null
@@ -0,0 +1,236 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let atanhOfHalf = Math.atanh(0.5);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["1", "Infinity"],
+    ["0", "0"],
+    ["-0.", "-0"],
+    ["0.5", "" + atanhOfHalf],
+    ["Math.PI", "" + Math.atanh(Math.PI)],
+    ["Infinity", "NaN"],
+    ["-Infinity", "NaN"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"0.5\"", "" + atanhOfHalf],
+    ["{ valueOf: () => { return 0.5; } }", "" + atanhOfHalf],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.atanh() without arguments.
+function opaqueATanhNoArgument() {
+    return Math.atanh();
+}
+noInline(opaqueATanhNoArgument);
+noOSRExitFuzzing(opaqueATanhNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueATanhNoArgument();
+        if (output === output) {
+            throw "Failed opaqueATanhNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueATanhNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.atanh() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesATanh(argument) {
+    return Math.atanh(argument);
+}
+noInline(opaqueAllTypesATanh);
+noOSRExitFuzzing(opaqueAllTypesATanh);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesATanh(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesATanh) > 2)
+        throw "We should have detected atanh() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.atanh() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueATanh(argument) {
+                return Math.atanh(argument);
+            }
+            noInline(opaqueATanh);
+            noOSRExitFuzzing(opaqueATanh);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueATanh(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueATanh) > 1)
+                throw "We should have compiled a single atanh for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.atanh() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueATanhOnConstant() {
+                return Math.atanh(${testCaseInput[0]});
+            }
+            noInline(opaqueATanhOnConstant);
+            noOSRExitFuzzing(opaqueATanhOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueATanhOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueATanhOnConstant) > 1)
+                throw "We should have compiled a single atanh for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueATanhForSideEffects(argument) {
+    return Math.atanh(argument);
+}
+noInline(opaqueATanhForSideEffects);
+noOSRExitFuzzing(opaqueATanhForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let atanhResult = Math.atanh(0.2);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueATanhForSideEffects(testObject) !== atanhResult)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueATanhForSideEffects) > 1)
+        throw "opaqueATanhForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify atanh() is not subject to CSE if the argument has side effects.
+function opaqueATanhForCSE(argument) {
+    return Math.atanh(argument) + Math.atanh(argument) + Math.atanh(argument);
+}
+noInline(opaqueATanhForCSE);
+noOSRExitFuzzing(opaqueATanhForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let atanhResult = Math.atanh(0.2);
+    let threeatanhResult = atanhResult + atanhResult + atanhResult;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueATanhForCSE(testObject) !== threeatanhResult)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueATanhForCSE) > 1)
+        throw "opaqueATanhForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify atanh() is not subject to DCE if the argument has side effects.
+function opaqueATanhForDCE(argument) {
+    Math.atanh(argument);
+}
+noInline(opaqueATanhForDCE);
+noOSRExitFuzzing(opaqueATanhForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueATanhForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueATanhForDCE) > 1)
+        throw "opaqueATanhForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueATanhWithException(argument) {
+        let result = Math.atanh(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueATanhWithException);
+
+    let testObject = { valueOf: () => {  return 0.1; } };
+    let atanhResult = Math.atanh(0.1);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueATanhWithException(testObject) !== atanhResult)
+            throw "Incorrect result in opaqueATanhWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 0.1; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueATanhWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueATanhWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-cbrt-on-various-types.js b/JSTests/stress/arith-cbrt-on-various-types.js
new file mode 100644 (file)
index 0000000..758564b
--- /dev/null
@@ -0,0 +1,237 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let cbrtOfHalf = Math.cbrt(0.5);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["1", "1"],
+    ["0", "0"],
+    ["-0.", "-0"],
+    ["-42.", "" + Math.cbrt(-42)],
+    ["0.5", "" + cbrtOfHalf],
+    ["Math.PI", "" + Math.cbrt(Math.PI)],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "-Infinity"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"0.5\"", "" + cbrtOfHalf],
+    ["{ valueOf: () => { return 0.5; } }", "" + cbrtOfHalf],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.cbrt() without arguments.
+function opaqueCbrtNoArgument() {
+    return Math.cbrt();
+}
+noInline(opaqueCbrtNoArgument);
+noOSRExitFuzzing(opaqueCbrtNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueCbrtNoArgument();
+        if (output === output) {
+            throw "Failed opaqueCbrtNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueCbrtNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.cbrt() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesCbrt(argument) {
+    return Math.cbrt(argument);
+}
+noInline(opaqueAllTypesCbrt);
+noOSRExitFuzzing(opaqueAllTypesCbrt);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesCbrt(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesCbrt) > 2)
+        throw "We should have detected cbrt() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.cbrt() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueCbrt(argument) {
+                return Math.cbrt(argument);
+            }
+            noInline(opaqueCbrt);
+            noOSRExitFuzzing(opaqueCbrt);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueCbrt(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueCbrt) > 1)
+                throw "We should have compiled a single cbrt for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.cbrt() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueCbrtOnConstant() {
+                return Math.cbrt(${testCaseInput[0]});
+            }
+            noInline(opaqueCbrtOnConstant);
+            noOSRExitFuzzing(opaqueCbrtOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueCbrtOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueCbrtOnConstant) > 1)
+                throw "We should have compiled a single cbrt for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueCbrtForSideEffects(argument) {
+    return Math.cbrt(argument);
+}
+noInline(opaqueCbrtForSideEffects);
+noOSRExitFuzzing(opaqueCbrtForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let cbrtResult = Math.cbrt(0.2);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueCbrtForSideEffects(testObject) !== cbrtResult)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueCbrtForSideEffects) > 1)
+        throw "opaqueCbrtForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify cbrt() is not subject to CSE if the argument has side effects.
+function opaqueCbrtForCSE(argument) {
+    return Math.cbrt(argument) + Math.cbrt(argument) + Math.cbrt(argument);
+}
+noInline(opaqueCbrtForCSE);
+noOSRExitFuzzing(opaqueCbrtForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let cbrtResult = Math.cbrt(0.2);
+    let threecbrtResult = cbrtResult + cbrtResult + cbrtResult;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueCbrtForCSE(testObject) !== threecbrtResult)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueCbrtForCSE) > 1)
+        throw "opaqueCbrtForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify cbrt() is not subject to DCE if the argument has side effects.
+function opaqueCbrtForDCE(argument) {
+    Math.cbrt(argument);
+}
+noInline(opaqueCbrtForDCE);
+noOSRExitFuzzing(opaqueCbrtForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueCbrtForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueCbrtForDCE) > 1)
+        throw "opaqueCbrtForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueCbrtWithException(argument) {
+        let result = Math.cbrt(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueCbrtWithException);
+
+    let testObject = { valueOf: () => {  return 0.1; } };
+    let cbrtResult = Math.cbrt(0.1);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueCbrtWithException(testObject) !== cbrtResult)
+            throw "Incorrect result in opaqueCbrtWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 0.1; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueCbrtWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueCbrtWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-cosh-on-various-types.js b/JSTests/stress/arith-cosh-on-various-types.js
new file mode 100644 (file)
index 0000000..6811961
--- /dev/null
@@ -0,0 +1,235 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let coshOfFour = Math.cosh(4);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "1"],
+    ["0", "1"],
+    ["-0.", "1"],
+    ["4", "" + coshOfFour],
+    ["Math.PI", "" + Math.cosh(Math.PI)],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "Infinity"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"4\"", "" + coshOfFour],
+    ["{ valueOf: () => { return 4; } }", "" + coshOfFour],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.cosh() without arguments.
+function opaqueCoshNoArgument() {
+    return Math.cosh();
+}
+noInline(opaqueCoshNoArgument);
+noOSRExitFuzzing(opaqueCoshNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueCoshNoArgument();
+        if (output === output) {
+            throw "Failed opaqueCoshNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueCoshNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.cosh() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesCosh(argument) {
+    return Math.cosh(argument);
+}
+noInline(opaqueAllTypesCosh);
+noOSRExitFuzzing(opaqueAllTypesCosh);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesCosh(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesCosh) > 2)
+        throw "We should have detected cosh() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.cosh() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueCosh(argument) {
+                return Math.cosh(argument);
+            }
+            noInline(opaqueCosh);
+            noOSRExitFuzzing(opaqueCosh);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueCosh(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueCosh) > 1)
+                throw "We should have compiled a single cosh for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.cosh() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueCoshOnConstant() {
+                return Math.cosh(${testCaseInput[0]});
+            }
+            noInline(opaqueCoshOnConstant);
+            noOSRExitFuzzing(opaqueCoshOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueCoshOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueCoshOnConstant) > 1)
+                throw "We should have compiled a single cosh for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueCoshForSideEffects(argument) {
+    return Math.cosh(argument);
+}
+noInline(opaqueCoshForSideEffects);
+noOSRExitFuzzing(opaqueCoshForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let cosh16 = Math.cosh(16);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueCoshForSideEffects(testObject) !== cosh16)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueCoshForSideEffects) > 1)
+        throw "opaqueCoshForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify cosh() is not subject to CSE if the argument has side effects.
+function opaqueCoshForCSE(argument) {
+    return Math.cosh(argument) + Math.cosh(argument) + Math.cosh(argument);
+}
+noInline(opaqueCoshForCSE);
+noOSRExitFuzzing(opaqueCoshForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let cosh16 = Math.cosh(16);
+    let threeCosh16 = cosh16 + cosh16 + cosh16;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueCoshForCSE(testObject) !== threeCosh16)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueCoshForCSE) > 1)
+        throw "opaqueCoshForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify cosh() is not subject to DCE if the argument has side effects.
+function opaqueCoshForDCE(argument) {
+    Math.cosh(argument);
+}
+noInline(opaqueCoshForDCE);
+noOSRExitFuzzing(opaqueCoshForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueCoshForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueCoshForDCE) > 1)
+        throw "opaqueCoshForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueCoshWithException(argument) {
+        let result = Math.cosh(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueCoshWithException);
+
+    let testObject = { valueOf: () => {  return 64; } };
+    let cosh64 = Math.cosh(64);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueCoshWithException(testObject) !== cosh64)
+            throw "Incorrect result in opaqueCoshWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 64; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueCoshWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueCoshWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-expm1-on-various-types.js b/JSTests/stress/arith-expm1-on-various-types.js
new file mode 100644 (file)
index 0000000..dbb0b10
--- /dev/null
@@ -0,0 +1,236 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let expm1OfHalf = Math.expm1(0.5);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["1", "" + Math.expm1(1)],
+    ["0", "0"],
+    ["-0.", "-0"],
+    ["0.5", "" + expm1OfHalf],
+    ["Math.PI", "" + Math.expm1(Math.PI)],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "-1"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"0.5\"", "" + expm1OfHalf],
+    ["{ valueOf: () => { return 0.5; } }", "" + expm1OfHalf],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.expm1() without arguments.
+function opaqueExpm1NoArgument() {
+    return Math.expm1();
+}
+noInline(opaqueExpm1NoArgument);
+noOSRExitFuzzing(opaqueExpm1NoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueExpm1NoArgument();
+        if (output === output) {
+            throw "Failed opaqueExpm1NoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueExpm1NoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.expm1() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesExpm1(argument) {
+    return Math.expm1(argument);
+}
+noInline(opaqueAllTypesExpm1);
+noOSRExitFuzzing(opaqueAllTypesExpm1);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesExpm1(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesExpm1) > 2)
+        throw "We should have detected expm1() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.expm1() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueExpm1(argument) {
+                return Math.expm1(argument);
+            }
+            noInline(opaqueExpm1);
+            noOSRExitFuzzing(opaqueExpm1);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueExpm1(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueExpm1) > 1)
+                throw "We should have compiled a single expm1 for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.expm1() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueExpm1OnConstant() {
+                return Math.expm1(${testCaseInput[0]});
+            }
+            noInline(opaqueExpm1OnConstant);
+            noOSRExitFuzzing(opaqueExpm1OnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueExpm1OnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueExpm1OnConstant) > 1)
+                throw "We should have compiled a single expm1 for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueExpm1ForSideEffects(argument) {
+    return Math.expm1(argument);
+}
+noInline(opaqueExpm1ForSideEffects);
+noOSRExitFuzzing(opaqueExpm1ForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let expm1Result = Math.expm1(0.2);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueExpm1ForSideEffects(testObject) !== expm1Result)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueExpm1ForSideEffects) > 1)
+        throw "opaqueExpm1ForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify expm1() is not subject to CSE if the argument has side effects.
+function opaqueExpm1ForCSE(argument) {
+    return Math.expm1(argument) + Math.expm1(argument) + Math.expm1(argument);
+}
+noInline(opaqueExpm1ForCSE);
+noOSRExitFuzzing(opaqueExpm1ForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let expm1Result = Math.expm1(0.2);
+    let threeexpm1Result = expm1Result + expm1Result + expm1Result;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueExpm1ForCSE(testObject) !== threeexpm1Result)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueExpm1ForCSE) > 1)
+        throw "opaqueExpm1ForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify expm1() is not subject to DCE if the argument has side effects.
+function opaqueExpm1ForDCE(argument) {
+    Math.expm1(argument);
+}
+noInline(opaqueExpm1ForDCE);
+noOSRExitFuzzing(opaqueExpm1ForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueExpm1ForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueExpm1ForDCE) > 1)
+        throw "opaqueExpm1ForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueExpm1WithException(argument) {
+        let result = Math.expm1(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueExpm1WithException);
+
+    let testObject = { valueOf: () => {  return 0.1; } };
+    let expm1Result = Math.expm1(0.1);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueExpm1WithException(testObject) !== expm1Result)
+            throw "Incorrect result in opaqueExpm1WithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 0.1; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueExpm1WithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueExpm1WithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-log10-on-various-types.js b/JSTests/stress/arith-log10-on-various-types.js
new file mode 100644 (file)
index 0000000..0ff6176
--- /dev/null
@@ -0,0 +1,236 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let log10OfHalf = Math.log10(0.5);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "-Infinity"],
+    ["1", "0"],
+    ["0", "-Infinity"],
+    ["-0.", "-Infinity"],
+    ["0.5", "" + log10OfHalf],
+    ["Math.PI", "" + Math.log10(Math.PI)],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "NaN"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"0.5\"", "" + log10OfHalf],
+    ["{ valueOf: () => { return 0.5; } }", "" + log10OfHalf],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.log10() without arguments.
+function opaqueLog10NoArgument() {
+    return Math.log10();
+}
+noInline(opaqueLog10NoArgument);
+noOSRExitFuzzing(opaqueLog10NoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueLog10NoArgument();
+        if (output === output) {
+            throw "Failed opaqueLog10NoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueLog10NoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.log10() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesLog10(argument) {
+    return Math.log10(argument);
+}
+noInline(opaqueAllTypesLog10);
+noOSRExitFuzzing(opaqueAllTypesLog10);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesLog10(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesLog10) > 2)
+        throw "We should have detected log10() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.log10() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueLog10(argument) {
+                return Math.log10(argument);
+            }
+            noInline(opaqueLog10);
+            noOSRExitFuzzing(opaqueLog10);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueLog10(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueLog10) > 1)
+                throw "We should have compiled a single log10 for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.log10() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueLog10OnConstant() {
+                return Math.log10(${testCaseInput[0]});
+            }
+            noInline(opaqueLog10OnConstant);
+            noOSRExitFuzzing(opaqueLog10OnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueLog10OnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueLog10OnConstant) > 1)
+                throw "We should have compiled a single log10 for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueLog10ForSideEffects(argument) {
+    return Math.log10(argument);
+}
+noInline(opaqueLog10ForSideEffects);
+noOSRExitFuzzing(opaqueLog10ForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let log10Result = Math.log10(0.2);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueLog10ForSideEffects(testObject) !== log10Result)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueLog10ForSideEffects) > 1)
+        throw "opaqueLog10ForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify log10() is not subject to CSE if the argument has side effects.
+function opaqueLog10ForCSE(argument) {
+    return Math.log10(argument) + Math.log10(argument) + Math.log10(argument);
+}
+noInline(opaqueLog10ForCSE);
+noOSRExitFuzzing(opaqueLog10ForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let log10Result = Math.log10(0.2);
+    let threelog10Result = log10Result + log10Result + log10Result;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueLog10ForCSE(testObject) !== threelog10Result)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueLog10ForCSE) > 1)
+        throw "opaqueLog10ForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify log10() is not subject to DCE if the argument has side effects.
+function opaqueLog10ForDCE(argument) {
+    Math.log10(argument);
+}
+noInline(opaqueLog10ForDCE);
+noOSRExitFuzzing(opaqueLog10ForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueLog10ForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueLog10ForDCE) > 1)
+        throw "opaqueLog10ForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueLog10WithException(argument) {
+        let result = Math.log10(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueLog10WithException);
+
+    let testObject = { valueOf: () => {  return 0.1; } };
+    let log10Result = Math.log10(0.1);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueLog10WithException(testObject) !== log10Result)
+            throw "Incorrect result in opaqueLog10WithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 0.1; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueLog10WithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueLog10WithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-log2-on-various-types.js b/JSTests/stress/arith-log2-on-various-types.js
new file mode 100644 (file)
index 0000000..fec8f32
--- /dev/null
@@ -0,0 +1,236 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let log2OfHalf = Math.log2(0.5);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "-Infinity"],
+    ["1", "0"],
+    ["0", "-Infinity"],
+    ["-0.", "-Infinity"],
+    ["0.5", "" + log2OfHalf],
+    ["Math.PI", "" + Math.log2(Math.PI)],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "NaN"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"0.5\"", "" + log2OfHalf],
+    ["{ valueOf: () => { return 0.5; } }", "" + log2OfHalf],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.log2() without arguments.
+function opaqueLog2NoArgument() {
+    return Math.log2();
+}
+noInline(opaqueLog2NoArgument);
+noOSRExitFuzzing(opaqueLog2NoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueLog2NoArgument();
+        if (output === output) {
+            throw "Failed opaqueLog2NoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueLog2NoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.log2() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesLog2(argument) {
+    return Math.log2(argument);
+}
+noInline(opaqueAllTypesLog2);
+noOSRExitFuzzing(opaqueAllTypesLog2);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesLog2(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesLog2) > 2)
+        throw "We should have detected log2() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.log2() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueLog2(argument) {
+                return Math.log2(argument);
+            }
+            noInline(opaqueLog2);
+            noOSRExitFuzzing(opaqueLog2);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueLog2(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueLog2) > 1)
+                throw "We should have compiled a single log2 for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.log2() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueLog2OnConstant() {
+                return Math.log2(${testCaseInput[0]});
+            }
+            noInline(opaqueLog2OnConstant);
+            noOSRExitFuzzing(opaqueLog2OnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueLog2OnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueLog2OnConstant) > 1)
+                throw "We should have compiled a single log2 for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueLog2ForSideEffects(argument) {
+    return Math.log2(argument);
+}
+noInline(opaqueLog2ForSideEffects);
+noOSRExitFuzzing(opaqueLog2ForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let log2Result = Math.log2(0.2);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueLog2ForSideEffects(testObject) !== log2Result)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueLog2ForSideEffects) > 1)
+        throw "opaqueLog2ForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify log2() is not subject to CSE if the argument has side effects.
+function opaqueLog2ForCSE(argument) {
+    return Math.log2(argument) + Math.log2(argument) + Math.log2(argument);
+}
+noInline(opaqueLog2ForCSE);
+noOSRExitFuzzing(opaqueLog2ForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    let log2Result = Math.log2(0.2);
+    let threelog2Result = log2Result + log2Result + log2Result;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueLog2ForCSE(testObject) !== threelog2Result)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueLog2ForCSE) > 1)
+        throw "opaqueLog2ForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify log2() is not subject to DCE if the argument has side effects.
+function opaqueLog2ForDCE(argument) {
+    Math.log2(argument);
+}
+noInline(opaqueLog2ForDCE);
+noOSRExitFuzzing(opaqueLog2ForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 0.2; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueLog2ForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueLog2ForDCE) > 1)
+        throw "opaqueLog2ForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueLog2WithException(argument) {
+        let result = Math.log2(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueLog2WithException);
+
+    let testObject = { valueOf: () => {  return 0.1; } };
+    let log2Result = Math.log2(0.1);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueLog2WithException(testObject) !== log2Result)
+            throw "Incorrect result in opaqueLog2WithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 0.1; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueLog2WithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueLog2WithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/arith-sinh-on-various-types.js b/JSTests/stress/arith-sinh-on-various-types.js
new file mode 100644 (file)
index 0000000..c7e5d43
--- /dev/null
@@ -0,0 +1,235 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let sinhOfFour = Math.sinh(4);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["0", "0"],
+    ["-0.", "-0"],
+    ["4", "" + sinhOfFour],
+    ["Math.PI", "" + Math.sinh(Math.PI)],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "-Infinity"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"4\"", "" + sinhOfFour],
+    ["{ valueOf: () => { return 4; } }", "" + sinhOfFour],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.sinh() without arguments.
+function opaqueSinhNoArgument() {
+    return Math.sinh();
+}
+noInline(opaqueSinhNoArgument);
+noOSRExitFuzzing(opaqueSinhNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueSinhNoArgument();
+        if (output === output) {
+            throw "Failed opaqueSinhNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueSinhNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.sinh() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesSinh(argument) {
+    return Math.sinh(argument);
+}
+noInline(opaqueAllTypesSinh);
+noOSRExitFuzzing(opaqueAllTypesSinh);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesSinh(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesSinh) > 2)
+        throw "We should have detected sinh() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.sinh() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueSinh(argument) {
+                return Math.sinh(argument);
+            }
+            noInline(opaqueSinh);
+            noOSRExitFuzzing(opaqueSinh);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueSinh(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueSinh) > 1)
+                throw "We should have compiled a single sinh for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.sinh() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueSinhOnConstant() {
+                return Math.sinh(${testCaseInput[0]});
+            }
+            noInline(opaqueSinhOnConstant);
+            noOSRExitFuzzing(opaqueSinhOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueSinhOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueSinhOnConstant) > 1)
+                throw "We should have compiled a single sinh for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueSinhForSideEffects(argument) {
+    return Math.sinh(argument);
+}
+noInline(opaqueSinhForSideEffects);
+noOSRExitFuzzing(opaqueSinhForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let sinh16 = Math.sinh(16);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueSinhForSideEffects(testObject) !== sinh16)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueSinhForSideEffects) > 1)
+        throw "opaqueSinhForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify sinh() is not subject to CSE if the argument has side effects.
+function opaqueSinhForCSE(argument) {
+    return Math.sinh(argument) + Math.sinh(argument) + Math.sinh(argument);
+}
+noInline(opaqueSinhForCSE);
+noOSRExitFuzzing(opaqueSinhForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let sinh16 = Math.sinh(16);
+    let threeSinh16 = sinh16 + sinh16 + sinh16;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueSinhForCSE(testObject) !== threeSinh16)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueSinhForCSE) > 1)
+        throw "opaqueSinhForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify sinh() is not subject to DCE if the argument has side effects.
+function opaqueSinhForDCE(argument) {
+    Math.sinh(argument);
+}
+noInline(opaqueSinhForDCE);
+noOSRExitFuzzing(opaqueSinhForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueSinhForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueSinhForDCE) > 1)
+        throw "opaqueSinhForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueSinhWithException(argument) {
+        let result = Math.sinh(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueSinhWithException);
+
+    let testObject = { valueOf: () => {  return 64; } };
+    let sinh64 = Math.sinh(64);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueSinhWithException(testObject) !== sinh64)
+            throw "Incorrect result in opaqueSinhWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 64; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueSinhWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueSinhWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
index 2442551..4cbcdb0 100644 (file)
@@ -26,8 +26,8 @@ function isIdentical(result, expected)
     if (expected === expected) {
         if (result !== expected)
             return false;
-        if (!expected && 1 / expected === -Infinity && 1 / result !== -Infinity)
-            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
 
         return true;
     }
diff --git a/JSTests/stress/arith-tanh-on-various-types.js b/JSTests/stress/arith-tanh-on-various-types.js
new file mode 100644 (file)
index 0000000..61c9454
--- /dev/null
@@ -0,0 +1,235 @@
+//@ defaultNoEagerRun
+"use strict";
+
+let tanhOfFour = Math.tanh(4);
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["0", "0"],
+    ["-0.", "-0"],
+    ["4", "" + tanhOfFour],
+    ["Math.PI", "" + Math.tanh(Math.PI)],
+    ["Infinity", "1"],
+    ["-Infinity", "-1"],
+    ["NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"4\"", "" + tanhOfFour],
+    ["{ valueOf: () => { return 4; } }", "" + tanhOfFour],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected)
+            return (1 / expected) === (1 / result);
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.tanh() without arguments.
+function opaqueTanhNoArgument() {
+    return Math.tanh();
+}
+noInline(opaqueTanhNoArgument);
+noOSRExitFuzzing(opaqueTanhNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueTanhNoArgument();
+        if (output === output) {
+            throw "Failed opaqueTanhNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueTanhNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.tanh() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesTanh(argument) {
+    return Math.tanh(argument);
+}
+noInline(opaqueAllTypesTanh);
+noOSRExitFuzzing(opaqueAllTypesTanh);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesTanh(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesTanh) > 2)
+        throw "We should have detected tanh() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.tanh() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueTanh(argument) {
+                return Math.tanh(argument);
+            }
+            noInline(opaqueTanh);
+            noOSRExitFuzzing(opaqueTanh);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueTanh(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueTanh) > 1)
+                throw "We should have compiled a single tanh for the expected type.";
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.tanh() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueTanhOnConstant() {
+                return Math.tanh(${testCaseInput[0]});
+            }
+            noInline(opaqueTanhOnConstant);
+            noOSRExitFuzzing(opaqueTanhOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueTanhOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueTanhOnConstant) > 1)
+                throw "We should have compiled a single tanh for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueTanhForSideEffects(argument) {
+    return Math.tanh(argument);
+}
+noInline(opaqueTanhForSideEffects);
+noOSRExitFuzzing(opaqueTanhForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let tanh16 = Math.tanh(16);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueTanhForSideEffects(testObject) !== tanh16)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueTanhForSideEffects) > 1)
+        throw "opaqueTanhForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify tanh() is not subject to CSE if the argument has side effects.
+function opaqueTanhForCSE(argument) {
+    return Math.tanh(argument) + Math.tanh(argument) + Math.tanh(argument);
+}
+noInline(opaqueTanhForCSE);
+noOSRExitFuzzing(opaqueTanhForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let tanh16 = Math.tanh(16);
+    let threeTanh16 = tanh16 + tanh16 + tanh16;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueTanhForCSE(testObject) !== threeTanh16)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueTanhForCSE) > 1)
+        throw "opaqueTanhForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify tanh() is not subject to DCE if the argument has side effects.
+function opaqueTanhForDCE(argument) {
+    Math.tanh(argument);
+}
+noInline(opaqueTanhForDCE);
+noOSRExitFuzzing(opaqueTanhForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueTanhForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueTanhForDCE) > 1)
+        throw "opaqueTanhForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueTanhWithException(argument) {
+        let result = Math.tanh(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueTanhWithException);
+
+    let testObject = { valueOf: () => {  return 64; } };
+    let tanh64 = Math.tanh(64);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueTanhWithException(testObject) !== tanh64)
+            throw "Incorrect result in opaqueTanhWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 64; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueTanhWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueTanhWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();
diff --git a/JSTests/stress/math-unary-no-arg.js b/JSTests/stress/math-unary-no-arg.js
new file mode 100644 (file)
index 0000000..f4f491f
--- /dev/null
@@ -0,0 +1,38 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+let functions = [
+    'sin',
+    'sinh',
+    'cos',
+    'cosh',
+    'tan',
+    'tanh',
+    'asin',
+    'asinh',
+    'acos',
+    'acosh',
+    'atan',
+    'atanh',
+    'log',
+    'log10',
+    'log1p',
+    'log2',
+    'cbrt',
+    'exp',
+    'expm1'
+];
+
+let repository = {};
+for (let func of functions) {
+    let wrap = new Function(`return Math.${func}()`);
+    noInline(wrap);
+    repository[func] = wrap;
+}
+
+for (let i = 0; i < 1e4; ++i) {
+    for (let func of functions)
+        shouldBe(Number.isNaN(repository[func]()), true);
+}
index 44610e9..0c3213b 100644 (file)
@@ -1,3 +1,108 @@
+2017-05-04  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] Math unary functions should be handled by DFG
+        https://bugs.webkit.org/show_bug.cgi?id=171269
+
+        Reviewed by Saam Barati.
+
+        ArithSin, ArithCos, and ArithLog are just calling a C runtime function.
+        While handling them in DFG is not very effective for performance, they
+        can drop some type checks & value conversions and mark them as pure
+        operations. It is effective if they are involved in some complex
+        optimization phase. Actually, ArithLog is effective in kraken.
+
+        While a few of Math functions have DFG nodes, basically math functions
+        are pure. And large part of these functions are just calling a C runtime
+        function. This patch generalizes these nodes in DFG as ArithUnary. And
+        we annotate many unary math functions with Intrinsics and convert them
+        to ArithUnary in DFG. It also cleans up duplicate code in ArithSin,
+        ArithCos, and ArithLog. If your math function has some good DFG / FTL
+        optimization rather than calling a C runtime function, you should add
+        a specialized DFG node, like ArithSqrt.
+
+        We also create a new namespace JSC::Math. Inside it, we collect math functions.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGArithMode.cpp:
+        (JSC::DFG::arithUnaryFunction):
+        (JSC::DFG::arithUnaryOperation):
+        (WTF::printInternal):
+        * dfg/DFGArithMode.h:
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasArithUnaryType):
+        (JSC::DFG::Node::arithUnaryType):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithUnary):
+        (JSC::DFG::SpeculativeJIT::compileArithCos): Deleted.
+        (JSC::DFG::SpeculativeJIT::compileArithTan): Deleted.
+        (JSC::DFG::SpeculativeJIT::compileArithSin): Deleted.
+        (JSC::DFG::SpeculativeJIT::compileArithLog): Deleted.
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithUnary):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithSin): Deleted.
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithCos): Deleted.
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithTan): Deleted.
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithLog): Deleted.
+        * ftl/FTLOutput.cpp:
+        (JSC::FTL::Output::doubleUnary):
+        (JSC::FTL::Output::doubleSin): Deleted.
+        (JSC::FTL::Output::doubleCos): Deleted.
+        (JSC::FTL::Output::doubleTan): Deleted.
+        (JSC::FTL::Output::doubleLog): Deleted.
+        * ftl/FTLOutput.h:
+        * runtime/Intrinsic.h:
+        * runtime/MathCommon.cpp:
+        (JSC::Math::log1p):
+        * runtime/MathCommon.h:
+        * runtime/MathObject.cpp:
+        (JSC::MathObject::finishCreation):
+        (JSC::mathProtoFuncACos):
+        (JSC::mathProtoFuncASin):
+        (JSC::mathProtoFuncATan):
+        (JSC::mathProtoFuncCos):
+        (JSC::mathProtoFuncExp):
+        (JSC::mathProtoFuncLog):
+        (JSC::mathProtoFuncSin):
+        (JSC::mathProtoFuncTan):
+        (JSC::mathProtoFuncACosh):
+        (JSC::mathProtoFuncASinh):
+        (JSC::mathProtoFuncATanh):
+        (JSC::mathProtoFuncCbrt):
+        (JSC::mathProtoFuncCosh):
+        (JSC::mathProtoFuncExpm1):
+        (JSC::mathProtoFuncLog1p):
+        (JSC::mathProtoFuncLog10):
+        (JSC::mathProtoFuncLog2):
+        (JSC::mathProtoFuncSinh):
+        (JSC::mathProtoFuncTanh):
+
 2017-05-03  Saam Barati  <sbarati@apple.com>
 
         How we build polymorphic cases is wrong when making a call from Wasm
index 8d71a83..35d44b4 100644 (file)
@@ -969,20 +969,8 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         executeDoubleUnaryOpEffects(node, [](double value) -> double { return static_cast<float>(value); });
         break;
         
-    case ArithSin:
-        executeDoubleUnaryOpEffects(node, sin);
-        break;
-    
-    case ArithCos:
-        executeDoubleUnaryOpEffects(node, cos);
-        break;
-
-    case ArithTan:
-        executeDoubleUnaryOpEffects(node, tan);
-        break;
-
-    case ArithLog:
-        executeDoubleUnaryOpEffects(node, log);
+    case ArithUnary:
+        executeDoubleUnaryOpEffects(node, arithUnaryFunction(node->arithUnaryType()));
         break;
             
     case LogicalNot: {
index 84ddae1..960c317 100644 (file)
 
 #if ENABLE(DFG_JIT)
 
+#include "DFGOperations.h"
 #include "JSCInlines.h"
 #include <wtf/PrintStream.h>
 
+namespace JSC { namespace DFG {
+
+Arith::UnaryFunction arithUnaryFunction(Arith::UnaryType type)
+{
+    switch (type) {
+#define DFG_ARITH_UNARY(capitalizedName, lowerName) \
+    case Arith::UnaryType::capitalizedName: \
+        return static_cast<Arith::UnaryFunction>(JSC::Math::lowerName);
+    FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
+#undef DFG_ARITH_UNARY
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+
+}
+
+Arith::UnaryOperation arithUnaryOperation(Arith::UnaryType type)
+{
+    switch (type) {
+#define DFG_ARITH_UNARY(capitalizedName, lowerName) \
+    case Arith::UnaryType::capitalizedName: \
+        return static_cast<Arith::UnaryOperation>(operationArith##capitalizedName);
+    FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
+#undef DFG_ARITH_UNARY
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} } // namespace JSC::DFG
+
 namespace WTF {
 
 void printInternal(PrintStream& out, JSC::DFG::Arith::Mode mode)
@@ -71,6 +101,20 @@ void printInternal(PrintStream& out, JSC::DFG::Arith::RoundingMode mode)
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+void printInternal(PrintStream& out, JSC::DFG::Arith::UnaryType type)
+{
+    switch (type) {
+#define DFG_ARITH_UNARY(capitalizedName, lowerName) \
+    case JSC::DFG::Arith::UnaryType::capitalizedName: \
+        out.print(#capitalizedName); \
+        return;
+    FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
+#undef DFG_ARITH_UNARY
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+
 } // namespace WTF
 
 #endif // ENABLE(DFG_JIT)
index 24a7952..0a64448 100644 (file)
 
 #if ENABLE(DFG_JIT)
 
-namespace JSC { namespace DFG {
+namespace JSC {
+
+class ExecState;
+using EncodedJSValue = int64_t;
+
+namespace DFG {
 
 // Arith::Mode describes the mode of an arithmetic operation that speculates integer.
 // Note that not all modes are valid for all operations.
@@ -47,6 +52,38 @@ enum class RoundingMode {
     Double // The round operation produce a double. The result can be -0, NaN or (+/-)Infinity.
 };
 
+
+// This macro defines a set of information about all known arith unary generic node.
+#define FOR_EACH_DFG_ARITH_UNARY_OP(macro) \
+    macro(Sin, sin) \
+    macro(Sinh, sinh) \
+    macro(Cos, cos) \
+    macro(Cosh, cosh) \
+    macro(Tan, tan) \
+    macro(Tanh, tanh) \
+    macro(ASin, asin) \
+    macro(ASinh, asinh) \
+    macro(ACos, acos) \
+    macro(ACosh, acosh) \
+    macro(ATan, atan) \
+    macro(ATanh, atanh) \
+    macro(Log, log) \
+    macro(Log10, log10) \
+    macro(Log1p, log1p) \
+    macro(Log2, log2) \
+    macro(Cbrt, cbrt) \
+    macro(Exp, exp) \
+    macro(Expm1, expm1) \
+
+enum class UnaryType : uint32_t {
+#define DFG_ARITH_UNARY_ENUM(capitalizedName, lowerName) capitalizedName,
+    FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY_ENUM)
+#undef DFG_ARITH_UNARY_ENUM
+};
+
+typedef double (*UnaryFunction)(double);
+typedef double (*UnaryOperation)(ExecState*, EncodedJSValue);
+
 } // namespace Arith
 
 inline bool doesOverflow(Arith::Mode mode)
@@ -139,6 +176,9 @@ inline bool shouldCheckNegativeZero(Arith::RoundingMode mode)
     return mode == Arith::RoundingMode::Int32WithNegativeZeroCheck;
 }
 
+Arith::UnaryFunction arithUnaryFunction(Arith::UnaryType);
+Arith::UnaryOperation arithUnaryOperation(Arith::UnaryType);
+
 } } // namespace JSC::DFG
 
 namespace WTF {
@@ -146,6 +186,7 @@ namespace WTF {
 class PrintStream;
 void printInternal(PrintStream&, JSC::DFG::Arith::Mode);
 void printInternal(PrintStream&, JSC::DFG::Arith::RoundingMode);
+void printInternal(PrintStream&, JSC::DFG::Arith::UnaryType);
 
 } // namespace WTF
 
index 8c10303..5f98907 100644 (file)
@@ -411,7 +411,7 @@ private:
             RELEASE_ASSERT_NOT_REACHED();
             break;
             
-        // Note: ArithSqrt, ArithSin, and ArithCos and other math intrinsics don't have special
+        // Note: ArithSqrt, ArithUnary and other math intrinsics don't have special
         // rules in here because they are always followed by Phantoms to signify that if the
         // method call speculation fails, the bytecode may use the arguments in arbitrary ways.
         // This corresponds to that possibility of someone doing something like:
index 224ab14..bcb3212 100644 (file)
@@ -2174,12 +2174,34 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin
     case MaxIntrinsic:
         return handleMinMax(resultOperand, ArithMax, registerOffset, argumentCountIncludingThis, insertChecks);
 
-    case CosIntrinsic:
+#define DFG_ARITH_UNARY(capitalizedName, lowerName) \
+    case capitalizedName##Intrinsic:
+    FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
+#undef DFG_ARITH_UNARY
+    {
+        if (argumentCountIncludingThis == 1) {
+            insertChecks();
+            set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN)));
+            return true;
+        }
+        Arith::UnaryType type = Arith::UnaryType::Sin;
+        switch (intrinsic) {
+#define DFG_ARITH_UNARY(capitalizedName, lowerName) \
+        case capitalizedName##Intrinsic: \
+            type = Arith::UnaryType::capitalizedName; \
+            break;
+    FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
+#undef DFG_ARITH_UNARY
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        insertChecks();
+        set(VirtualRegister(resultOperand), addToGraph(ArithUnary, OpInfo(static_cast<std::underlying_type<Arith::UnaryType>::type>(type)), get(virtualRegisterForArgument(1, registerOffset))));
+        return true;
+    }
+
     case FRoundIntrinsic:
-    case LogIntrinsic:
-    case SinIntrinsic:
-    case SqrtIntrinsic:
-    case TanIntrinsic: {
+    case SqrtIntrinsic: {
         if (argumentCountIncludingThis == 1) {
             insertChecks();
             set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN)));
@@ -2188,24 +2210,12 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin
 
         NodeType nodeType = Unreachable;
         switch (intrinsic) {
-        case CosIntrinsic:
-            nodeType = ArithCos;
-            break;
         case FRoundIntrinsic:
             nodeType = ArithFRound;
             break;
-        case LogIntrinsic:
-            nodeType = ArithLog;
-            break;
-        case SinIntrinsic:
-            nodeType = ArithSin;
-            break;
         case SqrtIntrinsic:
             nodeType = ArithSqrt;
             break;
-        case TanIntrinsic:
-            nodeType = ArithTan;
-            break;
         default:
             RELEASE_ASSERT_NOT_REACHED();
         }
index 2af9564..d8ce907 100644 (file)
@@ -190,12 +190,17 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         }
         return;
         
-    case ArithCos:
+    case ArithUnary:
+        if (node->child1().useKind() == DoubleRepUse)
+            def(PureValue(node, static_cast<std::underlying_type<Arith::UnaryType>::type>(node->arithUnaryType())));
+        else {
+            read(World);
+            write(Heap);
+        }
+        return;
+
     case ArithFRound:
-    case ArithLog:
-    case ArithSin:
     case ArithSqrt:
-    case ArithTan:
         if (node->child1().useKind() == DoubleRepUse)
             def(PureValue(node));
         else {
index 92faabb..f2ee0a3 100644 (file)
@@ -92,10 +92,7 @@ bool doesGC(Graph& graph, Node* node)
     case ArithCeil:
     case ArithTrunc:
     case ArithFRound:
-    case ArithSin:
-    case ArithCos:
-    case ArithTan:
-    case ArithLog:
+    case ArithUnary:
     case ValueAdd:
     case TryGetById:
     case GetById:
index 9008385..60789d5 100644 (file)
@@ -427,12 +427,9 @@ private:
             break;
         }
 
-        case ArithCos:
         case ArithFRound:
-        case ArithLog:
-        case ArithSin:
         case ArithSqrt:
-        case ArithTan: {
+        case ArithUnary: {
             Edge& child1 = node->child1();
             if (child1->shouldSpeculateNotCell()) {
                 fixDoubleOrBooleanEdge(child1);
index 05e9c1c..4297cb1 100644 (file)
@@ -232,6 +232,8 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
         out.print(comma, SpeculationDump(node->prediction()));
     if (node->hasArrayMode())
         out.print(comma, node->arrayMode());
+    if (node->hasArithUnaryType())
+        out.print(comma, "Type:", node->arithUnaryType());
     if (node->hasArithMode())
         out.print(comma, node->arithMode());
     if (node->hasArithRoundingMode())
index 7e5ebe2..194d7d5 100644 (file)
@@ -1892,6 +1892,17 @@ public:
         ASSERT(hasArithRoundingMode());
         m_opInfo = static_cast<uint32_t>(mode);
     }
+
+    bool hasArithUnaryType()
+    {
+        return op() == ArithUnary;
+    }
+
+    Arith::UnaryType arithUnaryType()
+    {
+        ASSERT(hasArithUnaryType());
+        return static_cast<Arith::UnaryType>(m_opInfo.as<uint32_t>());
+    }
     
     bool hasVirtualRegister()
     {
index 053243b..3b79ae0 100644 (file)
@@ -159,10 +159,7 @@ namespace JSC { namespace DFG {
     macro(ArithCeil, NodeResultNumber | NodeMustGenerate) \
     macro(ArithTrunc, NodeResultNumber | NodeMustGenerate) \
     macro(ArithSqrt, NodeResultDouble | NodeMustGenerate) \
-    macro(ArithSin, NodeResultDouble | NodeMustGenerate) \
-    macro(ArithCos, NodeResultDouble | NodeMustGenerate) \
-    macro(ArithTan, NodeResultDouble | NodeMustGenerate) \
-    macro(ArithLog, NodeResultDouble | NodeMustGenerate) \
+    macro(ArithUnary, NodeResultDouble | NodeMustGenerate) \
     \
     /* Add of values may either be arithmetic, or result in string concatenation. */\
     macro(ValueAdd, NodeResultJS | NodeMustGenerate) \
index 22839ec..139ab1b 100644 (file)
@@ -384,18 +384,6 @@ int32_t JIT_OPERATION operationArithClz32(ExecState* exec, EncodedJSValue encode
     return clz32(value);
 }
 
-double JIT_OPERATION operationArithCos(ExecState* exec, EncodedJSValue encodedOp1)
-{
-    VM* vm = &exec->vm();
-    NativeCallFrameTracer tracer(vm, exec);
-    auto scope = DECLARE_THROW_SCOPE(*vm);
-
-    JSValue op1 = JSValue::decode(encodedOp1);
-    double a = op1.toNumber(exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    return cos(a);
-}
-
 double JIT_OPERATION operationArithFRound(ExecState* exec, EncodedJSValue encodedOp1)
 {
     VM* vm = &exec->vm();
@@ -408,29 +396,19 @@ double JIT_OPERATION operationArithFRound(ExecState* exec, EncodedJSValue encode
     return static_cast<float>(a);
 }
 
-double JIT_OPERATION operationArithLog(ExecState* exec, EncodedJSValue encodedOp1)
-{
-    VM* vm = &exec->vm();
-    NativeCallFrameTracer tracer(vm, exec);
-    auto scope = DECLARE_THROW_SCOPE(*vm);
-
-    JSValue op1 = JSValue::decode(encodedOp1);
-    double a = op1.toNumber(exec);
-    RETURN_IF_EXCEPTION(scope, PNaN);
-    return log(a);
-}
-
-double JIT_OPERATION operationArithSin(ExecState* exec, EncodedJSValue encodedOp1)
-{
-    VM* vm = &exec->vm();
-    NativeCallFrameTracer tracer(vm, exec);
-    auto scope = DECLARE_THROW_SCOPE(*vm);
-
-    JSValue op1 = JSValue::decode(encodedOp1);
-    double a = op1.toNumber(exec);
-    RETURN_IF_EXCEPTION(scope, PNaN);
-    return sin(a);
+#define DFG_ARITH_UNARY(capitalizedName, lowerName) \
+double JIT_OPERATION operationArith##capitalizedName(ExecState* exec, EncodedJSValue encodedOp1) \
+{ \
+    VM* vm = &exec->vm(); \
+    NativeCallFrameTracer tracer(vm, exec); \
+    auto scope = DECLARE_THROW_SCOPE(*vm); \
+    JSValue op1 = JSValue::decode(encodedOp1); \
+    double result = op1.toNumber(exec); \
+    RETURN_IF_EXCEPTION(scope, PNaN); \
+    return JSC::Math::lowerName(result); \
 }
+    FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
+#undef DFG_ARITH_UNARY
 
 double JIT_OPERATION operationArithSqrt(ExecState* exec, EncodedJSValue encodedOp1)
 {
@@ -444,18 +422,6 @@ double JIT_OPERATION operationArithSqrt(ExecState* exec, EncodedJSValue encodedO
     return sqrt(a);
 }
 
-double JIT_OPERATION operationArithTan(ExecState* exec, EncodedJSValue encodedOp1)
-{
-    VM* vm = &exec->vm();
-    NativeCallFrameTracer tracer(vm, exec);
-    auto scope = DECLARE_THROW_SCOPE(*vm);
-
-    JSValue op1 = JSValue::decode(encodedOp1);
-    double a = op1.toNumber(exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    return tan(a);
-}
-
 EncodedJSValue JIT_OPERATION operationArithRound(ExecState* exec, EncodedJSValue encodedArgument)
 {
     VM* vm = &exec->vm();
index ae1b062..bfb2d59 100644 (file)
@@ -27,6 +27,7 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "DFGArithMode.h"
 #include "JITOperations.h"
 #include "PutKind.h"
 
@@ -54,12 +55,14 @@ EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSVal
 EncodedJSValue JIT_OPERATION operationValueDiv(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 double JIT_OPERATION operationArithAbs(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 int32_t JIT_OPERATION operationArithClz32(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
-double JIT_OPERATION operationArithCos(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
-double JIT_OPERATION operationArithTan(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 double JIT_OPERATION operationArithFRound(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
-double JIT_OPERATION operationArithLog(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
-double JIT_OPERATION operationArithSin(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 double JIT_OPERATION operationArithSqrt(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
+
+#define DFG_ARITH_UNARY(capitalizedName, lowerName) \
+double JIT_OPERATION operationArith##capitalizedName(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
+    FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
+#undef DFG_ARITH_UNARY
+
 EncodedJSValue JIT_OPERATION operationArithRound(ExecState*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArithFloor(ExecState*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArithCeil(ExecState*, EncodedJSValue) WTF_INTERNAL;
index b623ac5..884589e 100644 (file)
@@ -567,10 +567,7 @@ private:
             break;
                 
         case ArithSqrt:
-        case ArithCos:
-        case ArithSin:
-        case ArithTan:
-        case ArithLog:
+        case ArithUnary:
             if (node->child1()->shouldSpeculateNumber())
                 m_graph.voteNode(node->child1(), VoteDouble, weight);
             else
@@ -788,10 +785,7 @@ private:
         case ArithPow:
         case ArithSqrt:
         case ArithFRound:
-        case ArithSin:
-        case ArithCos:
-        case ArithTan:
-        case ArithLog: {
+        case ArithUnary: {
             setPrediction(SpecBytecodeDouble);
             break;
         }
index 1ea9c0b..ad3ff28 100644 (file)
@@ -191,10 +191,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case ArithFloor:
     case ArithCeil:
     case ArithTrunc:
-    case ArithSin:
-    case ArithCos:
-    case ArithTan:
-    case ArithLog:
+    case ArithUnary:
     case ValueAdd:
     case TryGetById:
     case DeleteById:
index 4700994..dc9a0f6 100644 (file)
@@ -4151,16 +4151,6 @@ void SpeculativeJIT::compileArithDoubleUnaryOp(Node* node, double (*doubleFuncti
     doubleResult(result.fpr(), node);
 }
 
-void SpeculativeJIT::compileArithCos(Node* node)
-{
-    compileArithDoubleUnaryOp(node, cos, operationArithCos);
-}
-
-void SpeculativeJIT::compileArithTan(Node* node)
-{
-    compileArithDoubleUnaryOp(node, tan, operationArithTan);
-}
-
 void SpeculativeJIT::compileArithSub(Node* node)
 {
     switch (node->binaryUseKind()) {
@@ -5313,9 +5303,9 @@ void SpeculativeJIT::compileArithRounding(Node* node)
     jsValueResult(resultRegs, node);
 }
 
-void SpeculativeJIT::compileArithSin(Node* node)
+void SpeculativeJIT::compileArithUnary(Node* node)
 {
-    compileArithDoubleUnaryOp(node, sin, operationArithSin);
+    compileArithDoubleUnaryOp(node, arithUnaryFunction(node->arithUnaryType()), arithUnaryOperation(node->arithUnaryType()));
 }
 
 void SpeculativeJIT::compileArithSqrt(Node* node)
@@ -5494,11 +5484,6 @@ void SpeculativeJIT::compileArithPow(Node* node)
     doubleResult(resultFpr, node);
 }
 
-void SpeculativeJIT::compileArithLog(Node* node)
-{
-    compileArithDoubleUnaryOp(node, log, operationArithLog);
-}
-
 // 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)
 {
index 87b0173..e9d9732 100644 (file)
@@ -2818,8 +2818,6 @@ public:
     void compileMakeRope(Node*);
     void compileArithAbs(Node*);
     void compileArithClz32(Node*);
-    void compileArithCos(Node*);
-    void compileArithTan(Node*);
     void compileArithSub(Node*);
     void compileArithNegate(Node*);
     void compileArithMul(Node*);
@@ -2829,9 +2827,8 @@ public:
     void compileArithPow(Node*);
     void compileArithRounding(Node*);
     void compileArithRandom(Node*);
-    void compileArithSin(Node*);
+    void compileArithUnary(Node*);
     void compileArithSqrt(Node*);
-    void compileArithLog(Node*);
     void compileConstantStoragePointer(Node*);
     void compileGetIndexedPropertyStorage(Node*);
     JITCompiler::Jump jumpForTypedArrayOutOfBounds(Node*, GPRReg baseGPR, GPRReg indexGPR);
index c327d66..cac6134 100644 (file)
@@ -2479,20 +2479,8 @@ void SpeculativeJIT::compile(Node* node)
         compileArithRounding(node);
         break;
 
-    case ArithSin:
-        compileArithSin(node);
-        break;
-
-    case ArithCos:
-        compileArithCos(node);
-        break;
-
-    case ArithTan:
-        compileArithTan(node);
-        break;
-
-    case ArithLog:
-        compileArithLog(node);
+    case ArithUnary:
+        compileArithUnary(node);
         break;
 
     case LogicalNot:
index ff2acc4..d794c34 100644 (file)
@@ -2627,20 +2627,8 @@ void SpeculativeJIT::compile(Node* node)
         compileArithRounding(node);
         break;
 
-    case ArithSin:
-        compileArithSin(node);
-        break;
-
-    case ArithCos:
-        compileArithCos(node);
-        break;
-
-    case ArithTan:
-        compileArithTan(node);
-        break;
-
-    case ArithLog:
-        compileArithLog(node);
+    case ArithUnary:
+        compileArithUnary(node);
         break;
 
     case LogicalNot:
index 80c8bea..9d115d4 100644 (file)
@@ -94,9 +94,6 @@ inline CapabilityLevel canCompile(Node* node)
     case ArithMin:
     case ArithMax:
     case ArithAbs:
-    case ArithSin:
-    case ArithCos:
-    case ArithTan:
     case ArithPow:
     case ArithRandom:
     case ArithRound:
@@ -104,9 +101,9 @@ inline CapabilityLevel canCompile(Node* node)
     case ArithCeil:
     case ArithTrunc:
     case ArithSqrt:
-    case ArithLog:
     case ArithFRound:
     case ArithNegate:
+    case ArithUnary:
     case UInt32ToNumber:
     case Jump:
     case ForceOSRExit:
index b4c6724..b00879a 100644 (file)
@@ -545,15 +545,6 @@ private:
         case ArithAbs:
             compileArithAbs();
             break;
-        case ArithSin:
-            compileArithSin();
-            break;
-        case ArithCos:
-            compileArithCos();
-            break;
-        case ArithTan:
-            compileArithTan();
-            break;
         case ArithPow:
             compileArithPow();
             break;
@@ -575,15 +566,15 @@ private:
         case ArithSqrt:
             compileArithSqrt();
             break;
-        case ArithLog:
-            compileArithLog();
-            break;
         case ArithFRound:
             compileArithFRound();
             break;
         case ArithNegate:
             compileArithNegate();
             break;
+        case ArithUnary:
+            compileArithUnary();
+            break;
         case DFG::BitAnd:
             compileBitAnd();
             break;
@@ -2210,36 +2201,14 @@ private:
         }
     }
 
-    void compileArithSin()
+    void compileArithUnary()
     {
         if (m_node->child1().useKind() == DoubleRepUse) {
-            setDouble(m_out.doubleSin(lowDouble(m_node->child1())));
+            setDouble(m_out.doubleUnary(m_node->arithUnaryType(), lowDouble(m_node->child1())));
             return;
         }
         LValue argument = lowJSValue(m_node->child1());
-        LValue result = vmCall(Double, m_out.operation(operationArithSin), m_callFrame, argument);
-        setDouble(result);
-    }
-
-    void compileArithCos()
-    {
-        if (m_node->child1().useKind() == DoubleRepUse) {
-            setDouble(m_out.doubleCos(lowDouble(m_node->child1())));
-            return;
-        }
-        LValue argument = lowJSValue(m_node->child1());
-        LValue result = vmCall(Double, m_out.operation(operationArithCos), m_callFrame, argument);
-        setDouble(result);
-    }
-
-    void compileArithTan()
-    {
-        if (m_node->child1().useKind() == DoubleRepUse) {
-            setDouble(m_out.doubleTan(lowDouble(m_node->child1())));
-            return;
-        }
-        LValue argument = lowJSValue(m_node->child1());
-        LValue result = vmCall(Double, m_out.operation(operationArithTan), m_callFrame, argument);
+        LValue result = vmCall(Double, m_out.operation(DFG::arithUnaryOperation(m_node->arithUnaryType())), m_callFrame, argument);
         setDouble(result);
     }
 
@@ -2527,17 +2496,6 @@ private:
         setDouble(result);
     }
 
-    void compileArithLog()
-    {
-        if (m_node->child1().useKind() == DoubleRepUse) {
-            setDouble(m_out.doubleLog(lowDouble(m_node->child1())));
-            return;
-        }
-        LValue argument = lowJSValue(m_node->child1());
-        LValue result = vmCall(Double, m_out.operation(operationArithLog), m_callFrame, argument);
-        setDouble(result);
-    }
-    
     void compileArithFRound()
     {
         if (m_node->child1().useKind() == DoubleRepUse) {
index dff75a4..816e30e 100644 (file)
@@ -289,22 +289,10 @@ LValue Output::doubleTrunc(LValue value)
     return callWithoutSideEffects(Double, truncDouble, value);
 }
 
-LValue Output::doubleSin(LValue value)
+LValue Output::doubleUnary(DFG::Arith::UnaryType type, LValue value)
 {
-    double (*sinDouble)(double) = sin;
-    return callWithoutSideEffects(B3::Double, sinDouble, value);
-}
-
-LValue Output::doubleCos(LValue value)
-{
-    double (*cosDouble)(double) = cos;
-    return callWithoutSideEffects(B3::Double, cosDouble, value);
-}
-
-LValue Output::doubleTan(LValue value)
-{
-    double (*tanDouble)(double) = tan;
-    return callWithoutSideEffects(B3::Double, tanDouble, value);
+    double (*unaryFunction)(double) = DFG::arithUnaryFunction(type);
+    return callWithoutSideEffects(B3::Double, unaryFunction, value);
 }
 
 LValue Output::doublePow(LValue xOperand, LValue yOperand)
@@ -328,12 +316,6 @@ LValue Output::doubleSqrt(LValue value)
     return m_block->appendNew<B3::Value>(m_proc, B3::Sqrt, origin(), value);
 }
 
-LValue Output::doubleLog(LValue value)
-{
-    double (*logDouble)(double) = log;
-    return callWithoutSideEffects(B3::Double, logDouble, value);
-}
-
 LValue Output::doubleToInt(LValue value)
 {
     PatchpointValue* result = patchpoint(Int32);
index ccd7cbd..fe22d6d 100644 (file)
@@ -183,9 +183,7 @@ public:
     LValue doubleFloor(LValue);
     LValue doubleTrunc(LValue);
 
-    LValue doubleSin(LValue);
-    LValue doubleCos(LValue);
-    LValue doubleTan(LValue);
+    LValue doubleUnary(DFG::Arith::UnaryType, LValue);
 
     LValue doublePow(LValue base, LValue exponent);
     LValue doublePowi(LValue base, LValue exponent);
index 7713a9e..d19e188 100644 (file)
@@ -31,13 +31,23 @@ enum JS_EXPORT_PRIVATE Intrinsic {
     // Call intrinsics.
     NoIntrinsic,
     AbsIntrinsic,
+    ACosIntrinsic,
+    ASinIntrinsic,
+    ATanIntrinsic,
+    ACoshIntrinsic,
+    ASinhIntrinsic,
+    ATanhIntrinsic,
     MinIntrinsic,
     MaxIntrinsic,
     SqrtIntrinsic,
     SinIntrinsic,
+    CbrtIntrinsic,
     Clz32Intrinsic,
     CosIntrinsic,
     TanIntrinsic,
+    CoshIntrinsic,
+    SinhIntrinsic,
+    TanhIntrinsic,
     ArrayPushIntrinsic,
     ArrayPopIntrinsic,
     ArraySliceIntrinsic,
@@ -49,7 +59,11 @@ enum JS_EXPORT_PRIVATE Intrinsic {
     CeilIntrinsic,
     RoundIntrinsic,
     ExpIntrinsic,
+    Expm1Intrinsic,
     LogIntrinsic,
+    Log10Intrinsic,
+    Log1pIntrinsic,
+    Log2Intrinsic,
     RegExpExecIntrinsic,
     RegExpTestIntrinsic,
     RegExpTestFastIntrinsic,
index 4e659e8..c107ed1 100644 (file)
@@ -521,4 +521,14 @@ double jsMod(double x, double y)
 #endif
 } // extern "C"
 
+namespace Math {
+
+double JIT_OPERATION log1p(double value)
+{
+    if (value == 0.0)
+        return value;
+    return std::log1p(value);
+}
+
+} // namespace Math
 } // namespace JSC
index d776b9d..e8f316c 100644 (file)
@@ -209,4 +209,28 @@ double JIT_OPERATION jsMod(double x, double y) REFERENCED_FROM_ASM WTF_INTERNAL;
 #endif
 }
 
+namespace Math {
+
+using std::sin;
+using std::sinh;
+using std::cos;
+using std::cosh;
+using std::tan;
+using std::tanh;
+using std::asin;
+using std::asinh;
+using std::acos;
+using std::acosh;
+using std::atan;
+using std::atanh;
+using std::log;
+using std::log10;
+using std::log2;
+using std::cbrt;
+using std::exp;
+using std::expm1;
+
+double JIT_OPERATION log1p(double) WTF_INTERNAL;
+
+} // namespace Math
 } // namespace JSC
index fb1ed0e..e432dc1 100644 (file)
@@ -78,10 +78,10 @@ void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
     Base::finishCreation(vm);
     ASSERT(inherits(vm, info()));
 
-    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly);
-    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly);
-    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly);
-    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly);
+    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "E"), jsNumber(Math::exp(1.0)), DontDelete | DontEnum | ReadOnly);
+    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LN2"), jsNumber(Math::log(2.0)), DontDelete | DontEnum | ReadOnly);
+    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LN10"), jsNumber(Math::log(10.0)), DontDelete | DontEnum | ReadOnly);
+    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LOG2E"), jsNumber(1.0 / Math::log(2.0)), DontDelete | DontEnum | ReadOnly);
     putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly);
     putDirectWithoutTransition(vm, Identifier::fromString(&vm, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly);
     putDirectWithoutTransition(vm, Identifier::fromString(&vm, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly);
@@ -89,27 +89,27 @@ void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
     putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Math"), DontEnum | ReadOnly);
 
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "abs"), 1, mathProtoFuncAbs, AbsIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acos"), 1, mathProtoFuncACos, NoIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "asin"), 1, mathProtoFuncASin, NoIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atan"), 1, mathProtoFuncATan, NoIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acosh"), 1, mathProtoFuncACosh, NoIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "asinh"), 1, mathProtoFuncASinh, NoIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atanh"), 1, mathProtoFuncATanh, NoIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acos"), 1, mathProtoFuncACos, ACosIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "asin"), 1, mathProtoFuncASin, ASinIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atan"), 1, mathProtoFuncATan, ATanIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acosh"), 1, mathProtoFuncACosh, ACoshIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "asinh"), 1, mathProtoFuncASinh, ASinhIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atanh"), 1, mathProtoFuncATanh, ATanhIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atan2"), 2, mathProtoFuncATan2, NoIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cbrt"), 1, mathProtoFuncCbrt, NoIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cbrt"), 1, mathProtoFuncCbrt, CbrtIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "ceil"), 1, mathProtoFuncCeil, CeilIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "clz32"), 1, mathProtoFuncClz32, Clz32Intrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cos"), 1, mathProtoFuncCos, CosIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cosh"), 1, mathProtoFuncCosh, NoIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cosh"), 1, mathProtoFuncCosh, CoshIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "exp"), 1, mathProtoFuncExp, ExpIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "expm1"), 1, mathProtoFuncExpm1, NoIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "expm1"), 1, mathProtoFuncExpm1, Expm1Intrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "floor"), 1, mathProtoFuncFloor, FloorIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "fround"), 1, mathProtoFuncFround, FRoundIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "hypot"), 2, mathProtoFuncHypot, NoIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log"), 1, mathProtoFuncLog, LogIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log10"), 1, mathProtoFuncLog10, NoIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log1p"), 1, mathProtoFuncLog1p, NoIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log2"), 1, mathProtoFuncLog2, NoIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log10"), 1, mathProtoFuncLog10, Log10Intrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log1p"), 1, mathProtoFuncLog1p, Log1pIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log2"), 1, mathProtoFuncLog2, Log2Intrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "max"), 2, mathProtoFuncMax, MaxIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "min"), 2, mathProtoFuncMin, MinIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "pow"), 2, mathProtoFuncPow, PowIntrinsic, DontEnum);
@@ -117,10 +117,10 @@ void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "round"), 1, mathProtoFuncRound, RoundIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sign"), 1, mathProtoFuncSign, NoIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sin"), 1, mathProtoFuncSin, SinIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sinh"), 1, mathProtoFuncSinh, NoIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sinh"), 1, mathProtoFuncSinh, SinhIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sqrt"), 1, mathProtoFuncSqrt, SqrtIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tan"), 1, mathProtoFuncTan, TanIntrinsic, DontEnum);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tanh"), 1, mathProtoFuncTanh, NoIntrinsic, DontEnum);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tanh"), 1, mathProtoFuncTanh, TanhIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "trunc"), 1, mathProtoFuncTrunc, TruncIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "imul"), 2, mathProtoFuncIMul, IMulIntrinsic, DontEnum);
 }
@@ -134,17 +134,17 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(acos(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::acos(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(asin(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::asin(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(atan(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::atan(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec)
@@ -170,12 +170,12 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncClz32(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(cos(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::cos(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(exp(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::exp(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec)
@@ -215,7 +215,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(log(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::log(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec)
@@ -278,7 +278,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncSign(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(sin(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::sin(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec)
@@ -288,7 +288,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(tan(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::tan(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState* exec)
@@ -304,32 +304,32 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncACosh(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(acosh(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::acosh(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncASinh(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(asinh(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::asinh(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncATanh(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(atanh(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::atanh(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCbrt(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(cbrt(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::cbrt(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCosh(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(cosh(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::cosh(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncExpm1(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(expm1(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::expm1(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState* exec)
@@ -339,30 +339,27 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncLog1p(ExecState* exec)
 {
-    double value = exec->argument(0).toNumber(exec);
-    if (value == 0)
-        return JSValue::encode(jsDoubleNumber(value));
-    return JSValue::encode(jsDoubleNumber(log1p(value)));
+    return JSValue::encode(jsDoubleNumber(Math::log1p(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncLog10(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(log10(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::log10(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncLog2(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(log2(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::log2(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncSinh(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(sinh(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::sinh(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncTanh(ExecState* exec)
 {
-    return JSValue::encode(jsDoubleNumber(tanh(exec->argument(0).toNumber(exec))));
+    return JSValue::encode(jsDoubleNumber(Math::tanh(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*exec)