Remove CachedTranscendentalFunction because caching math functions is an ugly idea
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 31 Oct 2013 19:19:15 +0000 (19:19 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 31 Oct 2013 19:19:15 +0000 (19:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123574

Source/JavaScriptCore:

Reviewed by Mark Hahnenberg.

This is performance-neutral because I also make Math.cos/sin intrinsic. This means that
we gain the "overhead" of actually computing sin and cos but we lose the overhead of
going through the native call thunks.

Caching transcendental functions is a really ugly idea. It works for SunSpider because
that benchmark makes very predictable calls into Math.sin. But I don't believe that this
is representative of any kind of reality, and so for sensible uses of Math.sin/cos all
that this was doing was adding more call overhead and some hashing overhead.

* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITOperations.h:
* runtime/CachedTranscendentalFunction.h: Removed.
* runtime/DateInstanceCache.h:
* runtime/Intrinsic.h:
* runtime/MathObject.cpp:
(JSC::MathObject::finishCreation):
(JSC::mathProtoFuncCos):
(JSC::mathProtoFuncSin):
* runtime/VM.h:

Tools:

Reviewed by Mark Hahnenberg.

Make it easier to see that a test doesn't have an -expected file.

* Scripts/run-jsc-stress-tests:

LayoutTests:

Reviewed by Mark Hahnenberg.

* js/dfg-cos-constant-expected.txt: Added.
* js/dfg-cos-constant.html: Added.
* js/dfg-sin-constant-expected.txt: Added.
* js/dfg-sin-constant.html: Added.
* js/script-tests/dfg-cos-constant.js: Added.
(foo):
* js/script-tests/dfg-sin-constant.js: Added.
(foo):

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

29 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dfg-cos-constant-expected.txt [new file with mode: 0644]
LayoutTests/js/dfg-cos-constant.html [new file with mode: 0644]
LayoutTests/js/dfg-sin-constant-expected.txt [new file with mode: 0644]
LayoutTests/js/dfg-sin-constant.html [new file with mode: 0644]
LayoutTests/js/script-tests/dfg-cos-constant.js [new file with mode: 0644]
LayoutTests/js/script-tests/dfg-sin-constant.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h [deleted file]
Source/JavaScriptCore/runtime/DateInstanceCache.h
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/MathObject.cpp
Source/JavaScriptCore/runtime/VM.h
Tools/ChangeLog
Tools/Scripts/run-jsc-stress-tests

index 2bf9277..0342553 100644 (file)
@@ -1,3 +1,19 @@
+2013-10-31  Filip Pizlo  <fpizlo@apple.com>
+
+        Remove CachedTranscendentalFunction because caching math functions is an ugly idea
+        https://bugs.webkit.org/show_bug.cgi?id=123574
+
+        Reviewed by Mark Hahnenberg.
+
+        * js/dfg-cos-constant-expected.txt: Added.
+        * js/dfg-cos-constant.html: Added.
+        * js/dfg-sin-constant-expected.txt: Added.
+        * js/dfg-sin-constant.html: Added.
+        * js/script-tests/dfg-cos-constant.js: Added.
+        (foo):
+        * js/script-tests/dfg-sin-constant.js: Added.
+        (foo):
+
 2013-10-30  Gavin Barraclough  <barraclough@apple.com>
 
         WebPageCreationParameters should be consistent in Window.open
diff --git a/LayoutTests/js/dfg-cos-constant-expected.txt b/LayoutTests/js/dfg-cos-constant-expected.txt
new file mode 100644 (file)
index 0000000..a49e1e0
--- /dev/null
@@ -0,0 +1,10 @@
+Tests that Math.cos() on a constant works in the DFG.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS foo() is 1 on all iterations including after DFG tier-up.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dfg-cos-constant.html b/LayoutTests/js/dfg-cos-constant.html
new file mode 100644 (file)
index 0000000..0e97920
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-cos-constant.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dfg-sin-constant-expected.txt b/LayoutTests/js/dfg-sin-constant-expected.txt
new file mode 100644 (file)
index 0000000..6327e6d
--- /dev/null
@@ -0,0 +1,10 @@
+Tests that Math.sin() on a constant works in the DFG.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS foo() is 0 on all iterations including after DFG tier-up.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dfg-sin-constant.html b/LayoutTests/js/dfg-sin-constant.html
new file mode 100644 (file)
index 0000000..46940f1
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-sin-constant.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/script-tests/dfg-cos-constant.js b/LayoutTests/js/script-tests/dfg-cos-constant.js
new file mode 100644 (file)
index 0000000..4650a94
--- /dev/null
@@ -0,0 +1,7 @@
+description(
+"Tests that Math.cos() on a constant works in the DFG."
+);
+
+function foo() { return Math.cos(0); }
+
+dfgShouldBe(foo, "foo()", "1");
diff --git a/LayoutTests/js/script-tests/dfg-sin-constant.js b/LayoutTests/js/script-tests/dfg-sin-constant.js
new file mode 100644 (file)
index 0000000..6f7d1dd
--- /dev/null
@@ -0,0 +1,7 @@
+description(
+"Tests that Math.sin() on a constant works in the DFG."
+);
+
+function foo() { return Math.sin(0); }
+
+dfgShouldBe(foo, "foo()", "0");
index 3b68126..e806e09 100644 (file)
@@ -1,3 +1,54 @@
+2013-10-31  Filip Pizlo  <fpizlo@apple.com>
+
+        Remove CachedTranscendentalFunction because caching math functions is an ugly idea
+        https://bugs.webkit.org/show_bug.cgi?id=123574
+
+        Reviewed by Mark Hahnenberg.
+        
+        This is performance-neutral because I also make Math.cos/sin intrinsic. This means that
+        we gain the "overhead" of actually computing sin and cos but we lose the overhead of
+        going through the native call thunks.
+        
+        Caching transcendental functions is a really ugly idea. It works for SunSpider because
+        that benchmark makes very predictable calls into Math.sin. But I don't believe that this
+        is representative of any kind of reality, and so for sensible uses of Math.sin/cos all
+        that this was doing was adding more call overhead and some hashing overhead.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::::executeEffects):
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        (JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JITOperations.h:
+        * runtime/CachedTranscendentalFunction.h: Removed.
+        * runtime/DateInstanceCache.h:
+        * runtime/Intrinsic.h:
+        * runtime/MathObject.cpp:
+        (JSC::MathObject::finishCreation):
+        (JSC::mathProtoFuncCos):
+        (JSC::mathProtoFuncSin):
+        * runtime/VM.h:
+
 2013-10-30  Filip Pizlo  <fpizlo@apple.com>
 
         Assertion failure in js/dom/global-constructors-attributes-dedicated-worker.html
index 283b8af..6429abc 100644 (file)
                86880F1F14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */; };
                86880F4D14353B2100B08D42 /* DFGSpeculativeJIT64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */; };
                868916B0155F286300CB2B9A /* PrivateName.h in Headers */ = {isa = PBXBuildFile; fileRef = 868916A9155F285400CB2B9A /* PrivateName.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               869D04AF1193B54D00803475 /* CachedTranscendentalFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
                869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */ = {isa = PBXBuildFile; fileRef = 869EBCB60E8C6D4A008722CC /* ResultType.h */; settings = {ATTRIBUTES = (Private, ); }; };
                86A90ED00EE7D51F00AB350D /* JITArithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */; };
                86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSpeculativeJIT32_64.cpp; path = dfg/DFGSpeculativeJIT32_64.cpp; sourceTree = "<group>"; };
                86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSpeculativeJIT64.cpp; path = dfg/DFGSpeculativeJIT64.cpp; sourceTree = "<group>"; };
                868916A9155F285400CB2B9A /* PrivateName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivateName.h; sourceTree = "<group>"; };
-               869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedTranscendentalFunction.h; sourceTree = "<group>"; };
                869EBCB60E8C6D4A008722CC /* ResultType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultType.h; sourceTree = "<group>"; };
                86A054461556451B00445157 /* LowLevelInterpreter.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter.asm; path = llint/LowLevelInterpreter.asm; sourceTree = "<group>"; };
                86A054471556451B00445157 /* LowLevelInterpreter32_64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter32_64.asm; path = llint/LowLevelInterpreter32_64.asm; sourceTree = "<group>"; };
                                BC7952350E15EB5600A898AB /* BooleanPrototype.h */,
                                0FB7F38B15ED8E3800F167B2 /* Butterfly.h */,
                                0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */,
