Diff
Modified: trunk/JSTests/ChangeLog (205063 => 205064)
--- trunk/JSTests/ChangeLog 2016-08-27 00:33:29 UTC (rev 205063)
+++ trunk/JSTests/ChangeLog 2016-08-27 00:36:15 UTC (rev 205064)
@@ -1,3 +1,12 @@
+2016-08-26 Benjamin Poulain <[email protected]>
+
+ [JSC] Implement CompareStrictEq(String, Untyped) in FTL
+ https://bugs.webkit.org/show_bug.cgi?id=161229
+
+ Reviewed by Geoffrey Garen.
+
+ * stress/compare-strict-eq-on-various-types.js: Added.
+
2016-08-26 Yusuke Suzuki <[email protected]>
[ES6] newPromiseCapabilities should check the given argument is constructor
Added: trunk/JSTests/stress/compare-strict-eq-on-various-types.js (0 => 205064)
--- trunk/JSTests/stress/compare-strict-eq-on-various-types.js (rev 0)
+++ trunk/JSTests/stress/compare-strict-eq-on-various-types.js 2016-08-27 00:36:15 UTC (rev 205064)
@@ -0,0 +1,240 @@
+"use strict";
+
+function opaqueKitString() {
+ return "Kit";
+}
+noInline(opaqueKitString);
+
+let someObject = new Object;
+let validInputTestCases = [
+ "undefined",
+ "Symbol(\"WebKit\")",
+ "null",
+ "true",
+ "false",
+ "0",
+ "{ valueOf: () => { return Math.E; } }",
+ "-0",
+ "42",
+ "-42",
+ "Math.PI",
+ "NaN",
+ "\"WebKit\"",
+ "\"Web\" + opaqueKitString()",
+ "new String(\"WebKit\")",
+ "someObject",
+ "validInputTestCases",
+];
+
+let leftCases = validInputTestCases.map((element) => { return eval("(" + element + ")"); });
+let rightCases = validInputTestCases.map((element) => { return eval("(" + element + ")"); });
+
+// Baseline results.
+let expectedEqualResults = [];
+let expectedNotEqualResults = [];
+for (let testCaseInputLeft of leftCases) {
+ let equalResultRow = [];
+ let notEqualResultRow = [];
+ for (let testCaseInputRight of rightCases) {
+ equalResultRow.push(testCaseInputLeft === testCaseInputRight);
+ notEqualResultRow.push(testCaseInputLeft !== testCaseInputRight);
+ }
+ expectedEqualResults.push(equalResultRow);
+ expectedNotEqualResults.push(notEqualResultRow);
+}
+
+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;
+}
+
+
+// Very polymorphic compare.
+function opaqueStrictEqualAllTypes(left, right) {
+ return left === right;
+}
+noInline(opaqueStrictEqualAllTypes);
+noOSRExitFuzzing(opaqueStrictEqualAllTypes);
+
+function opaqueStrictNotEqualAllTypes(left, right) {
+ return left !== right;
+}
+noInline(opaqueStrictNotEqualAllTypes);
+noOSRExitFuzzing(opaqueStrictNotEqualAllTypes);
+
+function testAllTypesCall() {
+ for (let i = 0; i < 1e3; ++i) {
+ for (let leftCaseIndex = 0; leftCaseIndex < leftCases.length; ++leftCaseIndex) {
+ for (let rightCaseIndex = 0; rightCaseIndex < rightCases.length; ++rightCaseIndex) {
+ let strictEqualOutput = opaqueStrictEqualAllTypes(leftCases[leftCaseIndex], rightCases[rightCaseIndex]);
+ if (!isIdentical(strictEqualOutput, expectedEqualResults[leftCaseIndex][rightCaseIndex])) {
+ throw "Failed testAllTypesCall for equality. Left = " +
+ leftCases[leftCaseIndex] +
+ ", Right = " +
+ rightCases[rightCaseIndex] +
+ ", Result = " +
+ strictEqualOutput;
+ }
+
+ let strictNotEqualOutput = opaqueStrictNotEqualAllTypes(leftCases[leftCaseIndex], rightCases[rightCaseIndex]);
+ if (!isIdentical(strictNotEqualOutput, expectedNotEqualResults[leftCaseIndex][rightCaseIndex])) {
+ throw "Failed testAllTypesCall for !equality. Left = " +
+ leftCases[leftCaseIndex] +
+ ", Right = " +
+ rightCases[rightCaseIndex] +
+ ", Result = " +
+ strictEqualOutput;
+ }
+ }
+ }
+ }
+ if (numberOfDFGCompiles(opaqueStrictEqualAllTypes) > 2)
+ throw "opaqueStrictEqualAllTypes() should have been quickly compiled as fully polymorphic.";
+ if (opaqueStrictNotEqualAllTypes(opaqueStrictEqualAllTypes) > 2)
+ throw "opaqueStrictEqualAllTypes() should have been quickly compiled as fully polymorphic.";
+}
+testAllTypesCall();
+
+
+// Comparing String to every type.
+function opaqueStrictEqualStringToAllTypes(left, right) {
+ return left === right;
+}
+noInline(opaqueStrictEqualStringToAllTypes);
+noOSRExitFuzzing(opaqueStrictEqualStringToAllTypes);
+
+function opaqueStrictEqualAllTypesToString(left, right) {
+ return left === right;
+}
+noInline(opaqueStrictEqualAllTypesToString);
+noOSRExitFuzzing(opaqueStrictEqualAllTypesToString);
+
+function opaqueStrictNotEqualStringToAllTypes(left, right) {
+ return left !== right;
+}
+noInline(opaqueStrictNotEqualStringToAllTypes);
+noOSRExitFuzzing(opaqueStrictNotEqualStringToAllTypes);
+
+function opaqueStrictNotEqualAllTypesToString(left, right) {
+ return left !== right;
+}
+noInline(opaqueStrictNotEqualAllTypesToString);
+noOSRExitFuzzing(opaqueStrictNotEqualAllTypesToString);
+
+function testStringToAllCompare() {
+ const leftStringIndex = leftCases.indexOf("WebKit");
+ for (let i = 0; i < 1e3; ++i) {
+ for (let rightCaseIndex = 0; rightCaseIndex < rightCases.length; ++rightCaseIndex) {
+ let rightCase = rightCases[rightCaseIndex];
+ let strictEqualOutput = opaqueStrictEqualStringToAllTypes("Web" + opaqueKitString(), rightCase);
+ if (!isIdentical(strictEqualOutput, expectedEqualResults[leftStringIndex][rightCaseIndex])) {
+ throw "Failed opaqueStrictEqualStringToAllTypes() with right = " + rightCase;
+ }
+ let strictNotEqualOutput = opaqueStrictNotEqualStringToAllTypes("Web" + opaqueKitString(), rightCase);
+ if (!isIdentical(strictNotEqualOutput, expectedNotEqualResults[leftStringIndex][rightCaseIndex])) {
+ throw "Failed opaqueStrictNotEqualStringToAllTypes() with right = " + rightCase;
+ }
+ }
+ }
+
+ const rightStringIndex = leftCases.lastIndexOf("WebKit");
+ for (let i = 0; i < 1e3; ++i) {
+ for (let leftCaseIndex = 0; leftCaseIndex < leftCases.length; ++leftCaseIndex) {
+ let leftCase = leftCases[leftCaseIndex];
+ let strictEqualOutput = opaqueStrictEqualAllTypesToString(leftCase, "Web" + opaqueKitString());
+ if (!isIdentical(strictEqualOutput, expectedEqualResults[leftCaseIndex][rightStringIndex])) {
+ throw "Failed opaqueStrictEqualAllTypesToString() with left = " + leftCase;
+ }
+ let strictNotEqualOutput = opaqueStrictNotEqualAllTypesToString(leftCase, "Web" + opaqueKitString());
+ if (!isIdentical(strictNotEqualOutput, expectedNotEqualResults[leftCaseIndex][rightStringIndex])) {
+ throw "Failed opaqueStrictNotEqualAllTypesToString() with left = " + leftCase;
+ }
+ }
+ }
+
+ if (numberOfDFGCompiles(opaqueStrictEqualStringToAllTypes) > 2)
+ throw "opaqueStrictEqualStringToAllTypes() should quickly converge its types.";
+ if (numberOfDFGCompiles(opaqueStrictEqualAllTypesToString) > 2)
+ throw "opaqueStrictEqualAllTypesToString() should quickly converge its types.";
+ if (numberOfDFGCompiles(opaqueStrictNotEqualStringToAllTypes) > 2)
+ throw "opaqueStrictNotEqualStringToAllTypes() should quickly converge its types.";
+ if (numberOfDFGCompiles(opaqueStrictNotEqualAllTypesToString) > 2)
+ throw "opaqueStrictNotEqualAllTypesToString() should quickly converge its types.";
+}
+testStringToAllCompare();
+
+
+// Compare one type to all the others.
+function compareOneTypeToAll() {
+ for (let leftCaseIndex = 0; leftCaseIndex < validInputTestCases.length; ++leftCaseIndex) {
+ let leftCase = validInputTestCases[leftCaseIndex];
+ eval(`
+ function opaqueStrictEqualOneTypeToAll(left, right) {
+ return left === right;
+ }
+ noInline(opaqueStrictEqualOneTypeToAll);
+ noOSRExitFuzzing(opaqueStrictEqualOneTypeToAll);
+
+ function opaqueStrictNotEqualOneTypeToAll(left, right) {
+ return left !== right;
+ }
+ noInline(opaqueStrictNotEqualOneTypeToAll);
+ noOSRExitFuzzing(opaqueStrictNotEqualOneTypeToAll);
+
+ for (let i = 0; i < 1e3; ++i) {
+ for (let rightCaseIndex = 0; rightCaseIndex < rightCases.length; ++rightCaseIndex) {
+ let strictEqualOutput = opaqueStrictEqualOneTypeToAll(${leftCase}, rightCases[rightCaseIndex]);
+ if (!isIdentical(strictEqualOutput, expectedEqualResults[${leftCaseIndex}][rightCaseIndex])) {
+ throw "Failed opaqueStrictEqualOneTypeToAll() with left case = " + ${leftCase} + ", right case = " + rightCases[rightCaseIndex];
+ }
+ let strictNotEqualOutput = opaqueStrictNotEqualOneTypeToAll(${leftCase}, rightCases[rightCaseIndex]);
+ if (!isIdentical(strictNotEqualOutput, expectedNotEqualResults[${leftCaseIndex}][rightCaseIndex])) {
+ throw "Failed opaqueStrictNotEqualOneTypeToAll() with left case = " + ${leftCase} + ", right case = " + rightCases[rightCaseIndex];
+ }
+ }
+ }
+ `);
+ }
+}
+compareOneTypeToAll();
+
+function compareAllTypesToOne() {
+ for (let rightCaseIndex = 0; rightCaseIndex < validInputTestCases.length; ++rightCaseIndex) {
+ let rightCase = validInputTestCases[rightCaseIndex];
+ eval(`
+ function opaqueStrictEqualAllToOne(left, right) {
+ return left === right;
+ }
+ noInline(opaqueStrictEqualAllToOne);
+ noOSRExitFuzzing(opaqueStrictEqualAllToOne);
+
+ function opaqueStrictNotEqualAllToOne(left, right) {
+ return left !== right;
+ }
+ noInline(opaqueStrictNotEqualAllToOne);
+ noOSRExitFuzzing(opaqueStrictNotEqualAllToOne);
+
+ for (let i = 0; i < 1e3; ++i) {
+ for (let leftCaseIndex = 0; leftCaseIndex < leftCases.length; ++leftCaseIndex) {
+ let strictEqualOutput = opaqueStrictEqualAllToOne(leftCases[leftCaseIndex], ${rightCase});
+ if (!isIdentical(strictEqualOutput, expectedEqualResults[leftCaseIndex][${rightCaseIndex}])) {
+ throw "Failed opaqueStrictEqualAllToOne() with left case = " + leftCases[leftCaseIndex] + ", right case = " + ${rightCase};
+ }
+ let strictNotEqualOutput = opaqueStrictNotEqualAllToOne(leftCases[leftCaseIndex], ${rightCase});
+ if (!isIdentical(strictNotEqualOutput, expectedNotEqualResults[leftCaseIndex][${rightCaseIndex}])) {
+ throw "Failed opaqueStrictNotEqualAllToOne() with left case = " + leftCases[leftCaseIndex] + ", right case = " + ${rightCase};
+ }
+ }
+ }
+ `);
+ }
+}
+compareAllTypesToOne();
Modified: trunk/Source/_javascript_Core/ChangeLog (205063 => 205064)
--- trunk/Source/_javascript_Core/ChangeLog 2016-08-27 00:33:29 UTC (rev 205063)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-08-27 00:36:15 UTC (rev 205064)
@@ -1,3 +1,23 @@
+2016-08-26 Benjamin Poulain <[email protected]>
+
+ [JSC] Implement CompareStrictEq(String, Untyped) in FTL
+ https://bugs.webkit.org/show_bug.cgi?id=161229
+
+ Reviewed by Geoffrey Garen.
+
+ Add (String, Untyped) uses to FTL CompareStrictEq.
+ This was the last use type not implemented, the node is fully
+ supported by FTL after this patch.
+
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+ (JSC::FTL::DFG::LowerDFGToB3::compileStringToUntypedStrictEquality):
+
+ (JSC::FTL::DFG::LowerDFGToB3::nonSpeculativeCompare):
+ Remove the type checks when possible.
+
2016-08-26 Johan K. Jensen <[email protected]>
Web Inspector: Frontend should have access to Resource Timing information
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (205063 => 205064)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-08-27 00:33:29 UTC (rev 205063)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-08-27 00:36:15 UTC (rev 205064)
@@ -246,6 +246,7 @@
case GetDynamicVar:
case PutDynamicVar:
case CompareEqPtr:
+ case CompareStrictEq:
// These are OK.
break;
@@ -388,42 +389,6 @@
if (node->child1().useKind() == OtherUse || node->child2().useKind() == OtherUse)
break;
return CannotCompile;
- case CompareStrictEq:
- if (node->isBinaryUseKind(Int32Use))
- break;
- if (node->isBinaryUseKind(Int52RepUse))
- break;
- if (node->isBinaryUseKind(DoubleRepUse))
- break;
- if (node->isBinaryUseKind(StringIdentUse))
- break;
- if (node->isBinaryUseKind(StringUse))
- break;
- if (node->isBinaryUseKind(ObjectUse, UntypedUse))
- break;
- if (node->isBinaryUseKind(UntypedUse, ObjectUse))
- break;
- if (node->isBinaryUseKind(ObjectUse))
- break;
- if (node->isBinaryUseKind(BooleanUse))
- break;
- if (node->isBinaryUseKind(UntypedUse))
- break;
- if (node->isBinaryUseKind(SymbolUse))
- break;
- if (node->isBinaryUseKind(SymbolUse, UntypedUse))
- break;
- if (node->isBinaryUseKind(UntypedUse, SymbolUse))
- break;
- if (node->isBinaryUseKind(MiscUse, UntypedUse))
- break;
- if (node->isBinaryUseKind(UntypedUse, MiscUse))
- break;
- if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse))
- break;
- if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
- break;
- return CannotCompile;
case CompareLess:
case CompareLessEq:
case CompareGreater:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (205063 => 205064)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-08-27 00:33:29 UTC (rev 205063)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-08-27 00:36:15 UTC (rev 205064)
@@ -5102,15 +5102,6 @@
return;
}
- if (m_node->isBinaryUseKind(UntypedUse)) {
- nonSpeculativeCompare(
- [&] (LValue left, LValue right) {
- return m_out.equal(left, right);
- },
- operationCompareStrictEq);
- return;
- }
-
if (m_node->isBinaryUseKind(SymbolUse)) {
LValue leftSymbol = lowSymbol(m_node->child1());
LValue rightSymbol = lowSymbol(m_node->child2());
@@ -5175,10 +5166,63 @@
setBoolean(m_out.phi(Int32, notCellResult, notStringResult, isStringResult));
return;
}
-
- DFG_CRASH(m_graph, m_node, "Bad use kinds");
+
+ if (m_node->isBinaryUseKind(StringUse, UntypedUse)) {
+ compileStringToUntypedStrictEquality(m_node->child1(), m_node->child2());
+ return;
+ }
+ if (m_node->isBinaryUseKind(UntypedUse, StringUse)) {
+ compileStringToUntypedStrictEquality(m_node->child2(), m_node->child1());
+ return;
+ }
+
+ DFG_ASSERT(m_graph, m_node, m_node->isBinaryUseKind(UntypedUse));
+ nonSpeculativeCompare(
+ [&] (LValue left, LValue right) {
+ return m_out.equal(left, right);
+ },
+ operationCompareStrictEq);
}
-
+
+ void compileStringToUntypedStrictEquality(Edge stringEdge, Edge untypedEdge)
+ {
+ ASSERT(stringEdge.useKind() == StringUse);
+ ASSERT(untypedEdge.useKind() == UntypedUse);
+
+ LValue leftString = lowCell(stringEdge);
+ LValue rightValue = lowJSValue(untypedEdge);
+ SpeculatedType rightValueType = provenType(untypedEdge);
+
+ // Verify left is string.
+ speculateString(stringEdge, leftString);
+
+ LBasicBlock testUntypedEdgeIsCell = m_out.newBlock();
+ LBasicBlock testUntypedEdgeIsString = m_out.newBlock();
+ LBasicBlock testStringEquality = m_out.newBlock();
+ LBasicBlock continuation = m_out.newBlock();
+
+ // Given left is string. If the value are strictly equal, rightValue has to be the same string.
+ ValueFromBlock fastTrue = m_out.anchor(m_out.booleanTrue);
+ m_out.branch(m_out.equal(leftString, rightValue), unsure(continuation), unsure(testUntypedEdgeIsCell));
+
+ LBasicBlock lastNext = m_out.appendTo(testUntypedEdgeIsCell, testUntypedEdgeIsString);
+ ValueFromBlock fastFalse = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(isNotCell(rightValue, rightValueType), unsure(continuation), unsure(testUntypedEdgeIsString));
+
+ // Check if the untyped edge is a string.
+ m_out.appendTo(testUntypedEdgeIsString, testStringEquality);
+ m_out.branch(isNotString(rightValue, rightValueType), unsure(continuation), unsure(testStringEquality));
+
+ // Full String compare.
+ m_out.appendTo(testStringEquality, continuation);
+ ValueFromBlock slowResult = m_out.anchor(stringsEqual(leftString, rightValue));
+ m_out.jump(continuation);
+
+ // Continuation.
+ m_out.appendTo(continuation, lastNext);
+ setBoolean(m_out.phi(Int32, fastTrue, fastFalse, slowResult));
+ }
+
void compileCompareEqPtr()
{
setBoolean(
@@ -8142,10 +8186,10 @@
LBasicBlock slowPath = m_out.newBlock();
LBasicBlock continuation = m_out.newBlock();
- m_out.branch(isNotInt32(left), rarely(slowPath), usually(leftIsInt));
+ m_out.branch(isNotInt32(left, provenType(m_node->child1())), rarely(slowPath), usually(leftIsInt));
LBasicBlock lastNext = m_out.appendTo(leftIsInt, fastPath);
- m_out.branch(isNotInt32(right), rarely(slowPath), usually(fastPath));
+ m_out.branch(isNotInt32(right, provenType(m_node->child2())), rarely(slowPath), usually(fastPath));
m_out.appendTo(fastPath, slowPath);
ValueFromBlock fastResult = m_out.anchor(intFunctor(unboxInt32(left), unboxInt32(right)));