Title: [205112] trunk
Revision
205112
Author
[email protected]
Date
2016-08-29 00:21:04 -0700 (Mon, 29 Aug 2016)

Log Message

[JSC] Improve ArithAbs with polymorphic input
https://bugs.webkit.org/show_bug.cgi?id=161286

Patch by Benjamin Poulain <[email protected]> on 2016-08-29
Reviewed by Saam Barati.

JSTests:

* stress/arith-abs-on-various-types.js: Added.
New tests.

* stress/arith-cos-on-various-types.js:
* stress/arith-fround-on-various-types.js:
* stress/arith-log-on-various-types.js:
* stress/arith-sin-on-various-types.js:
* stress/arith-sqrt-on-various-types.js:
Extend the existing tests to cover the DCE case.

Source/_javascript_Core:

This is similar to the previous patches: if we have polymorphic
input, do a function call.

I also discovered a few problems with the tests and fixed them:
-I forgot to add NodeMustGenerate to the previous nodes I changed.
 They could have been eliminated by DCE.
-ArithAbs was always exiting if the input types do not include numbers.
 The cause was the node was using isInt32OrBooleanSpeculationForArithmetic()
 instead of isInt32OrBooleanSpeculation(). The test of
 isInt32OrBooleanSpeculationForArithmetic() only verify the input does not
 contains double or int52. If we were in that case, we were always speculating
 Int32. That always fails and we were recompiling the same code over and over.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
Now that we have toNumberFromPrimitive(), we can improve constant folding here :)

* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasResult):
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasInt32Result): Deleted.
The accessor hasInt32Result() was unused.

* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithAbs):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileArithAbs):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (205111 => 205112)


--- trunk/JSTests/ChangeLog	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/JSTests/ChangeLog	2016-08-29 07:21:04 UTC (rev 205112)
@@ -1,3 +1,20 @@
+2016-08-29  Benjamin Poulain  <[email protected]>
+
+        [JSC] Improve ArithAbs with polymorphic input
+        https://bugs.webkit.org/show_bug.cgi?id=161286
+
+        Reviewed by Saam Barati.
+
+        * stress/arith-abs-on-various-types.js: Added.
+        New tests.
+
+        * stress/arith-cos-on-various-types.js:
+        * stress/arith-fround-on-various-types.js:
+        * stress/arith-log-on-various-types.js:
+        * stress/arith-sin-on-various-types.js:
+        * stress/arith-sqrt-on-various-types.js:
+        Extend the existing tests to cover the DCE case.
+
 2016-08-26  Benjamin Poulain  <[email protected]>
 
         [JSC] Implement CompareStrictEq(String, Untyped) in FTL

Added: trunk/JSTests/stress/arith-abs-on-various-types.js (0 => 205112)