-                               869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */,
                                BCA62DFE0E2826230004F30D /* CallData.cpp */,
                                145C507F0D9DF63B0088F6B9 /* CallData.h */,
                                BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */,
                                0F21C27F14BEAA8200ADC64B /* BytecodeConventions.h in Headers */,
                                969A07230ED1CE3300F1F681 /* BytecodeGenerator.h in Headers */,
                                0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */,
-                               869D04AF1193B54D00803475 /* CachedTranscendentalFunction.h in Headers */,
                                BC18C3ED0E16F5CD00B34460 /* CallData.h in Headers */,
                                1429D8DE0ED2205B00B89619 /* CallFrame.h in Headers */,
                                A7C1EAEF17987AB600299DB2 /* CallFrameInlines.h in Headers */,
index 414c93e..0ab5aa1 100644 (file)
@@ -547,7 +547,27 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case ArithSqrt: {
         JSValue child = forNode(node->child1()).value();
         if (child && child.isNumber()) {
-            setConstant(node, JSValue(sqrt(child.asNumber())));
+            setConstant(node, jsNumber(sqrt(child.asNumber())));
+            break;
+        }
+        forNode(node).setType(SpecDouble);
+        break;
+    }
+        
+    case ArithSin: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()) {
+            setConstant(node, jsNumber(sin(child.asNumber())));
+            break;
+        }
+        forNode(node).setType(SpecDouble);
+        break;
+    }
+    
+    case ArithCos: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()) {
+            setConstant(node, jsNumber(cos(child.asNumber())));
             break;
         }
         forNode(node).setType(SpecDouble);
