From 08c1b4df42fd9c25c9762fe2f973e8513097c8ed Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Sun, 5 Oct 2014 15:26:40 +0200 Subject: [PATCH] Bug 1073576 - Optimize strict compares with equal operands. r=h4writer --- .../basic/strict-compare-same-operands.js | 49 +++++++++++++++++++ js/src/jit/MIR.cpp | 39 +++++++++++++++ js/src/jit/MIR.h | 2 + 3 files changed, 90 insertions(+) create mode 100644 js/src/jit-test/tests/basic/strict-compare-same-operands.js diff --git a/js/src/jit-test/tests/basic/strict-compare-same-operands.js b/js/src/jit-test/tests/basic/strict-compare-same-operands.js new file mode 100644 index 00000000000..57ca425054c --- /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(); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 5fadc1ec105..7140c0c15d0 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2838,11 +2838,50 @@ MClampToUint8::foldsTo(TempAllocator &alloc) 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); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index bdce5ef6c65..c7ab3a3dd86 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -3473,6 +3473,8 @@ class MCompare ALLOW_CLONE(MCompare) protected: + bool tryFoldEqualOperands(bool *result); + bool congruentTo(const MDefinition *ins) const { if (!binaryCongruentTo(ins)) return false;