[DFG] Introduces fused compare and jump
https://bugs.webkit.org/show_bug.cgi?id=177100

Reviewed by Mark Lam.

JSTests:

* stress/fused-jeq-slow.js: Added.
(shouldBe):
(testJEQ):
(testJNEQB):
(testJEQB):
(testJNEQF):
(testJEQF):
* stress/fused-jeq.js: Added.
(shouldBe):
(testJEQ):
(testJNEQB):
(testJEQB):
(testJNEQF):
(testJEQF):
* stress/fused-jstricteq-slow.js: Added.
(shouldBe):
(testJSTRICTEQ):
(testJNSTRICTEQB):
(testJSTRICTEQB):
(testJNSTRICTEQF):
(testJSTRICTEQF):
* stress/fused-jstricteq.js: Added.
(shouldBe):
(testJSTRICTEQ):
(testJNSTRICTEQB):
(testJSTRICTEQB):
(testJNSTRICTEQF):
(testJSTRICTEQF):

Source/JavaScriptCore:

This patch introduces op_jeq, op_jneq, op_jstricteq, and op_jnstricteq.
It offers 3 benefit.

1. They are introduced due to the similar purpose to op_jless etc. It aligns
op_eq families to op_jless families.

2. It reduces the size of bytecode to represent the typical code sequence.

3. It offers the way to fuse check and jump in DFG code generation. Since
we have MovHint between Branch and CompareEq/CompareStrictEq previously,
we cannot do this optimization. It reduces the machine code size in DFG too.

It slightly improves Octane/boyer.

    boyer  6.18038+-0.05002    ^     6.06990+-0.04176       ^ definitely 1.0182x faster

* bytecode/BytecodeDumper.cpp:
(JSC::BytecodeDumper<Block>::dumpBytecode):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/Opcode.h:
(JSC::isBranch):
* bytecode/PreciseJumpTargetsInlines.h:
(JSC::extractStoredJumpTargetsForBytecodeOffset):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitJumpIfTrue):
(JSC::BytecodeGenerator::emitJumpIfFalse):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileStrictEq):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_jeq):
(JSC::JIT::emit_op_neq):
(JSC::JIT::emit_op_jneq):
(JSC::JIT::compileOpStrictEq):
(JSC::JIT::emit_op_stricteq):
(JSC::JIT::emit_op_nstricteq):
(JSC::JIT::compileOpStrictEqJump):
(JSC::JIT::emit_op_jstricteq):
(JSC::JIT::emit_op_jnstricteq):
(JSC::JIT::emitSlow_op_jstricteq):
(JSC::JIT::emitSlow_op_jnstricteq):
(JSC::JIT::emitSlow_op_jeq):
(JSC::JIT::emitSlow_op_jneq):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emitSlow_op_eq):
(JSC::JIT::emit_op_jeq):
(JSC::JIT::compileOpEqJumpSlow):
(JSC::JIT::emitSlow_op_jeq):
(JSC::JIT::emit_op_jneq):
(JSC::JIT::emitSlow_op_jneq):
(JSC::JIT::compileOpStrictEq):
(JSC::JIT::emit_op_stricteq):
(JSC::JIT::emit_op_nstricteq):
(JSC::JIT::compileOpStrictEqJump):
(JSC::JIT::emit_op_jstricteq):
(JSC::JIT::emit_op_jnstricteq):
(JSC::JIT::emitSlow_op_jstricteq):
(JSC::JIT::emitSlow_op_jnstricteq):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@229957 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index dcae489..62482a2 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,5 +1,41 @@
 2018-03-22  Yusuke Suzuki  <utatane.tea@gmail.com>
 
+        [DFG] Introduces fused compare and jump
+        https://bugs.webkit.org/show_bug.cgi?id=177100
+
+        Reviewed by Mark Lam.
+
+        * stress/fused-jeq-slow.js: Added.
+        (shouldBe):
+        (testJEQ):
+        (testJNEQB):
+        (testJEQB):
+        (testJNEQF):
+        (testJEQF):
+        * stress/fused-jeq.js: Added.
+        (shouldBe):
+        (testJEQ):
+        (testJNEQB):
+        (testJEQB):
+        (testJNEQF):
+        (testJEQF):
+        * stress/fused-jstricteq-slow.js: Added.
+        (shouldBe):
+        (testJSTRICTEQ):
+        (testJNSTRICTEQB):
+        (testJSTRICTEQB):
+        (testJNSTRICTEQF):
+        (testJSTRICTEQF):
+        * stress/fused-jstricteq.js: Added.
+        (shouldBe):
+        (testJSTRICTEQ):
+        (testJNSTRICTEQB):
+        (testJSTRICTEQB):
+        (testJNSTRICTEQF):
+        (testJSTRICTEQF):
+
+2018-03-22  Yusuke Suzuki  <utatane.tea@gmail.com>
+
         [JSC] Clear MustGenerate for ToString(Number) converted from NumberToStringWithRadix
         https://bugs.webkit.org/show_bug.cgi?id=183559
 
