Diff
Modified: trunk/JSTests/ChangeLog (204994 => 204995)
--- trunk/JSTests/ChangeLog 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/JSTests/ChangeLog 2016-08-25 23:02:52 UTC (rev 204995)
@@ -1,3 +1,19 @@
+2016-08-25 Benjamin Poulain <bpoul...@apple.com>
+
+ [JSC] Clean up the abstract interpreter for cos/sin/sqrt/fround/log
+ https://bugs.webkit.org/show_bug.cgi?id=161181
+
+ Reviewed by Geoffrey Garen.
+
+ Extend the tests to constants.
+ Add no-argument cases where needed.
+
+ * 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:
+
2016-08-25 Yusuke Suzuki <utatane....@gmail.com>
[DFG][FTL] Implement ES6 Generators in DFG / FTL
Modified: trunk/JSTests/stress/arith-cos-on-various-types.js (204994 => 204995)
--- trunk/JSTests/stress/arith-cos-on-various-types.js 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/JSTests/stress/arith-cos-on-various-types.js 2016-08-25 23:02:52 UTC (rev 204995)
@@ -34,6 +34,26 @@
}
+// Test Math.cos() without arguments.
+function opaqueCosNoArgument() {
+ return Math.cos();
+}
+noInline(opaqueCosNoArgument);
+noOSRExitFuzzing(opaqueCosNoArgument);
+
+function testNoArgument() {
+ for (let i = 0; i < 1e4; ++i) {
+ let output = opaqueCosNoArgument();
+ if (output === output) {
+ throw "Failed opaqueCosNoArgument";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueCosNoArgument) > 1)
+ throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
// Test Math.cos() with a very polymorphic input. All test cases are seen at each iteration.
function opaqueAllTypesCos(argument) {
return Math.cos(argument);
@@ -78,6 +98,29 @@
testSingleTypeCall();
+// Test Math.cos() on constants
+function testConstant() {
+ for (let testCaseInput of validInputTestCases) {
+ eval(`
+ function opaqueCosOnConstant() {
+ return Math.cos(${testCaseInput[0]});
+ }
+ noInline(opaqueCosOnConstant);
+ noOSRExitFuzzing(opaqueCosOnConstant);
+
+ for (let i = 0; i < 1e4; ++i) {
+ if (!isIdentical(opaqueCosOnConstant(), ${testCaseInput[1]})) {
+ throw "Failed testConstant()";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueCosOnConstant) > 1)
+ throw "We should have compiled a single cos for the expected type.";
+ `);
+ }
+}
+testConstant();
+
+
// Verify we call valueOf() exactly once per call.
function opaqueCosForSideEffects(argument) {
return Math.cos(argument);
Modified: trunk/JSTests/stress/arith-fround-on-various-types.js (204994 => 204995)
--- trunk/JSTests/stress/arith-fround-on-various-types.js 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/JSTests/stress/arith-fround-on-various-types.js 2016-08-25 23:02:52 UTC (rev 204995)
@@ -100,6 +100,29 @@
testSingleTypeCall();
+// Test Math.fround() on constants
+function testConstant() {
+ for (let testCaseInput of validInputTestCases) {
+ eval(`
+ function opaqueFroundOnConstant() {
+ return Math.fround(${testCaseInput[0]});
+ }
+ noInline(opaqueFroundOnConstant);
+ noOSRExitFuzzing(opaqueFroundOnConstant);
+
+ for (let i = 0; i < 1e4; ++i) {
+ if (!isIdentical(opaqueFroundOnConstant(), ${testCaseInput[1]})) {
+ throw "Failed testConstant()";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueFroundOnConstant) > 1)
+ throw "We should have compiled a single fround for the expected type.";
+ `);
+ }
+}
+testConstant();
+
+
// Verify we call valueOf() exactly once per call.
function opaqueFroundForSideEffects(argument) {
return Math.fround(argument);
Modified: trunk/JSTests/stress/arith-log-on-various-types.js (204994 => 204995)
--- trunk/JSTests/stress/arith-log-on-various-types.js 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/JSTests/stress/arith-log-on-various-types.js 2016-08-25 23:02:52 UTC (rev 204995)
@@ -37,6 +37,26 @@
}
+// Test Math.log() without arguments.
+function opaqueLogNoArgument() {
+ return Math.log();
+}
+noInline(opaqueLogNoArgument);
+noOSRExitFuzzing(opaqueLogNoArgument);
+
+function testNoArgument() {
+ for (let i = 0; i < 1e4; ++i) {
+ let output = opaqueLogNoArgument();
+ if (output === output) {
+ throw "Failed opaqueLogNoArgument";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueLogNoArgument) > 1)
+ throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
// Test Math.log() with a very polymorphic input. All test cases are seen at each iteration.
function opaqueAllTypesLog(argument) {
return Math.log(argument);
@@ -81,6 +101,29 @@
testSingleTypeCall();
+// Test Math.log() on constants
+function testConstant() {
+ for (let testCaseInput of validInputTestCases) {
+ eval(`
+ function opaqueLogOnConstant() {
+ return Math.log(${testCaseInput[0]});
+ }
+ noInline(opaqueLogOnConstant);
+ noOSRExitFuzzing(opaqueLogOnConstant);
+
+ for (let i = 0; i < 1e4; ++i) {
+ if (!isIdentical(opaqueLogOnConstant(), ${testCaseInput[1]})) {
+ throw "Failed testConstant()";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueLogOnConstant) > 1)
+ throw "We should have compiled a single log for the expected type.";
+ `);
+ }
+}
+testConstant();
+
+
// Verify we call valueOf() exactly once per call.
function opaqueLogForSideEffects(argument) {
return Math.log(argument);
Modified: trunk/JSTests/stress/arith-sin-on-various-types.js (204994 => 204995)
--- trunk/JSTests/stress/arith-sin-on-various-types.js 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/JSTests/stress/arith-sin-on-various-types.js 2016-08-25 23:02:52 UTC (rev 204995)
@@ -34,6 +34,26 @@
}
+// Test Math.sin() without arguments.
+function opaqueSinNoArgument() {
+ return Math.sin();
+}
+noInline(opaqueSinNoArgument);
+noOSRExitFuzzing(opaqueSinNoArgument);
+
+function testNoArgument() {
+ for (let i = 0; i < 1e4; ++i) {
+ let output = opaqueSinNoArgument();
+ if (output === output) {
+ throw "Failed opaqueSinNoArgument";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueSinNoArgument) > 1)
+ throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
// Test Math.sin() with a very polymorphic input. All test cases are seen at each iteration.
function opaqueAllTypesSin(argument) {
return Math.sin(argument);
@@ -78,6 +98,29 @@
testSingleTypeCall();
+// Test Math.sin() on constants
+function testConstant() {
+ for (let testCaseInput of validInputTestCases) {
+ eval(`
+ function opaqueSinOnConstant() {
+ return Math.sin(${testCaseInput[0]});
+ }
+ noInline(opaqueSinOnConstant);
+ noOSRExitFuzzing(opaqueSinOnConstant);
+
+ for (let i = 0; i < 1e4; ++i) {
+ if (!isIdentical(opaqueSinOnConstant(), ${testCaseInput[1]})) {
+ throw "Failed testConstant()";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueSinOnConstant) > 1)
+ throw "We should have compiled a single sin for the expected type.";
+ `);
+ }
+}
+testConstant();
+
+
// Verify we call valueOf() exactly once per call.
function opaqueSinForSideEffects(argument) {
return Math.sin(argument);
Modified: trunk/JSTests/stress/arith-sqrt-on-various-types.js (204994 => 204995)
--- trunk/JSTests/stress/arith-sqrt-on-various-types.js 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/JSTests/stress/arith-sqrt-on-various-types.js 2016-08-25 23:02:52 UTC (rev 204995)
@@ -32,6 +32,26 @@
}
+// Test Math.sqrt() without arguments.
+function opaqueSqrtNoArgument() {
+ return Math.sqrt();
+}
+noInline(opaqueSqrtNoArgument);
+noOSRExitFuzzing(opaqueSqrtNoArgument);
+
+function testNoArgument() {
+ for (let i = 0; i < 1e4; ++i) {
+ let output = opaqueSqrtNoArgument();
+ if (output === output) {
+ throw "Failed opaqueSqrtNoArgument";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueSqrtNoArgument) > 1)
+ throw "The call without arguments should never exit.";
+}
+testNoArgument();
+
+
// Test Math.sqrt() with a very polymorphic input. All test cases are seen at each iteration.
function opaqueAllTypesSqrt(argument) {
return Math.sqrt(argument);
@@ -76,6 +96,29 @@
testSingleTypeCall();
+// Test Math.sqrt() on constants
+function testConstant() {
+ for (let testCaseInput of validInputTestCases) {
+ eval(`
+ function opaqueSqrtOnConstant() {
+ return Math.sqrt(${testCaseInput[0]});
+ }
+ noInline(opaqueSqrtOnConstant);
+ noOSRExitFuzzing(opaqueSqrtOnConstant);
+
+ for (let i = 0; i < 1e4; ++i) {
+ if (!isIdentical(opaqueSqrtOnConstant(), ${testCaseInput[1]})) {
+ throw "Failed testConstant()";
+ }
+ }
+ if (numberOfDFGCompiles(opaqueSqrtOnConstant) > 1)
+ throw "We should have compiled a single sqrt for the expected type.";
+ `);
+ }
+}
+testConstant();
+
+
// Verify we call valueOf() exactly once per call.
function opaqueSqrtForSideEffects(argument) {
return Math.sqrt(argument);
Modified: trunk/Source/_javascript_Core/ChangeLog (204994 => 204995)
--- trunk/Source/_javascript_Core/ChangeLog 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-08-25 23:02:52 UTC (rev 204995)
@@ -1,3 +1,25 @@
+2016-08-25 Benjamin Poulain <bpoul...@apple.com>
+
+ [JSC] Clean up the abstract interpreter for cos/sin/sqrt/fround/log
+ https://bugs.webkit.org/show_bug.cgi?id=161181
+
+ Reviewed by Geoffrey Garen.
+
+ All the nodes are doing the exact same thing with a single
+ difference: how to process constants. I made that into a separate
+ function called from each node.
+
+ I also generalized the constant-to-number code of DoubleRep
+ to make it available for all those nodes.
+
+ * dfg/DFGAbstractInterpreter.h:
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeDoubleUnaryOpEffects):
+ * runtime/JSCJSValue.cpp:
+ (JSC::JSValue::toNumberFromPrimitive):
+ * runtime/JSCJSValue.h:
+
2016-08-25 Yusuke Suzuki <utatane....@gmail.com>
[DFG][FTL] Implement ES6 Generators in DFG / FTL
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h (204994 => 204995)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h 2016-08-25 23:02:52 UTC (rev 204995)
@@ -186,6 +186,7 @@
void verifyEdge(Node*, Edge);
void verifyEdges(Node*);
+ void executeDoubleUnaryOpEffects(Node*, double(*equivalentFunction)(double));
CodeBlock* m_codeBlock;
Graph& m_graph;
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (204994 => 204995)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-08-25 23:02:52 UTC (rev 204995)
@@ -433,23 +433,9 @@
case DoubleRep: {
JSValue child = forNode(node->child1()).value();
- if (child) {
- if (child.isNumber()) {
- setConstant(node, jsDoubleNumber(child.asNumber()));
- break;
- }
- if (child.isUndefined()) {
- setConstant(node, jsDoubleNumber(PNaN));
- break;
- }
- if (child.isNull() || child.isFalse()) {
- setConstant(node, jsDoubleNumber(0));
- break;
- }
- if (child.isTrue()) {
- setConstant(node, jsDoubleNumber(1));
- break;
- }
+ if (Optional<double> number = child.toNumberFromPrimitive()) {
+ setConstant(node, jsDoubleNumber(*number));
+ break;
}
SpeculatedType type = forNode(node->child1()).m_type;
@@ -955,70 +941,25 @@
break;
}
- case ArithSqrt: {
- JSValue child = forNode(node->child1()).value();
- if (child && child.isNumber()) {
- setConstant(node, jsDoubleNumber(sqrt(child.asNumber())));
- break;
- }
- SpeculatedType sqrtType = SpecFullNumber;
- if (node->child1().useKind() == DoubleRepUse)
- sqrtType = typeOfDoubleUnaryOp(forNode(node->child1()).m_type);
- forNode(node).setType(sqrtType);
+ case ArithSqrt:
+ executeDoubleUnaryOpEffects(node, sqrt);
break;
- }
-
- case ArithFRound: {
- JSValue child = forNode(node->child1()).value();
- if (child && child.isNumber()) {
- setConstant(node, jsDoubleNumber(static_cast<float>(child.asNumber())));
- break;
- }
- SpeculatedType froundType = SpecFullNumber;
- if (node->child1().useKind() == DoubleRepUse)
- froundType = typeOfDoubleUnaryOp(forNode(node->child1()).m_type);
- forNode(node).setType(froundType);
+
+ case ArithFRound:
+ executeDoubleUnaryOpEffects(node, [](double value) -> double { return static_cast<float>(value); });
break;
- }
- case ArithSin: {
- JSValue child = forNode(node->child1()).value();
- if (child && child.isNumber()) {
- setConstant(node, jsDoubleNumber(sin(child.asNumber())));
- break;
- }
- SpeculatedType sinType = SpecFullNumber;
- if (node->child1().useKind() == DoubleRepUse)
- sinType = typeOfDoubleUnaryOp(forNode(node->child1()).m_type);
- forNode(node).setType(sinType);
+ case ArithSin:
+ executeDoubleUnaryOpEffects(node, sin);
break;
- }
- case ArithCos: {
- JSValue child = forNode(node->child1()).value();
- if (child && child.isNumber()) {
- setConstant(node, jsDoubleNumber(cos(child.asNumber())));
- break;
- }
- SpeculatedType cosType = SpecFullNumber;
- if (node->child1().useKind() == DoubleRepUse)
- cosType = typeOfDoubleUnaryOp(forNode(node->child1()).m_type);
- forNode(node).setType(cosType);
+ case ArithCos:
+ executeDoubleUnaryOpEffects(node, cos);
break;
- }
- case ArithLog: {
- JSValue child = forNode(node->child1()).value();
- if (child && child.isNumber()) {
- setConstant(node, jsDoubleNumber(log(child.asNumber())));
- break;
- }
- SpeculatedType logType = SpecFullNumber;
- if (node->child1().useKind() == DoubleRepUse)
- logType = typeOfDoubleUnaryOp(forNode(node->child1()).m_type);
- forNode(node).setType(logType);
+ case ArithLog:
+ executeDoubleUnaryOpEffects(node, log);
break;
- }
case LogicalNot: {
switch (booleanResult(node, forNode(node->child1()))) {
@@ -3102,6 +3043,20 @@
return Contradiction;
}
+template<typename AbstractStateType>
+void AbstractInterpreter<AbstractStateType>::executeDoubleUnaryOpEffects(Node* node, double(*equivalentFunction)(double))
+{
+ JSValue child = forNode(node->child1()).value();
+ if (Optional<double> number = child.toNumberFromPrimitive()) {
+ setConstant(node, jsDoubleNumber(equivalentFunction(*number)));
+ return;
+ }
+ SpeculatedType type = SpecFullNumber;
+ if (node->child1().useKind() == DoubleRepUse)
+ type = typeOfDoubleUnaryOp(forNode(node->child1()).m_type);
+ forNode(node).setType(type);
+}
+
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
Modified: trunk/Source/_javascript_Core/runtime/JSCJSValue.cpp (204994 => 204995)
--- trunk/Source/_javascript_Core/runtime/JSCJSValue.cpp 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/Source/_javascript_Core/runtime/JSCJSValue.cpp 2016-08-25 23:02:52 UTC (rev 204995)
@@ -77,6 +77,21 @@
return isUndefined() ? PNaN : 0; // null and false both convert to 0.
}
+Optional<double> JSValue::toNumberFromPrimitive() const
+{
+ if (isEmpty())
+ return Nullopt;
+ if (isNumber())
+ return asNumber();
+ if (isBoolean())
+ return asBoolean();
+ if (isUndefined())
+ return PNaN;
+ if (isNull())
+ return 0;
+ return Nullopt;
+}
+
JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
{
ASSERT(!isCell());
Modified: trunk/Source/_javascript_Core/runtime/JSCJSValue.h (204994 => 204995)
--- trunk/Source/_javascript_Core/runtime/JSCJSValue.h 2016-08-25 22:55:10 UTC (rev 204994)
+++ trunk/Source/_javascript_Core/runtime/JSCJSValue.h 2016-08-25 23:02:52 UTC (rev 204995)
@@ -261,6 +261,10 @@
// toNumber conversion is expected to be side effect free if an exception has
// been set in the ExecState already.
double toNumber(ExecState*) const;
+
+ // toNumber conversion if it can be done without side effects.
+ Optional<double> toNumberFromPrimitive() const;
+
JSString* toString(ExecState*) const; // On exception, this returns the empty string.
JSString* toStringOrNull(ExecState*) const; // On exception, this returns null, to make exception checks faster.
Identifier toPropertyKey(ExecState*) const;