--- trunk/JSTests/stress/arith-abs-on-various-types.js	                        (rev 0)
+++ trunk/JSTests/stress/arith-abs-on-various-types.js	2016-08-29 07:21:04 UTC (rev 205112)
@@ -0,0 +1,238 @@
+"use strict";
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    ["undefined", "NaN"],
+    ["null", "0"],
+    ["0", "0"],
+    ["-0.", "0"],
+    ["1.", "1"],
+    ["42", "42"],
+    ["-42", "42"],
+    ["Math.E", "Math.E"],
+    ["Infinity", "Infinity"],
+    ["-Infinity", "Infinity"],
+    ["NaN", "NaN"],
+    ["-NaN", "NaN"],
+    ["\"WebKit\"", "NaN"],
+    ["\"4\"", "4"],
+    ["\"-4\"", "4"],
+    ["{ valueOf: () => { return Math.E; } }", "Math.E"],
+    ["{ valueOf: () => { return 4; } }", "4"],
+    ["{ valueOf: () => { return -4; } }", "4"],
+];
+
+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 && 1 / expected === -Infinity && 1 / result !== -Infinity)
+            return false;
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.abs() without arguments.
+function opaqueAbsNoArgument() {
+    return Math.abs();
+}
+noInline(opaqueAbsNoArgument);
+noOSRExitFuzzing(opaqueAbsNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i < 1e4; ++i) {
+        let output = opaqueAbsNoArgument();
+        if (output === output) {
+            throw "Failed opaqueAbsNoArgument";
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAbsNoArgument) > 1)
+        throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
+// Test Math.abs() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesAbs(argument) {
+    return Math.abs(argument);
+}
+noInline(opaqueAllTypesAbs);
+noOSRExitFuzzing(opaqueAllTypesAbs);
+
+function testAllTypesCall() {
+    for (let i = 0; i < 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesAbs(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesAbs) > 2)
+        throw "We should have detected abs() was polymorphic and generated a generic version.";
+}
+testAllTypesCall();
+
+
+// Test Math.abs() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueAbs(argument) {
+                return Math.abs(argument);
+            }
+            noInline(opaqueAbs);
+            noOSRExitFuzzing(opaqueAbs);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueAbs(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw "Failed testSingleTypeCall()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueAbs) > 1)
+                throw "We should have compiled a single abs for the expected type. The argument was " + ${testCaseInput[0]};
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+// Test Math.abs() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueAbsOnConstant() {
+                return Math.abs(${testCaseInput[0]});
+            }
+            noInline(opaqueAbsOnConstant);
+            noOSRExitFuzzing(opaqueAbsOnConstant);
+
+            for (let i = 0; i < 1e4; ++i) {
+                if (!isIdentical(opaqueAbsOnConstant(), ${testCaseInput[1]})) {
+                    throw "Failed testConstant()";
+                }
+            }
+            if (numberOfDFGCompiles(opaqueAbsOnConstant) > 1)
+                throw "We should have compiled a single abs for the expected type.";
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueAbsForSideEffects(argument) {
+    return Math.abs(argument);
+}
+noInline(opaqueAbsForSideEffects);
+noOSRExitFuzzing(opaqueAbsForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let abs16 = Math.abs(16);
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueAbsForSideEffects(testObject) !== abs16)
+            throw "Incorrect result in testSideEffect()";
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testSideEffect()";
+    if (numberOfDFGCompiles(opaqueAbsForSideEffects) > 1)
+        throw "opaqueAbsForSideEffects() is predictable, it should only be compiled once.";
+}
+testSideEffect();
+
+
+// Verify abs() is not subject to CSE if the argument has side effects.
+function opaqueAbsForCSE(argument) {
+    return Math.abs(argument) + Math.abs(argument) + Math.abs(argument);
+}
+noInline(opaqueAbsForCSE);
+noOSRExitFuzzing(opaqueAbsForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let abs16 = Math.abs(16);
+    let threeAbs16 = abs16 + abs16 + abs16;
+    for (let i = 0; i < 1e4; ++i) {
+        if (opaqueAbsForCSE(testObject) !== threeAbs16)
+            throw "Incorrect result in testCSE()";
+    }
+    if (testObject.counter !== 3e4)
+        throw "Failed testCSE()";
+    if (numberOfDFGCompiles(opaqueAbsForCSE) > 1)
+        throw "opaqueAbsForCSE() is predictable, it should only be compiled once.";
+}
+testCSE();
+
+
+// Verify abs() is not subject to DCE if the argument has side effects.
+function opaqueAbsForDCE(argument) {
+    Math.abs(argument);
+}
+noInline(opaqueAbsForDCE);
+noOSRExitFuzzing(opaqueAbsForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueAbsForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueAbsForDCE) > 1)
+        throw "opaqueAbsForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueAbsWithException(argument) {
+        let result = Math.abs(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueAbsWithException);
+
+    let testObject = { valueOf: () => {  return 64; } };
+    let abs64 = Math.abs(64);
+
+    // Warm up without exception.
+    for (let i = 0; i < 1e3; ++i) {
+        if (opaqueAbsWithException(testObject) !== abs64)
+            throw "Incorrect result in opaqueAbsWithException()";
+    }
+
+    let testThrowObject = { valueOf: () => { throw testObject; return 64; } };
+
+    for (let i = 0; i < 1e2; ++i) {
+        try {
+            if (opaqueAbsWithException(testThrowObject) !== 8)
+                throw "This code should not be reached!!";
+        } catch (e) {
+            if (e !== testObject) {
+                throw "Wrong object thrown from opaqueAbsWithException."
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw "Invalid count in testException()";
+    }
+}
+testException();

Modified: trunk/JSTests/stress/arith-cos-on-various-types.js (205111 => 205112)


--- trunk/JSTests/stress/arith-cos-on-various-types.js	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/JSTests/stress/arith-cos-on-various-types.js	2016-08-29 07:21:04 UTC (rev 205112)
@@ -146,7 +146,7 @@
 testSideEffect();
 
 
-// Verify SQRT is not subject to CSE if the argument has side effects.
+// Verify cos() is not subject to CSE if the argument has side effects.
 function opaqueCosForCSE(argument) {
     return Math.cos(argument) + Math.cos(argument) + Math.cos(argument);
 }
@@ -172,6 +172,29 @@
 testCSE();
 
 
+// Verify cos() is not subject to DCE if the argument has side effects.
+function opaqueCosForDCE(argument) {
+    Math.cos(argument);
+}
+noInline(opaqueCosForDCE);
+noOSRExitFuzzing(opaqueCosForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueCosForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueCosForDCE) > 1)
+        throw "opaqueCosForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
 // Test exceptions in the argument.
 function testException() {
     let counter = 0;

Modified: trunk/JSTests/stress/arith-fround-on-various-types.js (205111 => 205112)


--- trunk/JSTests/stress/arith-fround-on-various-types.js	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/JSTests/stress/arith-fround-on-various-types.js	2016-08-29 07:21:04 UTC (rev 205112)
@@ -148,7 +148,7 @@
 testSideEffect();
 
 
-// Verify SQRT is not subject to CSE if the argument has side effects.
+// Verify fround() is not subject to CSE if the argument has side effects.
 function opaqueFroundForCSE(argument) {
     return Math.fround(argument) + Math.fround(argument) + Math.fround(argument);
 }
@@ -174,6 +174,29 @@
 testCSE();
 
 
+// Verify fround() is not subject to DCE if the argument has side effects.
+function opaqueFroundForDCE(argument) {
+    Math.fround(argument);
+}
+noInline(opaqueFroundForDCE);
+noOSRExitFuzzing(opaqueFroundForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueFroundForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueFroundForDCE) > 1)
+        throw "opaqueFroundForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
 // Test exceptions in the argument.
 function testException() {
     let counter = 0;

Modified: trunk/JSTests/stress/arith-log-on-various-types.js (205111 => 205112)


--- trunk/JSTests/stress/arith-log-on-various-types.js	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/JSTests/stress/arith-log-on-various-types.js	2016-08-29 07:21:04 UTC (rev 205112)
@@ -149,7 +149,7 @@
 testSideEffect();
 
 
-// Verify SQRT is not subject to CSE if the argument has side effects.
+// Verify log() is not subject to CSE if the argument has side effects.
 function opaqueLogForCSE(argument) {
     return Math.log(argument) + Math.log(argument) + Math.log(argument);
 }
@@ -175,6 +175,29 @@
 testCSE();
 
 
+// Verify log() is not subject to DCE if the argument has side effects.
+function opaqueLogForDCE(argument) {
+    Math.log(argument);
+}
+noInline(opaqueLogForDCE);
+noOSRExitFuzzing(opaqueLogForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueLogForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueLogForDCE) > 1)
+        throw "opaqueLogForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
 // Test exceptions in the argument.
 function testException() {
     let counter = 0;

Modified: trunk/JSTests/stress/arith-sin-on-various-types.js (205111 => 205112)


--- trunk/JSTests/stress/arith-sin-on-various-types.js	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/JSTests/stress/arith-sin-on-various-types.js	2016-08-29 07:21:04 UTC (rev 205112)
@@ -146,7 +146,7 @@
 testSideEffect();
 
 
-// Verify SQRT is not subject to CSE if the argument has side effects.
+// Verify sin() is not subject to CSE if the argument has side effects.
 function opaqueSinForCSE(argument) {
     return Math.sin(argument) + Math.sin(argument) + Math.sin(argument);
 }
@@ -172,6 +172,29 @@
 testCSE();
 
 
+// Verify sin() is not subject to DCE if the argument has side effects.
+function opaqueSinForDCE(argument) {
+    Math.sin(argument);
+}
+noInline(opaqueSinForDCE);
+noOSRExitFuzzing(opaqueSinForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueSinForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueSinForDCE) > 1)
+        throw "opaqueSinForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
 // Test exceptions in the argument.
 function testException() {
     let counter = 0;

Modified: trunk/JSTests/stress/arith-sqrt-on-various-types.js (205111 => 205112)


--- trunk/JSTests/stress/arith-sqrt-on-various-types.js	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/JSTests/stress/arith-sqrt-on-various-types.js	2016-08-29 07:21:04 UTC (rev 205112)
@@ -143,7 +143,7 @@
 testSideEffect();
 
 
-// Verify SQRT is not subject to CSE if the argument has side effects.
+// Verify sqrt() is not subject to CSE if the argument has side effects.
 function opaqueSqrtForCSE(argument) {
     return Math.sqrt(argument) + Math.sqrt(argument) + Math.sqrt(argument);
 }
@@ -167,6 +167,29 @@
 testCSE();
 
 
+// Verify sqrt() is not subject to DCE if the argument has side effects.
+function opaqueSqrtForDCE(argument) {
+    Math.sqrt(argument);
+}
+noInline(opaqueSqrtForDCE);
+noOSRExitFuzzing(opaqueSqrtForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        opaqueSqrtForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw "Failed testDCE()";
+    if (numberOfDFGCompiles(opaqueSqrtForDCE) > 1)
+        throw "opaqueSqrtForDCE() is predictable, it should only be compiled once.";
+}
+testDCE();
+
+
 // Test exceptions in the argument.
 function testException() {
     let counter = 0;

Modified: trunk/Source/_javascript_Core/ChangeLog (205111 => 205112)


--- trunk/Source/_javascript_Core/ChangeLog	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-08-29 07:21:04 UTC (rev 205112)
@@ -1,3 +1,51 @@
+2016-08-29  Benjamin Poulain  <[email protected]>
+
+        [JSC] Improve ArithAbs with polymorphic input
+        https://bugs.webkit.org/show_bug.cgi?id=161286
+
+        Reviewed by Saam Barati.
+
+        This is similar to the previous patches: if we have polymorphic
+        input, do a function call.
+
+        I also discovered a few problems with the tests and fixed them:
+        -I forgot to add NodeMustGenerate to the previous nodes I changed.
+         They could have been eliminated by DCE.
+        -ArithAbs was always exiting if the input types do not include numbers.
+         The cause was the node was using isInt32OrBooleanSpeculationForArithmetic()
+         instead of isInt32OrBooleanSpeculation(). The test of
+         isInt32OrBooleanSpeculationForArithmetic() only verify the input does not
+         contains double or int52. If we were in that case, we were always speculating
+         Int32. That always fails and we were recompiling the same code over and over.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        Now that we have toNumberFromPrimitive(), we can improve constant folding here :)
+
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasResult):
+        (JSC::DFG::Node::hasHeapPrediction):
+        (JSC::DFG::Node::hasInt32Result): Deleted.
+        The accessor hasInt32Result() was unused.
+
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithAbs):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithAbs):
+
 2016-08-28  Saam Barati  <[email protected]>
 
         Make SpeculatedType a 64-bit integer

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-08-29 07:21:04 UTC (rev 205112)
@@ -852,8 +852,8 @@
         JSValue child = forNode(node->child1()).value();
         switch (node->child1().useKind()) {
         case Int32Use:
-            if (child && child.isInt32()) {
-                JSValue result = jsNumber(fabs(child.asNumber()));
+            if (Optional<double> number = child.toNumberFromPrimitive()) {
+                JSValue result = jsNumber(fabs(*number));
                 if (result.isInt32()) {
                     setConstant(node, result);
                     break;
@@ -862,14 +862,15 @@
             forNode(node).setType(SpecInt32Only);
             break;
         case DoubleRepUse:
-            if (child && child.isNumber()) {
-                setConstant(node, jsDoubleNumber(fabs(child.asNumber())));
+            if (Optional<double> number = child.toNumberFromPrimitive()) {
+                setConstant(node, jsDoubleNumber(fabs(*number)));
                 break;
             }
             forNode(node).setType(typeOfDoubleAbs(forNode(node->child1()).m_type));
             break;
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
+            forNode(node).setType(SpecFullNumber);
             break;
         }
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-08-29 07:21:04 UTC (rev 205112)
@@ -149,7 +149,6 @@
         return;
         
     case ArithIMul:
-    case ArithAbs:
     case ArithClz32:
     case ArithMin:
     case ArithMax:
@@ -198,6 +197,15 @@
         }
         return;
 
+    case ArithAbs:
+        if (node->child1().useKind() == Int32Use || node->child1().useKind() == DoubleRepUse)
+            def(PureValue(node));
+        else {
+            read(World);
+            write(Heap);
+        }
+        return;
+
     case BitAnd:
     case BitOr:
     case BitXor:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-08-29 07:21:04 UTC (rev 205112)
@@ -331,15 +331,23 @@
         }
             
         case ArithAbs: {
-            if (m_graph.unaryArithShouldSpeculateInt32(node, FixupPass)) {
+            if (node->child1()->shouldSpeculateInt32OrBoolean()
+                && node->canSpeculateInt32(FixupPass)) {
                 fixIntOrBooleanEdge(node->child1());
                 if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
                     node->setArithMode(Arith::Unchecked);
                 else
                     node->setArithMode(Arith::CheckOverflow);
+                node->clearFlags(NodeMustGenerate);
+                node->setResult(NodeResultInt32);
                 break;
             }
-            fixDoubleOrBooleanEdge(node->child1());
+
+            if (node->child1()->shouldSpeculateNumberOrBoolean()) {
+                fixDoubleOrBooleanEdge(node->child1());
+                node->clearFlags(NodeMustGenerate);
+            } else
+                fixEdge<UntypedUse>(node->child1());
             node->setResult(NodeResultDouble);
             break;
         }
@@ -392,9 +400,10 @@
         case ArithSin:
         case ArithSqrt: {
             Edge& child1 = node->child1();
-            if (child1->shouldSpeculateNumberOrBoolean())
+            if (child1->shouldSpeculateNumberOrBoolean()) {
                 fixDoubleOrBooleanEdge(child1);
-            else
+                node->clearFlags(NodeMustGenerate);
+            } else
                 fixEdge<UntypedUse>(child1);
             break;
         }

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-08-29 07:21:04 UTC (rev 205112)
@@ -1165,11 +1165,6 @@
     {
         return !!result();
     }
-
-    bool hasInt32Result()
-    {
-        return result() == NodeResultInt32;
-    }
     
     bool hasInt52Result()
     {
@@ -1392,6 +1387,7 @@
     bool hasHeapPrediction()
     {
         switch (op()) {
+        case ArithAbs:
         case ArithRound:
         case ArithFloor:
         case ArithCeil:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-08-29 07:21:04 UTC (rev 205112)
@@ -152,7 +152,7 @@
     macro(ArithAbs, NodeResultNumber | NodeMustGenerate) \
     macro(ArithMin, NodeResultNumber) \
     macro(ArithMax, NodeResultNumber) \
-    macro(ArithFRound, NodeResultDouble) \
+    macro(ArithFRound, NodeResultDouble | NodeMustGenerate) \
     macro(ArithPow, NodeResultDouble) \
     macro(ArithRandom, NodeResultDouble | NodeMustGenerate) \
     macro(ArithRound, NodeResultNumber) \
@@ -159,10 +159,10 @@
     macro(ArithFloor, NodeResultNumber) \
     macro(ArithCeil, NodeResultNumber) \
     macro(ArithTrunc, NodeResultNumber) \
-    macro(ArithSqrt, NodeResultDouble) \
-    macro(ArithSin, NodeResultDouble) \
-    macro(ArithCos, NodeResultDouble) \
-    macro(ArithLog, NodeResultDouble) \
+    macro(ArithSqrt, NodeResultDouble | NodeMustGenerate) \
+    macro(ArithSin, NodeResultDouble | NodeMustGenerate) \
+    macro(ArithCos, NodeResultDouble | NodeMustGenerate) \
+    macro(ArithLog, NodeResultDouble | NodeMustGenerate) \
     \
     /* Add of values may either be arithmetic, or result in string concatenation. */\
     macro(ValueAdd, NodeResultJS | NodeMustGenerate) \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2016-08-29 07:21:04 UTC (rev 205112)
@@ -322,6 +322,18 @@
     return JSValue::encode(jsNumber(a / b));
 }
 
+double JIT_OPERATION operationArithAbs(ExecState* exec, EncodedJSValue encodedOp1)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+
+    JSValue op1 = JSValue::decode(encodedOp1);
+    double a = op1.toNumber(exec);
+    if (UNLIKELY(vm->exception()))
+        return JSValue::encode(JSValue());
+    return fabs(a);
+}
+
 double JIT_OPERATION operationArithCos(ExecState* exec, EncodedJSValue encodedOp1)
 {
     VM* vm = &exec->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2016-08-29 07:21:04 UTC (rev 205112)
@@ -53,6 +53,7 @@
 EncodedJSValue JIT_OPERATION operationValueBitURShift(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueDiv(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
+double JIT_OPERATION operationArithAbs(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 double JIT_OPERATION operationArithCos(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 double JIT_OPERATION operationArithFRound(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 double JIT_OPERATION operationArithLog(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-08-29 07:21:04 UTC (rev 205112)
@@ -330,12 +330,12 @@
         }
 
         case ArithAbs: {
-            SpeculatedType child = node->child1()->prediction();
-            if (isInt32OrBooleanSpeculationForArithmetic(child)
+            SpeculatedType childPrediction = node->child1()->prediction();
+            if (isInt32OrBooleanSpeculation(childPrediction)
                 && node->canSpeculateInt32(m_pass))
                 changed |= mergePrediction(SpecInt32Only);
             else
-                changed |= mergePrediction(speculatedDoubleTypeForPrediction(child));
+                changed |= mergePrediction(SpecBytecodeDouble);
             break;
         }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-08-29 07:21:04 UTC (rev 205112)
@@ -3874,6 +3874,47 @@
     cellResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileArithAbs(Node* node)
+{
+    switch (node->child1().useKind()) {
+    case Int32Use: {
+        SpeculateStrictInt32Operand op1(this, node->child1());
+        GPRTemporary result(this, Reuse, op1);
+        GPRTemporary scratch(this);
+
+        m_jit.move(op1.gpr(), result.gpr());
+        m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
+        m_jit.add32(scratch.gpr(), result.gpr());
+        m_jit.xor32(scratch.gpr(), result.gpr());
+        if (shouldCheckOverflow(node->arithMode()))
+            speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, result.gpr()));
+        int32Result(result.gpr(), node);
+        break;
+    }
+
+    case DoubleRepUse: {
+        SpeculateDoubleOperand op1(this, node->child1());
+        FPRTemporary result(this);
+
+        m_jit.absDouble(op1.fpr(), result.fpr());
+        doubleResult(result.fpr(), node);
+        break;
+    }
+
+    default: {
+        DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse);
+        JSValueOperand op1(this, node->child1());
+        JSValueRegs op1Regs = op1.jsValueRegs();
+        flushRegisters();
+        FPRResult result(this);
+        callOperation(operationArithAbs, result.fpr(), op1Regs);
+        m_jit.exceptionCheck();
+        doubleResult(result.fpr(), node);
+        break;
+    }
+    }
+}
+
 void SpeculativeJIT::compileArithClz32(Node* node)
 {
     ASSERT_WITH_MESSAGE(node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use, "The Fixup phase should have enforced a Int32 operand.");

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-08-29 07:21:04 UTC (rev 205112)
@@ -2468,6 +2468,7 @@
     void compileValueAdd(Node*);
     void compileArithAdd(Node*);
     void compileMakeRope(Node*);
+    void compileArithAbs(Node*);
     void compileArithClz32(Node*);
     void compileArithCos(Node*);
     void compileArithSub(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-08-29 07:21:04 UTC (rev 205112)
@@ -2259,39 +2259,10 @@
         break;
     }
 
-    case ArithAbs: {
-        switch (node->child1().useKind()) {
-        case Int32Use: {
-            SpeculateStrictInt32Operand op1(this, node->child1());
-            GPRTemporary result(this, Reuse, op1);
-            GPRTemporary scratch(this);
-            
-            m_jit.move(op1.gpr(), result.gpr());
-            m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
-            m_jit.add32(scratch.gpr(), result.gpr());
-            m_jit.xor32(scratch.gpr(), result.gpr());
-            speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, result.gpr()));
-            int32Result(result.gpr(), node);
-            break;
-        }
-        
-            
-        case DoubleRepUse: {
-            SpeculateDoubleOperand op1(this, node->child1());
-            FPRTemporary result(this);
-            
-            m_jit.absDouble(op1.fpr(), result.fpr());
-            doubleResult(result.fpr(), node);
-            break;
-        }
-            
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
-        }
+    case ArithAbs:
+        compileArithAbs(node);
         break;
-    }
-        
+
     case ArithMin:
     case ArithMax: {
         switch (node->binaryUseKind()) {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (205111 => 205112)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-08-29 07:21:04 UTC (rev 205112)
@@ -2383,38 +2383,9 @@
         break;
     }
 
-    case ArithAbs: {
-        switch (node->child1().useKind()) {
-        case Int32Use: {
-            SpeculateStrictInt32Operand op1(this, node->child1());
-            GPRTemporary result(this);
-            GPRTemporary scratch(this);
-            
-            m_jit.move(op1.gpr(), result.gpr());
-            m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
-            m_jit.add32(scratch.gpr(), result.gpr());
-            m_jit.xor32(scratch.gpr(), result.gpr());
-            if (shouldCheckOverflow(node->arithMode()))
-                speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, result.gpr()));
-            int32Result(result.gpr(), node);
-            break;
-        }
-        
-        case DoubleRepUse: {
-            SpeculateDoubleOperand op1(this, node->child1());
-            FPRTemporary result(this);
-            
-            m_jit.absDouble(op1.fpr(), result.fpr());
-            doubleResult(result.fpr(), node);
-            break;
-        }
-            
-        default:
-            DFG_CRASH(m_jit.graph(), node, "Bad use kind");
-            break;
-        }
+    case ArithAbs:
+        compileArithAbs(node);
         break;
-    }
         
     case ArithMin:
     case ArithMax: {

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (205111 => 205112)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-08-29 06:55:59 UTC (rev 205111)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-08-29 07:21:04 UTC (rev 205112)
@@ -2014,10 +2014,14 @@
             break;
         }
             
-        default:
-            DFG_CRASH(m_graph, m_node, "Bad use kind");
+        default: {
+            DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
+            LValue argument = lowJSValue(m_node->child1());
+            LValue result = vmCall(Double, m_out.operation(operationArithAbs), m_callFrame, argument);
+            setDouble(result);
             break;
         }
+        }
     }
 
     void compileArithSin()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to