diff --git a/JSTests/stress/fused-jeq-slow.js b/JSTests/stress/fused-jeq-slow.js
new file mode 100644
index 0000000..8b34b3d
--- /dev/null
+++ b/JSTests/stress/fused-jeq-slow.js
@@ -0,0 +1,91 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)} ${String(expected)}`);
+}
+
+function testJNEQ(a, b)
+{
+    if (a == b) {
+        return 42;
+    }
+    return 30;
+}
+noInline(testJNEQ);
+
+function testJEQ(a, b)
+{
+    if (a != b) {
+        return 42;
+    }
+    return 30;
+}
+noInline(testJEQ);
+
+function testJNEQB(a, b)
+{
+    var i = 0;
+    do {
+        ++i;
+    } while (!(a == b));
+    return i;
+}
+noInline(testJNEQB);
+
+function testJEQB(a, b)
+{
+    var i = 0;
+    do {
+        ++i;
+    } while (!(a != b));
+    return i;
+}
+noInline(testJEQB);
+
+function testJNEQF(a, b)
+{
+    var i = 0;
+    while (!(a == b))
+        ++i;
+    return i;
+}
+noInline(testJNEQF);
+
+function testJEQF(a, b)
+{
+    var i = 0;
+    while (!(a != b))
+        ++i;
+    return i;
+}
+noInline(testJEQF);
+
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(testJNEQ('hello', 'world'), 30);
+    shouldBe(testJEQ('hello', 'world'), 42);
+    shouldBe(testJNEQ('world', 'world'), 42);
+    shouldBe(testJEQ('world', 'world'), 30);
+    shouldBe(testJNEQ(20.5, 'world'), 30);
+    shouldBe(testJEQ(20.5, 'world'), 42);
+
+    shouldBe(testJNEQ(20.5, 21.3), 30);
+    shouldBe(testJEQ(20.5, 21.3), 42);
+    shouldBe(testJNEQ(20.5, 20.5), 42);
+    shouldBe(testJEQ(20.5, 20.5), 30);
+
+    shouldBe(testJNEQB(0, 0), 1);
+    shouldBe(testJEQB(0, 1), 1);
+    shouldBe(testJNEQB('hello', 'hello'), 1);
+    shouldBe(testJEQB('hello', 'world'), 1);
+    shouldBe(testJNEQB(20.4, 20.4), 1);
+    shouldBe(testJEQB('hello', 20.4), 1);
+    shouldBe(testJNEQB(0, -0), 1);
+
+    shouldBe(testJNEQF(0, 0), 0);
+    shouldBe(testJEQF(0, 1), 0);
+    shouldBe(testJNEQF(20.4, 20.4), 0);
+    shouldBe(testJEQF(20.4, 10.5), 0);
+    shouldBe(testJNEQF(0, -0), 0);
+    shouldBe(testJEQF('hello', 10.5), 0);
+    shouldBe(testJNEQF('hello', 'hello'), 0);
+    shouldBe(testJEQF('hello', 'world'), 0);
+}
diff --git a/JSTests/stress/fused-jeq.js b/JSTests/stress/fused-jeq.js
new file mode 100644
index 0000000..234bf2d
--- /dev/null
+++ b/JSTests/stress/fused-jeq.js
@@ -0,0 +1,69 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)} ${String(expected)}`);
+}
+
+function testJNEQ(a, b)
+{
+    if (a == b) {
+        return 42;
+    }
+    return 30;
+}
+noInline(testJNEQ);
+
+function testJEQ(a, b)
+{
+    if (a != b) {
+        return 42;
+    }
+    return 30;
+}
+noInline(testJEQ);
+
+function testJNEQB(a, b)
+{
+    var i = 0;
+    do {
+        ++i;
+    } while (!(a == b));
+    return i;
+}
+noInline(testJNEQB);
+
+function testJEQB(a, b)
+{
+    var i = 0;
+    do {
+        ++i;
+    } while (!(a != b));
+    return i;
+}
+noInline(testJEQB);
+
+function testJNEQF(a, b)
+{
+    var i = 0;
+    while (!(a == b))
+        ++i;
+    return i;
+}
+noInline(testJNEQF);
+
+function testJEQF(a, b)
+{
+    var i = 0;
+    while (!(a != b))
+        ++i;
+    return i;
+}
+noInline(testJEQF);
+
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(testJNEQ(0, 42), 30);
+    shouldBe(testJEQ(0, 42), 42);
+    shouldBe(testJNEQB(0, 0), 1);
+    shouldBe(testJEQB(0, 1), 1);
+    shouldBe(testJNEQF(0, 0), 0);
+    shouldBe(testJEQF(0, 1), 0);
+}
diff --git a/JSTests/stress/fused-jstricteq-slow.js b/JSTests/stress/fused-jstricteq-slow.js
new file mode 100644
index 0000000..3b321fe
--- /dev/null
+++ b/JSTests/stress/fused-jstricteq-slow.js
@@ -0,0 +1,91 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)} ${String(expected)}`);
+}
+
+function testJNSTRICTEQ(a, b)
+{
+    if (a === b) {
+        return 42;
+    }
+    return 30;
+}
+noInline(testJNSTRICTEQ);
+
+function testJSTRICTEQ(a, b)
+{
+    if (a !== b) {
+        return 42;
+    }
+    return 30;
+}
+noInline(testJSTRICTEQ);
+
+function testJNSTRICTEQB(a, b)
+{
+    var i = 0;
+    do {
+        ++i;
+    } while (!(a === b));
+    return i;
+}
+noInline(testJNSTRICTEQB);
+
+function testJSTRICTEQB(a, b)
+{
+    var i = 0;
+    do {
+        ++i;
+    } while (!(a !== b));
+    return i;
+}
+noInline(testJSTRICTEQB);
+
+function testJNSTRICTEQF(a, b)
+{
+    var i = 0;
+    while (!(a === b))
+        ++i;
+    return i;
+}
+noInline(testJNSTRICTEQF);
+
+function testJSTRICTEQF(a, b)
+{
+    var i = 0;
+    while (!(a !== b))
+        ++i;
+    return i;
+}
+noInline(testJSTRICTEQF);
+
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(testJNSTRICTEQ('hello', 'world'), 30);
+    shouldBe(testJSTRICTEQ('hello', 'world'), 42);
+    shouldBe(testJNSTRICTEQ('world', 'world'), 42);
+    shouldBe(testJSTRICTEQ('world', 'world'), 30);
+    shouldBe(testJNSTRICTEQ(20.5, 'world'), 30);
+    shouldBe(testJSTRICTEQ(20.5, 'world'), 42);
+
+    shouldBe(testJNSTRICTEQ(20.5, 21.3), 30);
+    shouldBe(testJSTRICTEQ(20.5, 21.3), 42);
+    shouldBe(testJNSTRICTEQ(20.5, 20.5), 42);
+    shouldBe(testJSTRICTEQ(20.5, 20.5), 30);
+
+    shouldBe(testJNSTRICTEQB(0, 0), 1);
+    shouldBe(testJSTRICTEQB(0, 1), 1);
+    shouldBe(testJNSTRICTEQB('hello', 'hello'), 1);
+    shouldBe(testJSTRICTEQB('hello', 'world'), 1);
+    shouldBe(testJNSTRICTEQB(20.4, 20.4), 1);
+    shouldBe(testJSTRICTEQB('hello', 20.4), 1);
+    shouldBe(testJNSTRICTEQB(0, -0), 1);
+
+    shouldBe(testJNSTRICTEQF(0, 0), 0);
+    shouldBe(testJSTRICTEQF(0, 1), 0);
+    shouldBe(testJNSTRICTEQF(20.4, 20.4), 0);
+    shouldBe(testJSTRICTEQF(20.4, 10.5), 0);
+    shouldBe(testJNSTRICTEQF(0, -0), 0);
+    shouldBe(testJSTRICTEQF('hello', 10.5), 0);
+    shouldBe(testJNSTRICTEQF('hello', 'hello'), 0);
+    shouldBe(testJSTRICTEQF('hello', 'world'), 0);
+}
diff --git a/JSTests/stress/fused-jstricteq.js b/JSTests/stress/fused-jstricteq.js
new file mode 100644
index 0000000..3e8fe6c
--- /dev/null
+++ b/JSTests/stress/fused-jstricteq.js
@@ -0,0 +1,69 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)} ${String(expected)}`);
+}
+
+function testJNSTRICTEQ(a, b)
+{
+    if (a === b) {
+        return 42;
+    }
+    return 30;
+}
+noInline(testJNSTRICTEQ);
+
+function testJSTRICTEQ(a, b)
+{
+    if (a !== b) {
+        return 42;
+    }
+    return 30;
+}
+noInline(testJSTRICTEQ);
+
+function testJNSTRICTEQB(a, b)
+{
+    var i = 0;
+    do {
+        ++i;
+    } while (!(a === b));
+    return i;
+}
+noInline(testJNSTRICTEQB);
+
+function testJSTRICTEQB(a, b)
+{
+    var i = 0;
+    do {
+        ++i;
+    } while (!(a !== b));
+    return i;
+}
+noInline(testJSTRICTEQB);
+
+function testJNSTRICTEQF(a, b)
+{
+    var i = 0;
+    while (!(a === b))
+        ++i;
+    return i;
+}
+noInline(testJNSTRICTEQF);
+
+function testJSTRICTEQF(a, b)
+{
+    var i = 0;
+    while (!(a !== b))
+        ++i;
+    return i;
+}
+noInline(testJSTRICTEQF);
+
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(testJNSTRICTEQ(0, 42), 30);
+    shouldBe(testJSTRICTEQ(0, 42), 42);
+    shouldBe(testJNSTRICTEQB(0, 0), 1);
+    shouldBe(testJSTRICTEQB(0, 1), 1);
+    shouldBe(testJNSTRICTEQF(0, 0), 0);
+    shouldBe(testJSTRICTEQF(0, 1), 0);
+}
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 3d32a00..090d1bc 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,89 @@
+2018-03-22  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG] Introduces fused compare and jump
+        https://bugs.webkit.org/show_bug.cgi?id=177100
+
+        Reviewed by Mark Lam.
+
+        This patch introduces op_jeq, op_jneq, op_jstricteq, and op_jnstricteq.
+        It offers 3 benefit.
+
+        1. They are introduced due to the similar purpose to op_jless etc. It aligns
+        op_eq families to op_jless families.
+
+        2. It reduces the size of bytecode to represent the typical code sequence.
+
+        3. It offers the way to fuse check and jump in DFG code generation. Since
+        we have MovHint between Branch and CompareEq/CompareStrictEq previously,
+        we cannot do this optimization. It reduces the machine code size in DFG too.
+
+        It slightly improves Octane/boyer.
+
+            boyer  6.18038+-0.05002    ^     6.06990+-0.04176       ^ definitely 1.0182x faster
+
+        * bytecode/BytecodeDumper.cpp:
+        (JSC::BytecodeDumper<Block>::dumpBytecode):
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/Opcode.h:
+        (JSC::isBranch):
+        * bytecode/PreciseJumpTargetsInlines.h:
+        (JSC::extractStoredJumpTargetsForBytecodeOffset):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitJumpIfTrue):
+        (JSC::BytecodeGenerator::emitJumpIfFalse):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileStrictEq):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_jeq):
+        (JSC::JIT::emit_op_neq):
+        (JSC::JIT::emit_op_jneq):
+        (JSC::JIT::compileOpStrictEq):
+        (JSC::JIT::emit_op_stricteq):
+        (JSC::JIT::emit_op_nstricteq):
+        (JSC::JIT::compileOpStrictEqJump):
+        (JSC::JIT::emit_op_jstricteq):
+        (JSC::JIT::emit_op_jnstricteq):
+        (JSC::JIT::emitSlow_op_jstricteq):
+        (JSC::JIT::emitSlow_op_jnstricteq):
+        (JSC::JIT::emitSlow_op_jeq):
+        (JSC::JIT::emitSlow_op_jneq):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emitSlow_op_eq):
+        (JSC::JIT::emit_op_jeq):
+        (JSC::JIT::compileOpEqJumpSlow):
+        (JSC::JIT::emitSlow_op_jeq):
+        (JSC::JIT::emit_op_jneq):
+        (JSC::JIT::emitSlow_op_jneq):
+        (JSC::JIT::compileOpStrictEq):
+        (JSC::JIT::emit_op_stricteq):
+        (JSC::JIT::emit_op_nstricteq):
+        (JSC::JIT::compileOpStrictEqJump):
+        (JSC::JIT::emit_op_jstricteq):
+        (JSC::JIT::emit_op_jnstricteq):
+        (JSC::JIT::emitSlow_op_jstricteq):
+        (JSC::JIT::emitSlow_op_jnstricteq):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+
 2018-03-24  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] Improve constants and add comments for CodeBlockHash