index 0a2d533..2c4991e 100644 (file)
@@ -383,6 +383,12 @@ private:
             break;
         }
             
+        // Note: ArithSqrt, ArithSin, and ArithCos 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:
+        // Math.sin = function(x) { doArbitraryThingsTo(x); }
+            
         default:
             mergeDefaultFlags(node);
             break;
index 8f39802..ca61430 100644 (file)
@@ -1454,8 +1454,6 @@ bool ByteCodeParser::handleMinMax(int resultOperand, NodeType op, int registerOf
     return false;
 }
 
-// FIXME: We dead-code-eliminate unused Math intrinsics, but that's invalid because
-// they need to perform the ToNumber conversion, which can have side-effects.
 bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction)
 {
     switch (intrinsic) {
@@ -1481,17 +1479,34 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int
     case MaxIntrinsic:
         return handleMinMax(resultOperand, ArithMax, registerOffset, argumentCountIncludingThis);
         
-    case SqrtIntrinsic: {
-        if (argumentCountIncludingThis == 1) { // Math.sqrt()
+    case SqrtIntrinsic:
+    case CosIntrinsic:
+    case SinIntrinsic: {
+        if (argumentCountIncludingThis == 1) {
             set(VirtualRegister(resultOperand), constantNaN());
             return true;
         }
         
-        if (!MacroAssembler::supportsFloatingPointSqrt())
+        switch (intrinsic) {
+        case SqrtIntrinsic:
+            if (!MacroAssembler::supportsFloatingPointSqrt())
+                return false;
+            
+            set(VirtualRegister(resultOperand), addToGraph(ArithSqrt, get(virtualRegisterForArgument(1, registerOffset))));
+            return true;
+            
+        case CosIntrinsic:
+            set(VirtualRegister(resultOperand), addToGraph(ArithCos, get(virtualRegisterForArgument(1, registerOffset))));
+            return true;
+            
+        case SinIntrinsic:
+            set(VirtualRegister(resultOperand), addToGraph(ArithSin, get(virtualRegisterForArgument(1, registerOffset))));
+            return true;
+            
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
             return false;
-
-        set(VirtualRegister(resultOperand), addToGraph(ArithSqrt, get(virtualRegisterForArgument(1, registerOffset))));
-        return true;
+        }
     }
         
     case ArrayPushIntrinsic: {
index be31f47..6e3e4e2 100644 (file)
@@ -1059,6 +1059,8 @@ private:
         case ArithMin:
         case ArithMax:
         case ArithSqrt:
+        case ArithSin:
+        case ArithCos:
         case StringCharAt:
         case StringCharCodeAt:
         case IsUndefined:
index abbb551..3ad5cbc 100644 (file)
@@ -97,6 +97,8 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
     case ArithMin:
     case ArithMax:
     case ArithSqrt:
+    case ArithSin:
+    case ArithCos:
     case GetScope:
     case SkipScope:
     case CheckFunction:
index cb3849e..678e304 100644 (file)
@@ -278,7 +278,9 @@ private:
             break;
         }
             
-        case ArithSqrt: {
+        case ArithSqrt:
+        case ArithSin:
+        case ArithCos: {
             fixEdge<NumberUse>(node->child1());
             break;
         }
index 856a2f4..1e011aa 100644 (file)
@@ -129,6 +129,8 @@ namespace JSC { namespace DFG {
     macro(ArithMin, NodeResultNumber | NodeMustGenerate) \
     macro(ArithMax, NodeResultNumber | NodeMustGenerate) \
     macro(ArithSqrt, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithSin, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithCos, NodeResultNumber | NodeMustGenerate) \
     \
     /* Add of values may either be arithmetic, or result in string concatenation. */\
     macro(ValueAdd, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
index 9b88e7f..0fc62fa 100644 (file)
@@ -329,7 +329,9 @@ private:
             break;
         }
             
-        case ArithSqrt: {
+        case ArithSqrt:
+        case ArithSin:
+        case ArithCos: {
             changed |= setPrediction(SpecDouble);
             break;
         }
@@ -714,6 +716,8 @@ private:
             break;
                 
         case ArithSqrt:
+        case ArithCos:
+        case ArithSin:
             m_graph.voteNode(node->child1(), VoteDouble);
             break;
                 
index 0970cbe..7a839c5 100644 (file)
@@ -150,6 +150,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case ArithMin:
     case ArithMax:
     case ArithSqrt:
+    case ArithSin:
+    case ArithCos:
     case ValueAdd:
     case GetById:
     case GetByIdFlush:
index adfafc8..90712db 100644 (file)
@@ -1133,6 +1133,11 @@ public:
         m_jit.setupArguments(arg1, arg2);
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(D_JITOperation_D operation, FPRReg result, FPRReg arg1)
+    {
+        m_jit.setupArguments(arg1);
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(D_JITOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
     {
         m_jit.setupArguments(arg1, arg2);
index e2696d3..19e369f 100644 (file)
@@ -2260,6 +2260,30 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case ArithSin: {
+        SpeculateDoubleOperand op1(this, node->child1());
+        FPRReg op1FPR = op1.fpr();
+
+        flushRegisters();
+        
+        FPRResult result(this);
+        callOperation(sin, result.fpr(), op1FPR);
+        doubleResult(result.fpr(), node);
+        break;
+    }
+
+    case ArithCos: {
+        SpeculateDoubleOperand op1(this, node->child1());
+        FPRReg op1FPR = op1.fpr();
+
+        flushRegisters();
+        
+        FPRResult result(this);
+        callOperation(cos, result.fpr(), op1FPR);
+        doubleResult(result.fpr(), node);
+        break;
+    }
+
     case LogicalNot:
         compileLogicalNot(node);
         break;
index d7809b6..c08a5f9 100644 (file)
@@ -2580,6 +2580,30 @@ void SpeculativeJIT::compile(Node* node)
         doubleResult(result.fpr(), node);
         break;
     }
+        
+    case ArithSin: {
+        SpeculateDoubleOperand op1(this, node->child1());
+        FPRReg op1FPR = op1.fpr();
+
+        flushRegisters();
+        
+        FPRResult result(this);
+        callOperation(sin, result.fpr(), op1FPR);
+        doubleResult(result.fpr(), node);
+        break;
+    }
+
+    case ArithCos: {
+        SpeculateDoubleOperand op1(this, node->child1());
+        FPRReg op1FPR = op1.fpr();
+
+        flushRegisters();
+        
+        FPRResult result(this);
+        callOperation(cos, result.fpr(), op1FPR);
+        doubleResult(result.fpr(), node);
+        break;
+    }
 
     case LogicalNot:
         compileLogicalNot(node);
index d88e951..494b67d 100644 (file)
@@ -120,6 +120,7 @@ typedef JSCell* JIT_OPERATION (*C_JITOperation_EO)(ExecState*, JSObject*);
 typedef JSCell* JIT_OPERATION (*C_JITOperation_EOZ)(ExecState*, JSObject*, int32_t);
 typedef JSCell* JIT_OPERATION (*C_JITOperation_ESt)(ExecState*, Structure*);
 typedef JSCell* JIT_OPERATION (*C_JITOperation_EZ)(ExecState*, int32_t);
+typedef double JIT_OPERATION (*D_JITOperation_D)(double);
 typedef double JIT_OPERATION (*D_JITOperation_DD)(double, double);
 typedef double JIT_OPERATION (*D_JITOperation_ZZ)(int32_t, int32_t);
 typedef double JIT_OPERATION (*D_JITOperation_EJ)(ExecState*, EncodedJSValue);
diff --git a/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h b/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h
deleted file mode 100644 (file)
index 392d64f..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#ifndef CachedTranscendentalFunction_h
-#define CachedTranscendentalFunction_h
-
-#include "JSCJSValue.h"
-
-namespace JSC {
-
-typedef double (*TranscendentalFunctionPtr)(double);
-
-// CachedTranscendentalFunction provides a generic mechanism to cache results
-// for pure functions with the signature "double func(double)", and where NaN
-// maps to NaN.
-template<TranscendentalFunctionPtr orignalFunction>
-class CachedTranscendentalFunction {
-    struct CacheEntry {
-        double operand;
-        double result;
-    };
-
-public:
-    CachedTranscendentalFunction()
-        : m_cache(0)
-    {
-    }
-
-    ~CachedTranscendentalFunction()
-    {
-        if (m_cache)
-            fastFree(m_cache);
-    }
-
-    JSValue operator() (double operand)
-    {
-        if (UNLIKELY(!m_cache))
-            initialize();
-        CacheEntry* entry = &m_cache[hash(operand)];
-
-        if (entry->operand == operand)
-            return jsDoubleNumber(entry->result);
-        double result = orignalFunction(operand);
-        entry->operand = operand;
-        entry->result = result;
-        return jsDoubleNumber(result);
-    }
-
-private:
-    void initialize()
-    {
-        // Lazily allocate the table, populate with NaN->NaN mapping.
-        m_cache = static_cast<CacheEntry*>(fastMalloc(s_cacheSize * sizeof(CacheEntry)));
-        for (unsigned x = 0; x < s_cacheSize; ++x) {
-            m_cache[x].operand = QNaN;
-            m_cache[x].result = QNaN;
-        }
-    }
-
-    static unsigned hash(double d)
-    {
-        union doubleAndUInt64 {
-            double d;
-            uint32_t is[2];
-        } u;
-        u.d = d;
-
-        unsigned x = u.is[0] ^ u.is[1];
-        x = (x >> 20) ^ (x >> 8);
-        return x & (s_cacheSize - 1);
-    }
-
-    static const unsigned s_cacheSize = 0x1000;
-    CacheEntry* m_cache;
-};
-
-}
-
-#endif // CachedTranscendentalFunction_h
index e186516..7aa23f2 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef DateInstanceCache_h
 #define DateInstanceCache_h
 
+#include "JSCJSValue.h"
 #include "JSDateMath.h"
 #include <wtf/FixedArray.h>
 #include <wtf/HashFunctions.h>
index cd06c7e..1f741da 100644 (file)
@@ -34,6 +34,8 @@ enum Intrinsic {
     MinIntrinsic,
     MaxIntrinsic,
     SqrtIntrinsic,
+    SinIntrinsic,
+    CosIntrinsic,
     ArrayPushIntrinsic,
     ArrayPopIntrinsic,
     CharCodeAtIntrinsic,
index ebcdf29..5403dff 100644 (file)
@@ -85,7 +85,7 @@ void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atan"), 1, mathProtoFuncATan, NoIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atan2"), 2, mathProtoFuncATan2, NoIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "ceil"), 1, mathProtoFuncCeil, CeilIntrinsic, DontEnum | Function);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cos"), 1, mathProtoFuncCos, NoIntrinsic, DontEnum | Function);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cos"), 1, mathProtoFuncCos, CosIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "exp"), 1, mathProtoFuncExp, ExpIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "floor"), 1, mathProtoFuncFloor, FloorIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log"), 1, mathProtoFuncLog, LogIntrinsic, DontEnum | Function);
@@ -94,7 +94,7 @@ void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "pow"), 2, mathProtoFuncPow, PowIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "random"), 0, mathProtoFuncRandom, NoIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "round"), 1, mathProtoFuncRound, RoundIntrinsic, DontEnum | Function);
-    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sin"), 1, mathProtoFuncSin, NoIntrinsic, DontEnum | Function);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sin"), 1, mathProtoFuncSin, SinIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sqrt"), 1, mathProtoFuncSqrt, SqrtIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "tan"), 1, mathProtoFuncTan, NoIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "imul"), 1, mathProtoFuncIMul, IMulIntrinsic, DontEnum | Function);
@@ -136,7 +136,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec)
 {
-    return JSValue::encode(exec->vm().cachedCos(exec->argument(0).toNumber(exec)));
+    return JSValue::encode(jsDoubleNumber(cos(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec)
@@ -251,7 +251,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec)
 {
-    return JSValue::encode(exec->vm().cachedSin(exec->argument(0).toNumber(exec)));
+    return JSValue::encode(jsDoubleNumber(sin(exec->argument(0).toNumber(exec))));
 }
 
 EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec)
index 280c74f..f1ed6cf 100644 (file)
@@ -29,7 +29,6 @@
 #ifndef VM_h
 #define VM_h
 
-#include "CachedTranscendentalFunction.h"
 #include "DateInstanceCache.h"
 #include "ExecutableAllocator.h"
 #include "Heap.h"
@@ -419,9 +418,6 @@ namespace JSC {
 
         ThreadIdentifier exclusiveThread;
 
-        CachedTranscendentalFunction<std::sin> cachedSin;
-        CachedTranscendentalFunction<std::cos> cachedCos;
-
         JS_EXPORT_PRIVATE void resetDateCache();
 
         JS_EXPORT_PRIVATE void startSampling();
index 8a808f9..9a759a3 100644 (file)
@@ -1,3 +1,14 @@
+2013-10-31  Filip Pizlo  <fpizlo@apple.com>
+
+        Remove CachedTranscendentalFunction because caching math functions is an ugly idea
+        https://bugs.webkit.org/show_bug.cgi?id=123574
+
+        Reviewed by Mark Hahnenberg.
+
+        Make it easier to see that a test doesn't have an -expected file.
+
+        * Scripts/run-jsc-stress-tests:
+
 2013-10-31  Tamas Gergely  <gertom@inf.u-szeged.hu>
 
         Run tests as if they are expected to pass when --force is given.
index 27b37a9..5498642 100755 (executable)
@@ -186,7 +186,8 @@ def diffErrorHandler(expectedFilename)
         outp.puts "then"
         outp.puts "    (cat #{outputFilename} && echo ERROR: Unexpected exit code: `cat #{plan.failFile}`) | " + prefixCommand(plan.name)
         outp.puts "    " + plan.failCommand
-        outp.puts "else"
+        outp.puts "elif test -e #{Shellwords.shellescape(expectedFilename)}"
+        outp.puts "then"
         outp.puts "    diff -u #{Shellwords.shellescape(expectedFilename)} #{outputFilename} > #{diffFilename}"
         outp.puts "    if [ $? -eq 0 ]"
         outp.puts "    then"
@@ -195,6 +196,9 @@ def diffErrorHandler(expectedFilename)
         outp.puts "        (echo \"DIFF FAILURE!\" && cat #{diffFilename}) | " + prefixCommand(plan.name)
         outp.puts "        " + plan.failCommand
         outp.puts "    fi"
+        outp.puts "else"
+        outp.puts "    (echo \"NO EXPECTATION!\" && cat #{outputFilename}) | " + prefixCommand(plan.name)
+        outp.puts "    " + plan.failCommand
         outp.puts "fi"
     }
 end