Bug 1073576 - Optimize strict compares with equal operands. r=h4writer
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/strict-compare-same-operands.js
@@ -0,0 +1,49 @@
+function f(l, m) {
+ var a = NaN;
+ var b = 13;
+ var c = "test";
+ var d = undefined;
+ var e = null;
+ var f = 15.7;
+ var g = Math.fround(189777.111);
+ var h = "ABC";
+ var i = String.fromCharCode(65, 65, 65);
+ var j = {};
+ var k = Math.fround("".charCodeAt(15));
+
+ // Special case rigt here:
+ assertEq(a === a, false);
+ assertEq(a !== a, true);
+ assertEq(k === k, false);
+ assertEq(k !== k, true);
+ assertEq(l === l, false);
+ assertEq(l !== l, true);
+
+ assertEq(b === b, true);
+ assertEq(b !== b, false);
+ assertEq(c === c, true);
+ assertEq(c !== c, false);
+ assertEq(d === d, true);
+ assertEq(d !== d, false);
+ assertEq(e === e, true);
+ assertEq(e !== e, false);
+ assertEq(f === f, true);
+ assertEq(f !== f, false);
+ assertEq(g === g, true);
+ assertEq(g !== g, false);
+ assertEq(h === h, true);
+ assertEq(h !== h, false);
+ assertEq(i === i, true);
+ assertEq(i !== i, false);
+ assertEq(j === j, true);
+ assertEq(j !== j, false);
+ assertEq(m === m, true);
+ assertEq(m !== m, false);
+}
+
+function test() {
+ for (var i = 0; i < 100; i++)
+ f("".charCodeAt(15), 42);
+}
+
+test();
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2834,20 +2834,59 @@ MClampToUint8::foldsTo(TempAllocator &al
int32_t clamped = ClampIntForUint8Array(v.toInt32());
return MConstant::New(alloc, Int32Value(clamped));
}
}
return this;
}
bool
+MCompare::tryFoldEqualOperands(bool *result)
+{
+ if (lhs() != rhs())
+ return false;
+
+ // Intuitively somebody would think that if lhs == rhs,
+ // then we can just return true. (Or false for !==)
+ // However NaN !== NaN is true! So we spend some time trying
+ // to eliminate this case.
+
+ if (jsop() != JSOP_STRICTEQ && jsop() != JSOP_STRICTNE)
+ return false;
+
+ if (compareType_ == Compare_Unknown)
+ return false;
+
+ MOZ_ASSERT(compareType_ == Compare_Undefined || compareType_ == Compare_Null ||
+ compareType_ == Compare_Boolean || compareType_ == Compare_Int32 ||
+ compareType_ == Compare_Int32MaybeCoerceBoth ||
+ compareType_ == Compare_Int32MaybeCoerceLHS ||
+ compareType_ == Compare_Int32MaybeCoerceRHS || compareType_ == Compare_UInt32 ||
+ compareType_ == Compare_Double || compareType_ == Compare_DoubleMaybeCoerceLHS ||
+ compareType_ == Compare_DoubleMaybeCoerceRHS || compareType_ == Compare_Float32 ||
+ compareType_ == Compare_String || compareType_ == Compare_StrictString ||
+ compareType_ == Compare_Object || compareType_ == Compare_Value);
+
+ if (isDoubleComparison() || isFloat32Comparison()) {
+ if (!operandsAreNeverNaN())
+ return false;
+ }
+
+ *result = (jsop() == JSOP_STRICTEQ);
+ return true;
+}
+
+bool
MCompare::tryFold(bool *result)
{
JSOp op = jsop();
+ if (tryFoldEqualOperands(result))
+ return true;
+
if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
MOZ_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ ||
op == JSOP_NE || op == JSOP_STRICTNE);
// The LHS is the value we want to test against null or undefined.
switch (lhs()->type()) {
case MIRType_Value:
return false;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3468,16 +3468,18 @@ class MCompare
// Both sides of the compare can be Float32
return compareType_ == Compare_Float32;
}
# endif
ALLOW_CLONE(MCompare)
protected:
+ bool tryFoldEqualOperands(bool *result);
+
bool congruentTo(const MDefinition *ins) const {
if (!binaryCongruentTo(ins))
return false;
return compareType() == ins->toCompare()->compareType() &&
jsop() == ins->toCompare()->jsop();
}
};