diff --git a/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp b/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
index 3cef4b4..b655efe 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
+++ b/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
@@ -1250,6 +1250,22 @@
         printCompareJump(out, begin, it, location, "jngreatereq");
         break;
     }
+    case op_jeq: {
+        printCompareJump(out, begin, it, location, "jeq");
+        break;
+    }
+    case op_jneq: {
+        printCompareJump(out, begin, it, location, "jneq");
+        break;
+    }
+    case op_jstricteq: {
+        printCompareJump(out, begin, it, location, "jstricteq");
+        break;
+    }
+    case op_jnstricteq: {
+        printCompareJump(out, begin, it, location, "jnstricteq");
+        break;
+    }
     case op_jbelow: {
         printCompareJump(out, begin, it, location, "jbelow");
         break;
diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.json b/Source/JavaScriptCore/bytecode/BytecodeList.json
index a156d54..ff302ac 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeList.json
+++ b/Source/JavaScriptCore/bytecode/BytecodeList.json
@@ -109,6 +109,10 @@
             { "name" : "op_jeq_null", "length" : 3 },
             { "name" : "op_jneq_null", "length" : 3 },
             { "name" : "op_jneq_ptr", "length" : 5 },
+            { "name" : "op_jeq", "length" : 4 },
+            { "name" : "op_jstricteq", "length" : 4 },
+            { "name" : "op_jneq", "length" : 4 },
+            { "name" : "op_jnstricteq", "length" : 4 },
             { "name" : "op_jless", "length" : 4 },
             { "name" : "op_jlesseq", "length" : 4 },
             { "name" : "op_jgreater", "length" : 4 },
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
index 71c2a28..b250def 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
@@ -85,6 +85,10 @@
     case op_jngreater:
     case op_jngreatereq:
     case op_jless:
+    case op_jeq:
+    case op_jneq:
+    case op_jstricteq:
+    case op_jnstricteq:
     case op_jbelow:
     case op_jbeloweq:
     case op_set_function_name:
@@ -347,6 +351,10 @@
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_jeq:
+    case op_jneq:
+    case op_jstricteq:
+    case op_jnstricteq:
     case op_jbelow:
     case op_jbeloweq:
     case op_loop_hint:
diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h
index 758d340..07d9a73 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.h
+++ b/Source/JavaScriptCore/bytecode/Opcode.h
@@ -151,6 +151,10 @@
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_jeq:
+    case op_jneq:
+    case op_jstricteq:
+    case op_jnstricteq:
     case op_jbelow:
     case op_jbeloweq:
     case op_switch_imm:
diff --git a/Source/JavaScriptCore/bytecode/PreciseJumpTargetsInlines.h b/Source/JavaScriptCore/bytecode/PreciseJumpTargetsInlines.h
index 36725f9..070fde9 100644
--- a/Source/JavaScriptCore/bytecode/PreciseJumpTargetsInlines.h
+++ b/Source/JavaScriptCore/bytecode/PreciseJumpTargetsInlines.h
@@ -55,6 +55,10 @@
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_jeq:
+    case op_jneq:
+    case op_jstricteq:
+    case op_jnstricteq:
     case op_jbelow:
     case op_jbeloweq:
         function(current[3].u.operand);
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 1448ede..97eb3bb 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -1397,6 +1397,18 @@
     } else if (m_lastOpcodeID == op_greatereq) {
         if (fuseCompareAndJump(op_jgreatereq))
             return;
+    } else if (m_lastOpcodeID == op_eq) {
+        if (fuseCompareAndJump(op_jeq))
+            return;
+    } else if (m_lastOpcodeID == op_stricteq) {
+        if (fuseCompareAndJump(op_jstricteq))
+            return;
+    } else if (m_lastOpcodeID == op_neq) {
+        if (fuseCompareAndJump(op_jneq))
+            return;
+    } else if (m_lastOpcodeID == op_nstricteq) {
+        if (fuseCompareAndJump(op_jnstricteq))
+            return;
     } else if (m_lastOpcodeID == op_below) {
         if (fuseCompareAndJump(op_jbelow))
             return;
@@ -1479,6 +1491,18 @@
     } else if (m_lastOpcodeID == op_greatereq && target.isForward()) {
         if (fuseCompareAndJump(op_jngreatereq, false))
             return;
+    } else if (m_lastOpcodeID == op_eq && target.isForward()) {
+        if (fuseCompareAndJump(op_jneq, false))
+            return;
+    } else if (m_lastOpcodeID == op_stricteq && target.isForward()) {
+        if (fuseCompareAndJump(op_jnstricteq, false))
+            return;
+    } else if (m_lastOpcodeID == op_neq && target.isForward()) {
+        if (fuseCompareAndJump(op_jeq, false))
+            return;
+    } else if (m_lastOpcodeID == op_nstricteq && target.isForward()) {
+        if (fuseCompareAndJump(op_jstricteq, false))
+            return;
     } else if (m_lastOpcodeID == op_below && target.isForward()) {
         if (fuseCompareAndJump(op_jbeloweq, true))
             return;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 5f8c2bb..9b45b1b 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -5328,6 +5328,24 @@
             LAST_OPCODE(op_jgreatereq);
         }
 
