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()