DFG and FTL should specialize for and support CompareStrictEq over Misc (i.e. boolean, undefined, or null)
https://bugs.webkit.org/show_bug.cgi?id=129563
Source/JavaScriptCore:
Reviewed by Geoffrey Garen.
Rolling this back in after fixing an assertion failure. speculateMisc() should have
said DFG_TYPE_CHECK instead of typeCheck.
This adds a specialization of CompareStrictEq over Misc. I noticed the need for this
when I saw that we didn't support CompareStrictEq(Untyped) in FTL but that the main
user of this was EarleyBoyer, and in that benchmark what it was really doing was
comparing undefined, null, and booleans to each other.
This also adds support for miscellaneous things that I needed to make my various test
cases work. This includes comparison over booleans and the various Throw-related node
types.
This also improves constant folding of CompareStrictEq and CompareEq.
Also found a bug where we were claiming that GetByVals on typed arrays are OutOfBounds
based on profiling, which caused some downstream badness. We don't actually support
compiling OutOfBounds GetByVals on typed arrays. The DFG would ignore the flag and just
emit a bounds check, but in the FTL path, the SSA lowering phase would assume that it
shouldn't factor out the bounds check since the access is not InBounds but then the
backend would ignore the flag and assume that the bounds check was already emitted.
This showed up on an existing test but I added a test for this explicitly to have more
certain coverage. The fix is to not mark something as OutOfBounds if the semantics are
that we'll have a bounds check anyway.
This is a 1% speed-up on Octane mostly because of raytrace, but also because of just
general progressions across the board. No speed-up yet on EarleyBoyer, since there is
still a lot more coverage work to be done there.
* bytecode/SpeculatedType.cpp:
(JSC::speculationToAbbreviatedString):
(JSC::leastUpperBoundOfStrictlyEquivalentSpeculations):
(JSC::valuesCouldBeEqual):
* bytecode/SpeculatedType.h:
(JSC::isMiscSpeculation):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::refine):
* dfg/DFGArrayMode.h:
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::attemptToMakeGetArrayLength):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateMisc):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileStrictEq):
(JSC::DFG::SpeculativeJIT::speculateMisc):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileMiscStrictEq):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileMiscStrictEq):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileCompareEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
(JSC::FTL::LowerDFGToLLVM::compileThrow):
(JSC::FTL::LowerDFGToLLVM::isNotMisc):
(JSC::FTL::LowerDFGToLLVM::isMisc):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateMisc):
* tests/stress/float32-array-out-of-bounds.js: Added.
* tests/stress/weird-equality-folding-cases.js: Added.
LayoutTests:
Reviewed by Geoffrey Garen.
* js/regress/fold-strict-eq-expected.txt: Added.
* js/regress/fold-strict-eq.html: Added.
* js/regress/misc-strict-eq-expected.txt: Added.
* js/regress/misc-strict-eq.html: Added.
* js/regress/script-tests/fold-strict-eq.js: Added.
(foo):
(test):
* js/regress/script-tests/misc-strict-eq.js: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@165099 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index b174615..bc11456 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,19 @@
+2014-03-04 Filip Pizlo <fpizlo@apple.com>
+
+ DFG and FTL should specialize for and support CompareStrictEq over Misc (i.e. boolean, undefined, or null)
+ https://bugs.webkit.org/show_bug.cgi?id=129563
+
+ Reviewed by Geoffrey Garen.
+
+ * js/regress/fold-strict-eq-expected.txt: Added.
+ * js/regress/fold-strict-eq.html: Added.
+ * js/regress/misc-strict-eq-expected.txt: Added.
+ * js/regress/misc-strict-eq.html: Added.
+ * js/regress/script-tests/fold-strict-eq.js: Added.
+ (foo):
+ (test):
+ * js/regress/script-tests/misc-strict-eq.js: Added.
+
2014-03-04 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r165085.
diff --git a/LayoutTests/js/regress/fold-strict-eq-expected.txt b/LayoutTests/js/regress/fold-strict-eq-expected.txt
new file mode 100644
index 0000000..b66c610
--- /dev/null
+++ b/LayoutTests/js/regress/fold-strict-eq-expected.txt
@@ -0,0 +1,10 @@
+JSRegress/fold-strict-eq
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/fold-strict-eq.html b/LayoutTests/js/regress/fold-strict-eq.html
new file mode 100644
index 0000000..9c262aa
--- /dev/null
+++ b/LayoutTests/js/regress/fold-strict-eq.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/fold-strict-eq.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/misc-strict-eq-expected.txt b/LayoutTests/js/regress/misc-strict-eq-expected.txt
new file mode 100644
index 0000000..b47c309
--- /dev/null
+++ b/LayoutTests/js/regress/misc-strict-eq-expected.txt
@@ -0,0 +1,10 @@
+JSRegress/misc-strict-eq
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/misc-strict-eq.html b/LayoutTests/js/regress/misc-strict-eq.html
new file mode 100644
index 0000000..883c695
--- /dev/null
+++ b/LayoutTests/js/regress/misc-strict-eq.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/misc-strict-eq.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/fold-strict-eq.js b/LayoutTests/js/regress/script-tests/fold-strict-eq.js
new file mode 100644
index 0000000..0d83e66
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/fold-strict-eq.js
@@ -0,0 +1,16 @@
+function foo(a, b) {
+ return a === b;
+}
+
+function test(actual, expected) {
+ if (actual !== expected)
+ throw new Error("bad result: " + actual);
+}
+
+for (var i = 0; i < 10000000; ++i) {
+ test(foo(true, null), false);
+ test(foo(true, false), false);
+ test(foo(true, true), true);
+ test(foo(5, "hello"), false);
+ test(foo(void 0, new Object()), false);
+}
diff --git a/LayoutTests/js/regress/script-tests/misc-strict-eq.js b/LayoutTests/js/regress/script-tests/misc-strict-eq.js
new file mode 100644
index 0000000..05913d3
--- /dev/null
+++ b/LayoutTests/js/regress/script-tests/misc-strict-eq.js
@@ -0,0 +1,13 @@
+(function() {
+ var array = [true, false, null, void 0];
+ for (var i = 0; i < 1000000; ++i) {
+ for (var j = 0; j < array.length; ++j) {
+ for (var k = j ; k < array.length; ++k) {
+ var actual = array[j] === array[k];
+ var expected = j == k;
+ if (actual != expected)
+ throw "Error: bad result for j = " + j + ", k = " + k;
+ }
+ }
+ }
+})();
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index db27faf..50d161f 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,83 @@
+2014-03-04 Filip Pizlo <fpizlo@apple.com>
+
+ DFG and FTL should specialize for and support CompareStrictEq over Misc (i.e. boolean, undefined, or null)
+ https://bugs.webkit.org/show_bug.cgi?id=129563
+
+ Reviewed by Geoffrey Garen.
+
+ Rolling this back in after fixing an assertion failure. speculateMisc() should have
+ said DFG_TYPE_CHECK instead of typeCheck.
+
+ This adds a specialization of CompareStrictEq over Misc. I noticed the need for this
+ when I saw that we didn't support CompareStrictEq(Untyped) in FTL but that the main
+ user of this was EarleyBoyer, and in that benchmark what it was really doing was
+ comparing undefined, null, and booleans to each other.
+
+ This also adds support for miscellaneous things that I needed to make my various test
+ cases work. This includes comparison over booleans and the various Throw-related node
+ types.
+
+ This also improves constant folding of CompareStrictEq and CompareEq.
+
+ Also found a bug where we were claiming that GetByVals on typed arrays are OutOfBounds
+ based on profiling, which caused some downstream badness. We don't actually support
+ compiling OutOfBounds GetByVals on typed arrays. The DFG would ignore the flag and just
+ emit a bounds check, but in the FTL path, the SSA lowering phase would assume that it
+ shouldn't factor out the bounds check since the access is not InBounds but then the
+ backend would ignore the flag and assume that the bounds check was already emitted.
+ This showed up on an existing test but I added a test for this explicitly to have more
+ certain coverage. The fix is to not mark something as OutOfBounds if the semantics are
+ that we'll have a bounds check anyway.
+
+ This is a 1% speed-up on Octane mostly because of raytrace, but also because of just
+ general progressions across the board. No speed-up yet on EarleyBoyer, since there is
+ still a lot more coverage work to be done there.
+
+ * bytecode/SpeculatedType.cpp:
+ (JSC::speculationToAbbreviatedString):
+ (JSC::leastUpperBoundOfStrictlyEquivalentSpeculations):
+ (JSC::valuesCouldBeEqual):
+ * bytecode/SpeculatedType.h:
+ (JSC::isMiscSpeculation):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGArrayMode.cpp:
+ (JSC::DFG::ArrayMode::refine):
+ * dfg/DFGArrayMode.h:
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ (JSC::DFG::FixupPhase::attemptToMakeGetArrayLength):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::shouldSpeculateMisc):
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::SafeToExecuteEdge::operator()):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileStrictEq):
+ (JSC::DFG::SpeculativeJIT::speculateMisc):
+ (JSC::DFG::SpeculativeJIT::speculate):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compileMiscStrictEq):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compileMiscStrictEq):
+ * dfg/DFGUseKind.cpp:
+ (WTF::printInternal):
+ * dfg/DFGUseKind.h:
+ (JSC::DFG::typeFilterFor):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileNode):
+ (JSC::FTL::LowerDFGToLLVM::compileCompareEq):
+ (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
+ (JSC::FTL::LowerDFGToLLVM::compileThrow):
+ (JSC::FTL::LowerDFGToLLVM::isNotMisc):
+ (JSC::FTL::LowerDFGToLLVM::isMisc):
+ (JSC::FTL::LowerDFGToLLVM::speculate):
+ (JSC::FTL::LowerDFGToLLVM::speculateMisc):
+ * tests/stress/float32-array-out-of-bounds.js: Added.
+ * tests/stress/weird-equality-folding-cases.js: Added.
+
2014-03-04 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r165085.
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
index aca45b7..041eb1c 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
@@ -255,6 +255,8 @@
return "<Boolean>";
if (isOtherSpeculation(prediction))
return "<Other>";
+ if (isMiscSpeculation(prediction))
+ return "<Misc>";
return "";
}
@@ -391,5 +393,40 @@
return NotTypedArray;
}
+SpeculatedType leastUpperBoundOfStrictlyEquivalentSpeculations(SpeculatedType type)
+{
+ if (type & SpecInteger)
+ type |= SpecInteger;
+ if (type & SpecString)
+ type |= SpecString;
+ return type;
+}
+
+bool valuesCouldBeEqual(SpeculatedType a, SpeculatedType b)
+{
+ a = leastUpperBoundOfStrictlyEquivalentSpeculations(a);
+ b = leastUpperBoundOfStrictlyEquivalentSpeculations(b);
+
+ // Anything could be equal to a string.
+ if (a & SpecString)
+ return true;
+ if (b & SpecString)
+ return true;
+
+ // If both sides are definitely only objects, then equality is fairly sane.
+ if (isObjectSpeculation(a) && isObjectSpeculation(b))
+ return !!(a & b);
+
+ // If either side could be an object or not, then we could call toString or
+ // valueOf, which could return anything.
+ if (a & SpecObject)
+ return true;
+ if (b & SpecObject)
+ return true;
+
+ // Neither side is an object or string, so the world is relatively sane.
+ return !!(a & b);
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h
index eaf0af3..b280690 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.h
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h
@@ -75,7 +75,8 @@
static const SpeculatedType SpecBytecodeNumber = 0x0e800000; // It's either an Int32 or a Double.
static const SpeculatedType SpecFullNumber = 0x0f800000; // It's either an Int32, Int52, or a Double.
static const SpeculatedType SpecBoolean = 0x10000000; // It's definitely a Boolean.
-static const SpeculatedType SpecOther = 0x20000000; // It's definitely none of the above.
+static const SpeculatedType SpecOther = 0x20000000; // It's definitely either Null or Undefined.
+static const SpeculatedType SpecMisc = 0x30000000; // It's definitely either a boolean, Null, or Undefined.
static const SpeculatedType SpecHeapTop = 0x3effffff; // It can be any of the above, except for SpecInt52.
static const SpeculatedType SpecEmpty = 0x40000000; // It's definitely an empty value marker.
static const SpeculatedType SpecBytecodeTop = 0x7effffff; // It can be any of the above, except for SpecInt52.
@@ -335,6 +336,11 @@
return value == SpecOther;
}
+inline bool isMiscSpeculation(SpeculatedType value)
+{
+ return !!value && !(value & ~SpecMisc);
+}
+
inline bool isOtherOrEmptySpeculation(SpeculatedType value)
{
return !value || value == SpecOther;
@@ -382,6 +388,10 @@
SpeculatedType speculationFromTypedArrayType(TypedArrayType); // only valid for typed views.
TypedArrayType typedArrayTypeFromSpeculation(SpeculatedType);
+SpeculatedType leastUpperBoundOfStrictlyEquivalentSpeculations(SpeculatedType);
+
+bool valuesCouldBeEqual(SpeculatedType, SpeculatedType);
+
} // namespace JSC
#endif // SpeculatedType_h
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 32ed82f..dbf88ff 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -917,8 +917,7 @@
if (node->op() == CompareEqConstant || node->op() == CompareEq) {
SpeculatedType leftType = forNode(node->child1()).m_type;
SpeculatedType rightType = forNode(node->child2()).m_type;
- if ((isInt32Speculation(leftType) && isOtherSpeculation(rightType))
- || (isOtherSpeculation(leftType) && isInt32Speculation(rightType))) {
+ if (!valuesCouldBeEqual(leftType, rightType)) {
setConstant(node, jsBoolean(false));
break;
}
@@ -943,19 +942,28 @@
JSValue left = forNode(leftNode).value();
JSValue right = forNode(rightNode).value();
if (left && right) {
- if (left.isNumber() && right.isNumber()) {
- setConstant(node, jsBoolean(left.asNumber() == right.asNumber()));
- break;
- }
if (left.isString() && right.isString()) {
+ // We need this case because JSValue::strictEqual is otherwise too racy for
+ // string comparisons.
const StringImpl* a = asString(left)->tryGetValueImpl();
const StringImpl* b = asString(right)->tryGetValueImpl();
if (a && b) {
setConstant(node, jsBoolean(WTF::equal(a, b)));
break;
}
+ } else {
+ setConstant(node, jsBoolean(JSValue::strictEqual(0, left, right)));
+ break;
}
}
+
+ SpeculatedType leftLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode).m_type);
+ SpeculatedType rightLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode).m_type);
+ if (!(leftLUB & rightLUB)) {
+ setConstant(node, jsBoolean(false));
+ break;
+ }
+
forNode(node).setType(SpecBoolean);
node->setCanExit(true); // This is overly conservative.
break;
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
index 1dd9f31..9a93980 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -132,7 +132,7 @@
}
ArrayMode ArrayMode::refine(
- Graph& graph, CodeOrigin codeOrigin,
+ Graph& graph, Node* node,
SpeculatedType base, SpeculatedType index, SpeculatedType value,
NodeFlags flags) const
{
@@ -199,10 +199,18 @@
return withType(Array::Arguments);
ArrayMode result;
- if (graph.hasExitSite(codeOrigin, OutOfBounds) || !isInBounds())
- result = withSpeculation(Array::OutOfBounds);
- else
+ switch (node->op()) {
+ case PutByVal:
+ if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
+ result = withSpeculation(Array::OutOfBounds);
+ else
+ result = withSpeculation(Array::InBounds);
+ break;
+
+ default:
result = withSpeculation(Array::InBounds);
+ break;
+ }
if (isInt8ArraySpeculation(base))
return result.withType(Array::Int8Array);
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h
index add9215..9c67edb 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.h
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -220,7 +220,7 @@
return ArrayMode(type, arrayClass(), speculation(), conversion);
}
- ArrayMode refine(Graph&, CodeOrigin, SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone, NodeFlags = 0) const;
+ ArrayMode refine(Graph&, Node*, SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone, NodeFlags = 0) const;
bool alreadyChecked(Graph&, Node*, AbstractValue&) const;
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index b90c317..5c0aa42 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -432,6 +432,11 @@
fixEdge<ObjectUse>(node->child2());
break;
}
+ if (node->child1()->shouldSpeculateMisc() && node->child2()->shouldSpeculateMisc()) {
+ fixEdge<MiscUse>(node->child1());
+ fixEdge<MiscUse>(node->child2());
+ break;
+ }
break;
}
@@ -452,7 +457,7 @@
case GetByVal: {
node->setArrayMode(
node->arrayMode().refine(
- m_graph, node->origin.semantic,
+ m_graph, node,
node->child1()->prediction(),
node->child2()->prediction(),
SpecNone, node->flags()));
@@ -510,7 +515,7 @@
node->setArrayMode(
node->arrayMode().refine(
- m_graph, node->origin.semantic,
+ m_graph, node,
child1->prediction(),
child2->prediction(),
child3->prediction()));
@@ -596,7 +601,7 @@
// that would break things.
node->setArrayMode(
node->arrayMode().refine(
- m_graph, node->origin.semantic,
+ m_graph, node,
node->child1()->prediction() & SpecCell,
SpecInt32,
node->child2()->prediction()));
@@ -1750,7 +1755,7 @@
}
arrayMode = arrayMode.refine(
- m_graph, node->origin.semantic, node->child1()->prediction(), node->prediction());
+ m_graph, node, node->child1()->prediction(), node->prediction());
if (arrayMode.type() == Array::Generic) {
// Check if the input is something that we can't get array length for, but for which we
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 690f1f5..b5b9590 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -1399,6 +1399,11 @@
{
return isBooleanSpeculation(prediction());
}
+
+ bool shouldSpeculateMisc()
+ {
+ return isMiscSpeculation(prediction());
+ }
bool shouldSpeculateStringIdent()
{
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 1bc1fbc..06c0d40 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -59,6 +59,7 @@
case StringOrStringObjectUse:
case NotCellUse:
case OtherUse:
+ case MiscUse:
case MachineIntUse:
return;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 417e760..2641fbb 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -3802,6 +3802,11 @@
return false;
}
+ case MiscUse: {
+ compileMiscStrictEq(node);
+ return false;
+ }
+
case UntypedUse: {
return nonSpeculativeStrictEq(node);
}
@@ -4830,6 +4835,31 @@
#endif
}
+void SpeculativeJIT::speculateMisc(Edge edge, JSValueRegs regs)
+{
+#if USE(JSVALUE64)
+ DFG_TYPE_CHECK(
+ regs, edge, SpecMisc,
+ m_jit.branch64(MacroAssembler::Above, regs.gpr(), MacroAssembler::TrustedImm64(TagBitTypeOther | TagBitBool | TagBitUndefined)));
+#else
+ DFG_TYPE_CHECK(
+ regs, edge, SpecMisc | SpecInt32,
+ m_jit.branch32(MacroAssembler::Equal, regs.tagGPR(), MacroAssembler::TrustedImm32(JSValue::Int32Tag)));
+ DFG_TYPE_CHECK(
+ regs, edge, SpecMisc,
+ m_jit.branch32(MacroAssembler::Below, regs.tagGPR(), MacroAssembler::TrustedImm32(JSValue::UndefinedTag)));
+#endif
+}
+
+void SpeculativeJIT::speculateMisc(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecMisc))
+ return;
+
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+ speculateMisc(edge, operand.jsValueRegs());
+}
+
void SpeculativeJIT::speculate(Node*, Edge edge)
{
switch (edge.useKind()) {
@@ -4892,6 +4922,9 @@
case OtherUse:
speculateOther(edge);
break;
+ case MiscUse:
+ speculateMisc(edge);
+ break;
default:
RELEASE_ASSERT_NOT_REACHED();
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 391d1ed..df4f96d 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1985,6 +1985,7 @@
void compileStringEquality(Node*);
void compileStringIdentEquality(Node*);
void compileStringZeroLength(Node*);
+ void compileMiscStrictEq(Node*);
void emitObjectOrOtherBranch(Edge value, BasicBlock* taken, BasicBlock* notTaken);
void emitBranch(Node*);
@@ -2203,6 +2204,8 @@
void speculateStringOrStringObject(Edge);
void speculateNotCell(Edge);
void speculateOther(Edge);
+ void speculateMisc(Edge, JSValueRegs);
+ void speculateMisc(Edge);
void speculate(Node*, Edge);
JITCompiler::Jump jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, IndexingType);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 1cf356c..9e0097a 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -613,6 +613,22 @@
booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
}
+void SpeculativeJIT::compileMiscStrictEq(Node* node)
+{
+ JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
+ JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
+ GPRTemporary result(this);
+
+ speculateMisc(node->child1(), op1.jsValueRegs());
+ speculateMisc(node->child2(), op2.jsValueRegs());
+
+ m_jit.move(TrustedImm32(0), result.gpr());
+ JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, op1.tagGPR(), op2.tagGPR());
+ m_jit.compare32(JITCompiler::Equal, op1.payloadGPR(), op2.payloadGPR(), result.gpr());
+ notEqual.link(&m_jit);
+ booleanResult(result.gpr(), node);
+}
+
void SpeculativeJIT::emitCall(Node* node)
{
if (node->op() != Call)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 475b4db..c3c95db 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -648,6 +648,20 @@
jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean, UseChildrenCalledExplicitly);
}
+void SpeculativeJIT::compileMiscStrictEq(Node* node)
+{
+ JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
+ JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
+ GPRTemporary result(this);
+
+ speculateMisc(node->child1(), op1.jsValueRegs());
+ speculateMisc(node->child2(), op2.jsValueRegs());
+
+ m_jit.compare32(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr());
+ m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+ jsValueResult(result.gpr(), node, DataFormatJSBoolean);
+}
+
void SpeculativeJIT::emitCall(Node* node)
{
if (node->op() != Call)
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.cpp b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
index 4e6df98..b7a5c6f 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.cpp
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -97,6 +97,9 @@
case OtherUse:
out.print("Other");
break;
+ case MiscUse:
+ out.print("Misc");
+ break;
default:
RELEASE_ASSERT_NOT_REACHED();
break;
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.h b/Source/JavaScriptCore/dfg/DFGUseKind.h
index dfa82ee..f66d143 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.h
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -54,6 +54,7 @@
StringOrStringObjectUse,
NotCellUse,
OtherUse,
+ MiscUse,
LastUseKind // Must always be the last entry in the enum, as it is used to denote the number of enum elements.
};
@@ -96,6 +97,8 @@
return ~SpecCell;
case OtherUse:
return SpecOther;
+ case MiscUse:
+ return SpecMisc;
default:
RELEASE_ASSERT_NOT_REACHED();
return SpecFullTop;
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index 435c032..b7ee25c 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -141,6 +141,9 @@
case MultiPutByOffset:
case ToPrimitive:
case PhantomArguments:
+ case Throw:
+ case ThrowReferenceError:
+ case Unreachable:
case GetMyArgumentByVal:
// These are OK.
break;
@@ -233,6 +236,8 @@
break;
if (node->isBinaryUseKind(UntypedUse))
break;
+ if (node->isBinaryUseKind(BooleanUse))
+ break;
if (node->child1().useKind() == ObjectUse
&& node->child2().useKind() == ObjectOrOtherUse)
break;
@@ -249,6 +254,10 @@
break;
if (node->isBinaryUseKind(ObjectUse))
break;
+ if (node->isBinaryUseKind(MiscUse))
+ break;
+ if (node->isBinaryUseKind(BooleanUse))
+ break;
return CannotCompile;
case CompareLess:
case CompareLessEq:
@@ -341,6 +350,7 @@
case StringOrStringObjectUse:
case FinalObjectUse:
case NotCellUse:
+ case MiscUse:
// These are OK.
break;
default:
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index 31c38e3..9756dbb 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -559,6 +559,10 @@
case ForceOSRExit:
compileForceOSRExit();
break;
+ case Throw:
+ case ThrowReferenceError:
+ compileThrow();
+ break;
case InvalidationPoint:
compileInvalidationPoint();
break;
@@ -592,6 +596,9 @@
case TypedArrayWatchpoint:
case AllocationProfileWatchpoint:
break;
+ case Unreachable:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
default:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -3362,7 +3369,8 @@
if (m_node->isBinaryUseKind(Int32Use)
|| m_node->isBinaryUseKind(MachineIntUse)
|| m_node->isBinaryUseKind(NumberUse)
- || m_node->isBinaryUseKind(ObjectUse)) {
+ || m_node->isBinaryUseKind(ObjectUse)
+ || m_node->isBinaryUseKind(BooleanUse)) {
compileCompareStrictEq();
return;
}
@@ -3425,6 +3433,21 @@
return;
}
+ if (m_node->isBinaryUseKind(BooleanUse)) {
+ setBoolean(
+ m_out.equal(lowBoolean(m_node->child1()), lowBoolean(m_node->child2())));
+ return;
+ }
+
+ if (m_node->isBinaryUseKind(MiscUse)) {
+ LValue left = lowJSValue(m_node->child1(), ManualOperandSpeculation);
+ LValue right = lowJSValue(m_node->child2(), ManualOperandSpeculation);
+ FTL_TYPE_CHECK(jsValueValue(left), m_node->child1(), SpecMisc, isNotMisc(left));
+ FTL_TYPE_CHECK(jsValueValue(right), m_node->child2(), SpecMisc, isNotMisc(right));
+ setBoolean(m_out.equal(left, right));
+ return;
+ }
+
RELEASE_ASSERT_NOT_REACHED();
}
@@ -3691,6 +3714,11 @@
terminate(InadequateCoverage);
}
+ void compileThrow()
+ {
+ terminate(Uncountable);
+ }
+
void compileInvalidationPoint()
{
if (verboseCompilationEnabled())
@@ -4963,6 +4991,16 @@
return m_out.testIsZero64(jsValue, m_tagMask);
}
+ LValue isNotMisc(LValue value)
+ {
+ return m_out.above(value, m_out.constInt64(TagBitTypeOther | TagBitBool | TagBitUndefined));
+ }
+
+ LValue isMisc(LValue value)
+ {
+ return m_out.bitNot(isNotMisc(value));
+ }
+
LValue isNotBoolean(LValue jsValue)
{
return m_out.testNonZero64(
@@ -5046,6 +5084,9 @@
case NotCellUse:
speculateNotCell(edge);
break;
+ case MiscUse:
+ speculateMisc(edge);
+ break;
default:
dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
RELEASE_ASSERT_NOT_REACHED();
@@ -5323,6 +5364,15 @@
typeCheck(jsValueValue(value), edge, ~SpecCell, isCell(value));
}
+ void speculateMisc(Edge edge)
+ {
+ if (!m_interpreter.needsTypeCheck(edge))
+ return;
+
+ LValue value = lowJSValue(edge);
+ typeCheck(jsValueValue(value), edge, SpecMisc, isNotMisc(value));
+ }
+
bool masqueradesAsUndefinedWatchpointIsStillValid()
{
return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->origin.semantic);
diff --git a/Source/JavaScriptCore/tests/stress/float32-array-out-of-bounds.js b/Source/JavaScriptCore/tests/stress/float32-array-out-of-bounds.js
new file mode 100644
index 0000000..b50765d
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/float32-array-out-of-bounds.js
@@ -0,0 +1,23 @@
+function foo(a) {
+ return a[42];
+}
+
+noInline(foo);
+
+var shortArray = new Float32Array(10);
+var longArray = new Float32Array(100);
+
+function test(array, expected) {
+ var result = foo(array);
+ if (result != expected)
+ throw new Error("bad result: " + result);
+}
+
+for (var i = 0; i < 1000; ++i)
+ test(shortArray, void 0);
+
+for (var i = 0; i < 100000; ++i)
+ test(longArray, 0);
+
+test(shortArray, void 0);
+
diff --git a/Source/JavaScriptCore/tests/stress/weird-equality-folding-cases.js b/Source/JavaScriptCore/tests/stress/weird-equality-folding-cases.js
new file mode 100644
index 0000000..d2c618e
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/weird-equality-folding-cases.js
@@ -0,0 +1,13 @@
+function test(actualFunction, expected) {
+ var actual = actualFunction();
+ if (actual != expected)
+ throw new Error("bad in " + actualFunction + " result: " + actual);
+}
+
+noInline(test);
+
+for (var i = 0; i < 10000; ++i) {
+ test(function() { return "5" == 5; }, true);
+ test(function() { return ({valueOf:function(){return 42;}}) == 42; }, true);
+ test(function() { return ({valueOf:function(){return 42;}}) == ({valueOf:function(){return 42;}}) }, false);
+}