+        case op_jeq: {
+            unsigned relativeOffset = currentInstruction[3].u.operand;
+            Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* condition = addToGraph(CompareEq, op1, op2);
+            addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jeq))), condition);
+            LAST_OPCODE(op_jeq);
+        }
+
+        case op_jstricteq: {
+            unsigned relativeOffset = currentInstruction[3].u.operand;
+            Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* condition = addToGraph(CompareStrictEq, op1, op2);
+            addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jstricteq))), condition);
+            LAST_OPCODE(op_jstricteq);
+        }
+
         case op_jnless: {
             unsigned relativeOffset = currentInstruction[3].u.operand;
             Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand));
@@ -5364,6 +5382,24 @@
             LAST_OPCODE(op_jngreatereq);
         }
 
+        case op_jneq: {
+            unsigned relativeOffset = currentInstruction[3].u.operand;
+            Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* condition = addToGraph(CompareEq, op1, op2);
+            addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jneq), m_currentIndex + relativeOffset)), condition);
+            LAST_OPCODE(op_jneq);
+        }
+
+        case op_jnstricteq: {
+            unsigned relativeOffset = currentInstruction[3].u.operand;
+            Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* condition = addToGraph(CompareStrictEq, op1, op2);
+            addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jnstricteq), m_currentIndex + relativeOffset)), condition);
+            LAST_OPCODE(op_jnstricteq);
+        }
+
         case op_jbelow: {
             unsigned relativeOffset = currentInstruction[3].u.operand;
             Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand));
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index ae58395..e205863 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -194,6 +194,10 @@
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_jeq:
+    case op_jneq:
+    case op_jstricteq:
+    case op_jnstricteq:
     case op_jbelow:
     case op_jbeloweq:
     case op_loop_hint:
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index a00f091..ec30500 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1243,17 +1243,6 @@
     return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
 }
 
-size_t JIT_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
-{
-    VM* vm = &exec->vm();
-    NativeCallFrameTracer tracer(vm, exec);
-
-    JSValue src1 = JSValue::decode(encodedOp1);
-    JSValue src2 = JSValue::decode(encodedOp2);
-    
-    return JSValue::strictEqual(exec, src1, src2);
-}
-
 EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
 {
     VM* vm = &exec->vm();
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 7add59d..a356d82 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -162,7 +162,6 @@
 size_t JIT_OPERATION operationRegExpTest(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
 size_t JIT_OPERATION operationRegExpTestGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
-size_t JIT_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*, EncodedJSValue);
 JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState*, Structure*, uint32_t length, uint32_t minCapacity);
 JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState*, InlineCallFrame*, JSFunction*, uint32_t argumentCount);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 5275c6c..816156b 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -5737,12 +5737,6 @@
 
 bool SpeculativeJIT::compileStrictEq(Node* node)
 {
-    // FIXME: Currently, we have op_jless, op_jgreater etc. But we don't have op_jeq, op_jstricteq etc.
-    // `==` and `===` operations with branching will be compiled to op_{eq,stricteq} and op_{jfalse,jtrue}.
-    // In DFG bytecodes, between op_eq and op_jfalse, we have MovHint to store the result of op_eq.
-    // As a result, detectPeepHoleBranch() never detects peep hole for that case.
-    // https://bugs.webkit.org/show_bug.cgi?id=149713
-
     if (node->isBinaryUseKind(BooleanUse)) {
         unsigned branchIndexInBlock = detectPeepHoleBranch();
         if (branchIndexInBlock != UINT_MAX) {
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index c4269d6..d4706e3 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -358,6 +358,10 @@
         DEFINE_OP(op_jnlesseq)
         DEFINE_OP(op_jngreater)
         DEFINE_OP(op_jngreatereq)
+        DEFINE_OP(op_jeq)
+        DEFINE_OP(op_jneq)
+        DEFINE_OP(op_jstricteq)
+        DEFINE_OP(op_jnstricteq)
         DEFINE_OP(op_jbelow)
         DEFINE_OP(op_jbeloweq)
         DEFINE_OP(op_jtrue)
@@ -520,6 +524,10 @@
         DEFINE_SLOWCASE_OP(op_jnlesseq)
         DEFINE_SLOWCASE_OP(op_jngreater)
         DEFINE_SLOWCASE_OP(op_jngreatereq)
+        DEFINE_SLOWCASE_OP(op_jeq)
+        DEFINE_SLOWCASE_OP(op_jneq)
+        DEFINE_SLOWCASE_OP(op_jstricteq)
+        DEFINE_SLOWCASE_OP(op_jnstricteq)
         DEFINE_SLOWCASE_OP(op_loop_hint)
         DEFINE_SLOWCASE_OP(op_check_traps)
         DEFINE_SLOWCASE_OP(op_mod)
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index c5dda73..1cd69f7 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -313,8 +313,11 @@
         void compileCallEvalSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitPutCallResult(Instruction*);
 
-        enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
-        void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type);
+        enum class CompileOpStrictEqType { StrictEq, NStrictEq };
+        void compileOpStrictEq(Instruction*, CompileOpStrictEqType);
+        void compileOpStrictEqJump(Instruction*, CompileOpStrictEqType);
+        enum class CompileOpEqType { Eq, NEq };
+        void compileOpEqJumpSlow(Vector<SlowCaseEntry>::iterator&, CompileOpEqType, int jumpTarget);
         bool isOperandConstantDouble(int src);
         
         void emitLoadDouble(int index, FPRegisterID value);
@@ -523,6 +526,10 @@
         void emit_op_jnlesseq(Instruction*);
         void emit_op_jngreater(Instruction*);
         void emit_op_jngreatereq(Instruction*);
+        void emit_op_jeq(Instruction*);
+        void emit_op_jneq(Instruction*);
+        void emit_op_jstricteq(Instruction*);
+        void emit_op_jnstricteq(Instruction*);
         void emit_op_jbelow(Instruction*);
         void emit_op_jbeloweq(Instruction*);
         void emit_op_jtrue(Instruction*);
@@ -616,6 +623,10 @@
         void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_jngreater(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_jngreatereq(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_jeq(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_jneq(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_jstricteq(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_jnstricteq(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_loop_hint(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_check_traps(Instruction*, Vector<SlowCaseEntry>::iterator&);
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index 89d12e2..8f320b7 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -425,6 +425,14 @@
     emitPutVirtualRegister(currentInstruction[1].u.operand);
 }
 
+void JIT::emit_op_jeq(Instruction* currentInstruction)
+{
+    unsigned target = currentInstruction[3].u.operand;
+    emitGetVirtualRegisters(currentInstruction[1].u.operand, regT0, currentInstruction[2].u.operand, regT1);
+    emitJumpSlowCaseIfNotInt(regT0, regT1, regT2);
+    addJump(branch32(Equal, regT0, regT1), target);
+}
+
 void JIT::emit_op_jtrue(Instruction* currentInstruction)
 {
     unsigned target = currentInstruction[2].u.operand;
@@ -446,7 +454,14 @@
     emitTagBool(regT0);
 
     emitPutVirtualRegister(currentInstruction[1].u.operand);
+}
 
+void JIT::emit_op_jneq(Instruction* currentInstruction)
+{
+    unsigned target = currentInstruction[3].u.operand;
+    emitGetVirtualRegisters(currentInstruction[1].u.operand, regT0, currentInstruction[2].u.operand, regT1);
+    emitJumpSlowCaseIfNotInt(regT0, regT1, regT2);
+    addJump(branch32(NotEqual, regT0, regT1), target);
 }
 
 void JIT::emit_op_throw(Instruction* currentInstruction)
@@ -480,7 +495,7 @@
     addSlowCase(emitJumpIfNumber(regT1));
     rightOK.link(this);
 
-    if (type == OpStrictEq)
+    if (type == CompileOpStrictEqType::StrictEq)
         compare64(Equal, regT1, regT0, regT0);
     else
         compare64(NotEqual, regT1, regT0, regT0);
@@ -491,12 +506,68 @@
 
 void JIT::emit_op_stricteq(Instruction* currentInstruction)
 {
-    compileOpStrictEq(currentInstruction, OpStrictEq);
+    compileOpStrictEq(currentInstruction, CompileOpStrictEqType::StrictEq);
 }
 
 void JIT::emit_op_nstricteq(Instruction* currentInstruction)
 {
-    compileOpStrictEq(currentInstruction, OpNStrictEq);
+    compileOpStrictEq(currentInstruction, CompileOpStrictEqType::NStrictEq);
+}
+
+void JIT::compileOpStrictEqJump(Instruction* currentInstruction, CompileOpStrictEqType type)
+{
+    int target = currentInstruction[3].u.operand;
+    int src1 = currentInstruction[1].u.operand;
+    int src2 = currentInstruction[2].u.operand;
+
+    emitGetVirtualRegisters(src1, regT0, src2, regT1);
+
+    // Jump slow if both are cells (to cover strings).
+    move(regT0, regT2);
+    or64(regT1, regT2);
+    addSlowCase(emitJumpIfJSCell(regT2));
+
+    // Jump slow if either is a double. First test if it's an integer, which is fine, and then test
+    // if it's a double.
+    Jump leftOK = emitJumpIfInt(regT0);
+    addSlowCase(emitJumpIfNumber(regT0));
+    leftOK.link(this);
+    Jump rightOK = emitJumpIfInt(regT1);
+    addSlowCase(emitJumpIfNumber(regT1));
+    rightOK.link(this);
+
+    if (type == CompileOpStrictEqType::StrictEq)
+        addJump(branch64(Equal, regT1, regT0), target);
+    else
+        addJump(branch64(NotEqual, regT1, regT0), target);
+}
+
+void JIT::emit_op_jstricteq(Instruction* currentInstruction)
+{
+    compileOpStrictEqJump(currentInstruction, CompileOpStrictEqType::StrictEq);
+}
+
+void JIT::emit_op_jnstricteq(Instruction* currentInstruction)
+{
+    compileOpStrictEqJump(currentInstruction, CompileOpStrictEqType::NStrictEq);
+}
+
+void JIT::emitSlow_op_jstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    unsigned target = currentInstruction[3].u.operand;
+    callOperation(operationCompareStrictEq, regT0, regT1);
+    emitJumpSlowToHot(branchTest32(NonZero, returnValueGPR), target);
+}
+
+void JIT::emitSlow_op_jnstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    unsigned target = currentInstruction[3].u.operand;
+    callOperation(operationCompareStrictEq, regT0, regT1);
+    emitJumpSlowToHot(branchTest32(Zero, returnValueGPR), target);
 }
 
 void JIT::emit_op_to_number(Instruction* currentInstruction)
@@ -818,6 +889,24 @@
     emitPutVirtualRegister(currentInstruction[1].u.operand, returnValueGPR);
 }
 
+void JIT::emitSlow_op_jeq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    unsigned target = currentInstruction[3].u.operand;
+    callOperation(operationCompareEq, regT0, regT1);
+    emitJumpSlowToHot(branchTest32(NonZero, returnValueGPR), target);
+}
+
+void JIT::emitSlow_op_jneq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    unsigned target = currentInstruction[3].u.operand;
+    callOperation(operationCompareEq, regT0, regT1);
+    emitJumpSlowToHot(branchTest32(Zero, returnValueGPR), target);
+}
+
 void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     linkAllSlowCases(iter);
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
index 0d751ea..46e507b 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -469,8 +469,6 @@
 void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     int dst = currentInstruction[1].u.operand;
-    int op1 = currentInstruction[2].u.operand;
-    int op2 = currentInstruction[3].u.operand;
 
     JumpList storeResult;
     JumpList genericCase;
@@ -488,14 +486,56 @@
     // Generic case.
     genericCase.append(getSlowCase(iter)); // doubles
     genericCase.link(this);
-    emitLoad(op1, regT1, regT0);
-    emitLoad(op2, regT3, regT2);
     callOperation(operationCompareEq, JSValueRegs(regT1, regT0), JSValueRegs(regT3, regT2));
 
     storeResult.link(this);
     emitStoreBool(dst, returnValueGPR);
 }
 
+void JIT::emit_op_jeq(Instruction* currentInstruction)
+{
+    int target = currentInstruction[3].u.operand;
+    int src1 = currentInstruction[1].u.operand;
+    int src2 = currentInstruction[2].u.operand;
+
+    emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
+    addSlowCase(branch32(NotEqual, regT1, regT3));
+    addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
+    addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
+
+    addJump(branch32(Equal, regT0, regT2), target);
+}
+
+void JIT::compileOpEqJumpSlow(Vector<SlowCaseEntry>::iterator& iter, CompileOpEqType type, int jumpTarget)
+{
+    JumpList done;
+    JumpList genericCase;
+
+    genericCase.append(getSlowCase(iter)); // tags not equal
+
+    linkSlowCase(iter); // tags equal and JSCell
+    genericCase.append(branchPtr(NotEqual, Address(regT0, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
+    genericCase.append(branchPtr(NotEqual, Address(regT2, JSCell::structureIDOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
+
+    // String case.
+    callOperation(operationCompareStringEq, regT0, regT2);
+    emitJumpSlowToHot(branchTest32(type == CompileOpEqType::Eq ? NonZero : Zero, returnValueGPR), jumpTarget);
+    done.append(jump());
+
+    // Generic case.
+    genericCase.append(getSlowCase(iter)); // doubles
+    genericCase.link(this);
+    callOperation(operationCompareEq, JSValueRegs(regT1, regT0), JSValueRegs(regT3, regT2));
+    emitJumpSlowToHot(branchTest32(type == CompileOpEqType::Eq ? NonZero : Zero, returnValueGPR), jumpTarget);
+
+    done.link(this);
+}
+
+void JIT::emitSlow_op_jeq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    compileOpEqJumpSlow(iter, CompileOpEqType::Eq, currentInstruction[3].u.operand);
+}
+
 void JIT::emit_op_neq(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
@@ -539,6 +579,25 @@
     emitStoreBool(dst, returnValueGPR);
 }
 
+void JIT::emit_op_jneq(Instruction* currentInstruction)
+{
+    int target = currentInstruction[3].u.operand;
+    int src1 = currentInstruction[1].u.operand;
+    int src2 = currentInstruction[2].u.operand;
+
+    emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
+    addSlowCase(branch32(NotEqual, regT1, regT3));
+    addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
+    addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
+
+    addJump(branch32(NotEqual, regT0, regT2), target);
+}
+
+void JIT::emitSlow_op_jneq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    compileOpEqJumpSlow(iter, CompileOpEqType::NEq, currentInstruction[3].u.operand);
+}
+
 void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type)
 {
     int dst = currentInstruction[1].u.operand;
@@ -559,7 +618,7 @@
     firstIsObject.link(this);
 
     // Simply compare the payloads.
-    if (type == OpStrictEq)
+    if (type == CompileOpStrictEqType::StrictEq)
         compare32(Equal, regT0, regT2, regT0);
     else
         compare32(NotEqual, regT0, regT2, regT0);
@@ -569,12 +628,66 @@
 
 void JIT::emit_op_stricteq(Instruction* currentInstruction)
 {
-    compileOpStrictEq(currentInstruction, OpStrictEq);
+    compileOpStrictEq(currentInstruction, CompileOpStrictEqType::StrictEq);
 }
 
 void JIT::emit_op_nstricteq(Instruction* currentInstruction)
 {
-    compileOpStrictEq(currentInstruction, OpNStrictEq);
+    compileOpStrictEq(currentInstruction, CompileOpStrictEqType::NStrictEq);
+}
+
+void JIT::compileOpStrictEqJump(Instruction* currentInstruction, CompileOpStrictEqType type)
+{
+    int target = currentInstruction[3].u.operand;
+    int src1 = currentInstruction[1].u.operand;
+    int src2 = currentInstruction[2].u.operand;
+
+    emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
+
+    // Bail if the tags differ, or are double.
+    addSlowCase(branch32(NotEqual, regT1, regT3));
+    addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
+
+    // Jump to a slow case if both are strings or symbols (non object).
+    Jump notCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
+    Jump firstIsObject = emitJumpIfCellObject(regT0);
+    addSlowCase(emitJumpIfCellNotObject(regT2));
+    notCell.link(this);
+    firstIsObject.link(this);
+
+    // Simply compare the payloads.
+    if (type == CompileOpStrictEqType::StrictEq)
+        addJump(branch32(Equal, regT0, regT2), target);
+    else
+        addJump(branch32(NotEqual, regT0, regT2), target);
+}
+
+void JIT::emit_op_jstricteq(Instruction* currentInstruction)
+{
+    compileOpStrictEqJump(currentInstruction, CompileOpStrictEqType::StrictEq);
+}
+
+void JIT::emit_op_jnstricteq(Instruction* currentInstruction)
+{
+    compileOpStrictEqJump(currentInstruction, CompileOpStrictEqType::NStrictEq);
+}
+
+void JIT::emitSlow_op_jstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    unsigned target = currentInstruction[3].u.operand;
+    callOperation(operationCompareStrictEq, JSValueRegs(regT1, regT0), JSValueRegs(regT3, regT2));
+    emitJumpSlowToHot(branchTest32(NonZero, returnValueGPR), target);
+}
+
+void JIT::emitSlow_op_jnstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkAllSlowCases(iter);
+
+    unsigned target = currentInstruction[3].u.operand;
+    callOperation(operationCompareStrictEq, JSValueRegs(regT1, regT0), JSValueRegs(regT3, regT2));
+    emitJumpSlowToHot(branchTest32(Zero, returnValueGPR), target);
 }
 
 void JIT::emit_op_eq_null(Instruction* currentInstruction)
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index e46a3d7..e0072fa 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -1170,6 +1170,17 @@
 #endif
 }
 
+size_t JIT_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+
+    JSValue src1 = JSValue::decode(encodedOp1);
+    JSValue src2 = JSValue::decode(encodedOp2);
+
+    return JSValue::strictEqual(exec, src1, src2);
+}
+
 EncodedJSValue JIT_OPERATION operationNewArrayWithProfile(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, int size)
 {
     VM* vm = &exec->vm();
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index 4a91ab8..909eaa0 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -396,6 +396,7 @@
 size_t JIT_OPERATION operationCompareGreater(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 size_t JIT_OPERATION operationCompareGreaterEq(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 size_t JIT_OPERATION operationCompareEq(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+size_t JIT_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 #if USE(JSVALUE64)
 EncodedJSValue JIT_OPERATION operationCompareStringEq(ExecState*, JSCell* left, JSCell* right) WTF_INTERNAL;
 #else
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index 8b6b610..58481a5 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -1149,6 +1149,30 @@
     LLINT_BRANCH(op_jngreatereq, !jsLessEq<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue()));
 }
 
+LLINT_SLOW_PATH_DECL(slow_path_jeq)
+{
+    LLINT_BEGIN();
+    LLINT_BRANCH(op_jeq, JSValue::equal(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue()));
+}
+
+LLINT_SLOW_PATH_DECL(slow_path_jneq)
+{
+    LLINT_BEGIN();
+    LLINT_BRANCH(op_jneq, !JSValue::equal(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue()));
+}
+
+LLINT_SLOW_PATH_DECL(slow_path_jstricteq)
+{
+    LLINT_BEGIN();
+    LLINT_BRANCH(op_jstricteq, JSValue::strictEqual(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue()));
+}
+
+LLINT_SLOW_PATH_DECL(slow_path_jnstricteq)
+{
+    LLINT_BEGIN();
+    LLINT_BRANCH(op_jnstricteq, !JSValue::strictEqual(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue()));
+}
+
 LLINT_SLOW_PATH_DECL(slow_path_switch_imm)
 {
     LLINT_BEGIN();
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.h b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
index 6e5051b..d241f71 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.h
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
@@ -92,6 +92,10 @@
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jnlesseq);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jgreatereq);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jngreatereq);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jeq);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jneq);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jstricteq);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jnstricteq);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_imm);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_char);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_string);
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index d1b3ffd..e81a492 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -1455,6 +1455,20 @@
     dispatch(constexpr op_greatereq_length)
 
 
+_llint_op_eq:
+    traceExecution()
+    equalityComparison(
+        macro (left, right, result) cieq left, right, result end,
+        _slow_path_eq)
+
+
+_llint_op_neq:
+    traceExecution()
+    equalityComparison(
+        macro (left, right, result) cineq left, right, result end,
+        _slow_path_neq)
+
+
 _llint_op_below:
     traceExecution()
     compareUnsigned(
@@ -1578,7 +1592,7 @@
 
 _llint_op_jless:
     traceExecution()
-    compare(
+    compareJump(
         macro (left, right, target) bilt left, right, target end,
         macro (left, right, target) bdlt left, right, target end,
         _llint_slow_path_jless)
@@ -1586,7 +1600,7 @@
 
 _llint_op_jnless:
     traceExecution()
-    compare(
+    compareJump(
         macro (left, right, target) bigteq left, right, target end,
         macro (left, right, target) bdgtequn left, right, target end,
         _llint_slow_path_jnless)
@@ -1594,7 +1608,7 @@
 
 _llint_op_jgreater:
     traceExecution()
-    compare(
+    compareJump(
         macro (left, right, target) bigt left, right, target end,
         macro (left, right, target) bdgt left, right, target end,
         _llint_slow_path_jgreater)
@@ -1602,7 +1616,7 @@
 
 _llint_op_jngreater:
     traceExecution()
-    compare(
+    compareJump(
         macro (left, right, target) bilteq left, right, target end,
         macro (left, right, target) bdltequn left, right, target end,
         _llint_slow_path_jngreater)
@@ -1610,7 +1624,7 @@
 
 _llint_op_jlesseq:
     traceExecution()
-    compare(
+    compareJump(
         macro (left, right, target) bilteq left, right, target end,
         macro (left, right, target) bdlteq left, right, target end,
         _llint_slow_path_jlesseq)
@@ -1618,7 +1632,7 @@
 
 _llint_op_jnlesseq:
     traceExecution()
-    compare(
+    compareJump(
         macro (left, right, target) bigt left, right, target end,
         macro (left, right, target) bdgtun left, right, target end,
         _llint_slow_path_jnlesseq)
@@ -1626,7 +1640,7 @@
 
 _llint_op_jgreatereq:
     traceExecution()
-    compare(
+    compareJump(
         macro (left, right, target) bigteq left, right, target end,
         macro (left, right, target) bdgteq left, right, target end,
         _llint_slow_path_jgreatereq)
@@ -1634,12 +1648,26 @@
 
 _llint_op_jngreatereq:
     traceExecution()
-    compare(
+    compareJump(
         macro (left, right, target) bilt left, right, target end,
         macro (left, right, target) bdltun left, right, target end,
         _llint_slow_path_jngreatereq)
 
 
+_llint_op_jeq:
+    traceExecution()
+    equalityJump(
+        macro (left, right, target) bieq left, right, target end,
+        _llint_slow_path_jeq)
+
+
+_llint_op_jneq:
+    traceExecution()
+    equalityJump(
+        macro (left, right, target) bineq left, right, target end,
+        _llint_slow_path_jneq)
+
+
 _llint_op_jbelow:
     traceExecution()
     compareUnsignedJump(
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index 3361cb9..8f99f5a 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -755,8 +755,7 @@
     dispatch(constexpr op_not_length)
 
 
-_llint_op_eq:
-    traceExecution()
+macro equalityComparison(integerComparison, slowPath)
     loadi 12[PC], t2
     loadi 8[PC], t0
     loadConstantOrVariable(t2, t3, t1)
@@ -765,14 +764,35 @@
     bieq t2, CellTag, .opEqSlow
     bib t2, LowestTag, .opEqSlow
     loadi 4[PC], t2
-    cieq t0, t1, t0
+    integerComparison(t0, t1, t0)
     storei BooleanTag, TagOffset[cfr, t2, 8]
     storei t0, PayloadOffset[cfr, t2, 8]
     dispatch(constexpr op_eq_length)
 
 .opEqSlow:
-    callSlowPath(_slow_path_eq)
+    callSlowPath(slowPath)
     dispatch(constexpr op_eq_length)
+end
+
+
+macro equalityJump(integerComparison, slowPath)
+    loadi 8[PC], t2
+    loadi 4[PC], t0
+    loadConstantOrVariable(t2, t3, t1)
+    loadConstantOrVariable2Reg(t0, t2, t0)
+    bineq t2, t3, .slow
+    bieq t2, CellTag, .slow
+    bib t2, LowestTag, .slow
+    integerComparison(t0, t1, .jumpTarget)
+    dispatch(constexpr op_jeq_length)
+
+.jumpTarget:
+    dispatchBranch(12[PC])
+
+.slow:
+    callSlowPath(slowPath)
+    dispatch(0)
+end
 
 
 _llint_op_eq_null:
@@ -802,26 +822,6 @@
     dispatch(constexpr op_eq_null_length)
 
 
-_llint_op_neq:
-    traceExecution()
-    loadi 12[PC], t2
-    loadi 8[PC], t0
-    loadConstantOrVariable(t2, t3, t1)
-    loadConstantOrVariable2Reg(t0, t2, t0)
-    bineq t2, t3, .opNeqSlow
-    bieq t2, CellTag, .opNeqSlow
-    bib t2, LowestTag, .opNeqSlow
-    loadi 4[PC], t2
-    cineq t0, t1, t0
-    storei BooleanTag, TagOffset[cfr, t2, 8]
-    storei t0, PayloadOffset[cfr, t2, 8]
-    dispatch(constexpr op_neq_length)
-
-.opNeqSlow:
-    callSlowPath(_slow_path_neq)
-    dispatch(constexpr op_neq_length)
-    
-
 _llint_op_neq_null:
     traceExecution()
     loadi 8[PC], t0
@@ -871,6 +871,30 @@
     dispatch(4)
 end
 
+
+macro strictEqualityJump(equalityOperation, slowPath)
+    loadi 8[PC], t2
+    loadi 4[PC], t0
+    loadConstantOrVariable(t2, t3, t1)
+    loadConstantOrVariable2Reg(t0, t2, t0)
+    bineq t2, t3, .slow
+    bib t2, LowestTag, .slow
+    bineq t2, CellTag, .notStringOrSymbol
+    bbaeq JSCell::m_type[t0], ObjectType, .notStringOrSymbol
+    bbb JSCell::m_type[t1], ObjectType, .slow
+.notStringOrSymbol:
+    equalityOperation(t0, t1, .jumpTarget)
+    dispatch(constexpr op_jstricteq_length)
+
+.jumpTarget:
+    dispatchBranch(12[PC])
+
+.slow:
+    callSlowPath(slowPath)
+    dispatch(0)
+end
+
+
 _llint_op_stricteq:
     traceExecution()
     strictEq(macro (left, right, result) cieq left, right, result end, _slow_path_stricteq)
@@ -881,6 +905,20 @@
     strictEq(macro (left, right, result) cineq left, right, result end, _slow_path_nstricteq)
 
 
+_llint_op_jstricteq:
+    traceExecution()
+    strictEqualityJump(
+        macro (left, right, target) bieq left, right, target end,
+        _llint_slow_path_jstricteq)
+
+
+_llint_op_jnstricteq:
+    traceExecution()
+    strictEqualityJump(
+        macro (left, right, target) bineq left, right, target end,
+        _llint_slow_path_jnstricteq)
+
+
 _llint_op_inc:
     traceExecution()
     loadi 4[PC], t0
@@ -1826,7 +1864,7 @@
 end
 
 
-macro compare(integerCompare, doubleCompare, slowPath)
+macro compareJump(integerCompare, doubleCompare, slowPath)
     loadi 4[PC], t2
     loadi 8[PC], t3
     loadConstantOrVariable(t2, t0, t1)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index 8bd50ff..6b250aa 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -722,7 +722,6 @@
 
 
 macro equalityComparison(integerComparison, slowPath)
-    traceExecution()
     loadisFromInstruction(3, t0)
     loadisFromInstruction(2, t2)
     loadisFromInstruction(1, t3)
@@ -738,16 +737,22 @@
     dispatch(4)
 end
 
-_llint_op_eq:
-    equalityComparison(
-        macro (left, right, result) cieq left, right, result end,
-        _slow_path_eq)
 
+macro equalityJump(integerComparison, slowPath)
+    loadisFromInstruction(1, t2)
+    loadisFromInstruction(2, t3)
+    loadConstantOrVariableInt32(t2, t0, .slow)
+    loadConstantOrVariableInt32(t3, t1, .slow)
+    integerComparison(t0, t1, .jumpTarget)
+    dispatch(constexpr op_jeq_length)
 
-_llint_op_neq:
-    equalityComparison(
-        macro (left, right, result) cineq left, right, result end,
-        _slow_path_neq)
+.jumpTarget:
+    dispatchIntIndirect(3)
+
+.slow:
+    callSlowPath(slowPath)
+    dispatch(0)
+end
 
 
 macro equalNullComparison()
@@ -788,7 +793,6 @@
 
 
 macro strictEq(equalityOperation, slowPath)
-    traceExecution()
     loadisFromInstruction(3, t0)
     loadisFromInstruction(2, t2)
     loadConstantOrVariable(t0, t1)
@@ -813,18 +817,61 @@
     dispatch(4)
 end
 
+
+macro strictEqualityJump(equalityOperation, slowPath)
+    loadisFromInstruction(1, t2)
+    loadisFromInstruction(2, t3)
+    loadConstantOrVariable(t2, t0)
+    loadConstantOrVariable(t3, t1)
+    move t0, t2
+    orq t1, t2
+    btqz t2, tagMask, .slow
+    bqaeq t0, tagTypeNumber, .leftOK
+    btqnz t0, tagTypeNumber, .slow
+.leftOK:
+    bqaeq t1, tagTypeNumber, .rightOK
+    btqnz t1, tagTypeNumber, .slow
+.rightOK:
+    equalityOperation(t0, t1, .jumpTarget)
+    dispatch(constexpr op_jstricteq_length)
+
+.jumpTarget:
+    dispatchIntIndirect(3)
+
+.slow:
+    callSlowPath(slowPath)
+    dispatch(0)
+end
+
+
 _llint_op_stricteq:
+    traceExecution()
     strictEq(
         macro (left, right, result) cqeq left, right, result end,
         _slow_path_stricteq)
 
 
 _llint_op_nstricteq:
+    traceExecution()
     strictEq(
         macro (left, right, result) cqneq left, right, result end,
         _slow_path_nstricteq)
 
 
+_llint_op_jstricteq:
+    traceExecution()
+    strictEqualityJump(
+        macro (left, right, target) bqeq left, right, target end,
+        _llint_slow_path_jstricteq)
+
+
+_llint_op_jnstricteq:
+    traceExecution()
+    strictEqualityJump(
+        macro (left, right, target) bqneq left, right, target end,
+        _llint_slow_path_jnstricteq)
+
+
 macro preOp(arithmeticOperation, slowPath)
     traceExecution()
     loadisFromInstruction(1, t0)
@@ -1848,7 +1895,7 @@
     dispatchIntIndirect(3)
 
 
-macro compare(integerCompare, doubleCompare, slowPath)
+macro compareJump(integerCompare, doubleCompare, slowPath)
     loadisFromInstruction(1, t2)
     loadisFromInstruction(2, t3)
     loadConstantOrVariable(t2, t0)
@@ -1904,7 +1951,6 @@
 
 
 macro compareUnsigned(integerCompareAndSet)
-    traceExecution()
     loadisFromInstruction(3, t0)
     loadisFromInstruction(2, t2)
     loadisFromInstruction(1, t3)