Title: [223318] trunk
Revision
223318
Author
utatane....@gmail.com
Date
2017-10-14 08:35:48 -0700 (Sat, 14 Oct 2017)

Log Message

Reland "Add Above/Below comparisons for UInt32 patterns"
https://bugs.webkit.org/show_bug.cgi?id=177281

Reviewed by Saam Barati.

JSTests:

* stress/uint32-comparison-jump.js: Added.
(shouldBe):
(above):
(aboveOrEqual):
(below):
(belowOrEqual):
(notAbove):
(notAboveOrEqual):
(notBelow):
(notBelowOrEqual):
* stress/uint32-comparison.js: Added.
(shouldBe):
(above):
(aboveOrEqual):
(below):
(belowOrEqual):
(aboveTest):
(aboveOrEqualTest):
(belowTest):
(belowOrEqualTest):

Source/_javascript_Core:

We reland this patch without DFGStrengthReduction change to see what causes
regression in the iOS bot.

Sometimes, we would like to have UInt32 operations in JS. While VM does
not support UInt32 nicely, VM supports efficient Int32 operations. As long
as signedness does not matter, we can just perform Int32 operations instead
and recognize its bit pattern as UInt32.

But of course, some operations respect signedness. The most frequently
used one is comparison. Octane/zlib performs UInt32 comparison by performing
`val >>> 0`. It emits op_urshift and op_unsigned. op_urshift produces
UInt32 in Int32 form. And op_unsigned will generate Double value if
the generated Int32 is < 0 (which should be UInt32).

There is a chance for optimization. The given code pattern is the following.

    op_unsigned(op_urshift(@1)) lessThan:< op_unsigned(op_urshift(@2))

This can be converted to the following.

    op_urshift(@1) below:< op_urshift(@2)

The above conversion is nice since

1. We can avoid op_unsigned. This could be unsignedness check in DFG. Since
this check depends on the value of Int32, dropping this check is not as easy as
removing Int32 edge filters.

2. We can perform unsigned comparison in Int32 form. We do not need to convert
them to DoubleRep.

Since the above comparison exists in Octane/zlib's *super* hot path, dropping
op_unsigned offers huge win.

At first, my patch attempts to convert the above thing in DFG pipeline.
However it poses several problems.

1. MovHint is not well removed. It makes UInt32ToNumber (which is for op_unsigned) live.
2. UInt32ToNumber could cause an OSR exit. So if we have the following nodes,

    2: UInt32ToNumber(@0)
    3: MovHint(@2, xxx)
    4: UInt32ToNumber(@1)
    5: MovHint(@1, xxx)

we could drop @5's MovHint. But @3 is difficult since @4 can exit.

So, instead, we start introducing a simple optimization in the bytecode compiler.
It performs pattern matching for op_urshift and comparison to drop op_unsigned.
We adds op_below and op_above families to bytecodes. They only accept Int32 and
perform unsigned comparison.

This offers 4% performance improvement in Octane/zlib.

                            baseline                  patched

zlib           x2     431.07483+-16.28434       414.33407+-9.38375         might be 1.0404x faster

* bytecode/BytecodeDumper.cpp:
(JSC::BytecodeDumper<Block>::printCompareJump):
(JSC::BytecodeDumper<Block>::dumpBytecode):
* bytecode/BytecodeDumper.h:
* 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):
* bytecompiler/NodesCodegen.cpp:
(JSC::BinaryOpNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGIntegerRangeOptimizationPhase.cpp:
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCompareUnsigned):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareBelow):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareBelowEq):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_below):
(JSC::JIT::emit_op_beloweq):
(JSC::JIT::emit_op_jbelow):
(JSC::JIT::emit_op_jbeloweq):
(JSC::JIT::emit_compareUnsignedAndJump):
(JSC::JIT::emit_compareUnsigned):
* jit/JITArithmetic32_64.cpp:
(JSC::JIT::emit_compareUnsignedAndJump):
(JSC::JIT::emit_compareUnsigned):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* parser/Nodes.h:
(JSC::ExpressionNode::isBinaryOpNode const):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (223317 => 223318)


--- trunk/JSTests/ChangeLog	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/JSTests/ChangeLog	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1,3 +1,31 @@
+2017-10-14  Yusuke Suzuki  <utatane....@gmail.com>
+
+        Reland "Add Above/Below comparisons for UInt32 patterns"
+        https://bugs.webkit.org/show_bug.cgi?id=177281
+
+        Reviewed by Saam Barati.
+
+        * stress/uint32-comparison-jump.js: Added.
+        (shouldBe):
+        (above):
+        (aboveOrEqual):
+        (below):
+        (belowOrEqual):
+        (notAbove):
+        (notAboveOrEqual):
+        (notBelow):
+        (notBelowOrEqual):
+        * stress/uint32-comparison.js: Added.
+        (shouldBe):
+        (above):
+        (aboveOrEqual):
+        (below):
+        (belowOrEqual):
+        (aboveTest):
+        (aboveOrEqualTest):
+        (belowTest):
+        (belowOrEqualTest):
+
 2017-10-12  Yusuke Suzuki  <utatane....@gmail.com>
 
         WebAssembly: Wasm functions should have either JSFunctionType or TypeOfShouldCallGetCallData

Added: trunk/JSTests/stress/uint32-comparison-jump.js (0 => 223318)


--- trunk/JSTests/stress/uint32-comparison-jump.js	                        (rev 0)
+++ trunk/JSTests/stress/uint32-comparison-jump.js	2017-10-14 15:35:48 UTC (rev 223318)
@@ -0,0 +1,141 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function above(a, trap) {
+    let result = 0;
+    for (let i = 0; (a >>> 0) > (i >>> 0); ++i) {
+        result += i;
+        if (i === trap)
+            break;
+    }
+    return result;
+}
+noInline(above);
+
+function aboveOrEqual(a, trap) {
+    let result = 0;
+    for (let i = 0; (a >>> 0) >= (i >>> 0); ++i) {
+        result += i;
+        if (i === trap)
+            break;
+    }
+    return result;
+}
+noInline(aboveOrEqual);
+
+function below(a, trap) {
+    let result = 0;
+    for (let i = 0; (i >>> 0) < (a >>> 0); ++i) {
+        result += i;
+        if (i === trap)
+            break;
+    }
+    return result;
+}
+noInline(below);
+
+function belowOrEqual(a, trap) {
+    let result = 0;
+    for (let i = 0; (i >>> 0) <= (a >>> 0); ++i) {
+        result += i;
+        if (i === trap)
+            break;
+    }
+    return result;
+}
+noInline(belowOrEqual);
+
+function notAbove(a, trap) {
+    let result = 0;
+    for (let i = 0; (a >>> 0) > (i >>> 0) && a; ++i) {
+        result += i;
+        if (i === trap)
+            break;
+    }
+    return result;
+}
+noInline(notAbove);
+
+function notAboveOrEqual(a, trap) {
+    let result = 0;
+    for (let i = 0; (a >>> 0) >= (i >>> 0) && a; ++i) {
+        result += i;
+        if (i === trap)
+            break;
+    }
+    return result;
+}
+noInline(notAboveOrEqual);
+
+function notBelow(a, trap) {
+    let result = 0;
+    for (let i = 0; (i >>> 0) < (a >>> 0) && a; ++i) {
+        result += i;
+        if (i === trap)
+            break;
+    }
+    return result;
+}
+noInline(notBelow);
+
+function notBelowOrEqual(a, trap) {
+    let result = 0;
+    for (let i = 0; (i >>> 0) <= (a >>> 0) && a; ++i) {
+        result += i;
+        if (i === trap)
+            break;
+    }
+    return result;
+}
+noInline(notBelowOrEqual);
+
+for (var i = 0; i < 1e2; ++i) {
+    shouldBe(above(0, -1), 0);
+    shouldBe(above(20000, -1), 199990000);
+    shouldBe(above(-1, 10000), 50005000);
+}
+
+for (var i = 0; i < 1e2; ++i) {
+    shouldBe(aboveOrEqual(0, -1), 0);
+    shouldBe(aboveOrEqual(20000, -1), 200010000);
+    shouldBe(aboveOrEqual(-1, 10000), 50005000);
+}
+
+for (var i = 0; i < 1e2; ++i) {
+    shouldBe(below(0, -1), 0);
+    shouldBe(below(20000, -1), 199990000);
+    shouldBe(below(-1, 10000), 50005000);
+}
+
+for (var i = 0; i < 1e2; ++i) {
+    shouldBe(belowOrEqual(0, -1), 0);
+    shouldBe(belowOrEqual(20000, -1), 200010000);
+    shouldBe(belowOrEqual(-1, 10000), 50005000);
+}
+
+for (var i = 0; i < 1e2; ++i) {
+    shouldBe(notAbove(0, -1), 0);
+    shouldBe(notAbove(20000, -1), 199990000);
+    shouldBe(notAbove(-1, 10000), 50005000);
+}
+
+for (var i = 0; i < 1e2; ++i) {
+    shouldBe(notAboveOrEqual(0, -1), 0);
+    shouldBe(notAboveOrEqual(20000, -1), 200010000);
+    shouldBe(notAboveOrEqual(-1, 10000), 50005000);
+}
+
+for (var i = 0; i < 1e2; ++i) {
+    shouldBe(notBelow(0, -1), 0);
+    shouldBe(notBelow(20000, -1), 199990000);
+    shouldBe(notBelow(-1, 10000), 50005000);
+}
+
+for (var i = 0; i < 1e2; ++i) {
+    shouldBe(notBelowOrEqual(0, -1), 0);
+    shouldBe(notBelowOrEqual(20000, -1), 200010000);
+    shouldBe(notBelowOrEqual(-1, 10000), 50005000);
+}
+

Added: trunk/JSTests/stress/uint32-comparison.js (0 => 223318)


--- trunk/JSTests/stress/uint32-comparison.js	                        (rev 0)
+++ trunk/JSTests/stress/uint32-comparison.js	2017-10-14 15:35:48 UTC (rev 223318)
@@ -0,0 +1,88 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function above(a, b) {
+    return (a >>> 0) > (b >>> 0);
+}
+noInline(above);
+
+function aboveOrEqual(a, b) {
+    return (a >>> 0) >= (b >>> 0);
+}
+noInline(aboveOrEqual);
+
+function below(a, b) {
+    return (a >>> 0) < (b >>> 0);
+}
+noInline(below);
+
+function belowOrEqual(a, b) {
+    return (a >>> 0) <= (b >>> 0);
+}
+noInline(belowOrEqual);
+
+(function aboveTest() {
+    for (let i = 0; i < 1e5; ++i) {
+        shouldBe(above(0, 20), false);
+        shouldBe(above(0, 0), false);
+        shouldBe(above(0, -0), false);
+        shouldBe(above(-1, 0), true);
+        shouldBe(above(-1, -1), false);
+        shouldBe(above(-1, 1), true);
+        shouldBe(above(1, -1), false);
+        shouldBe(above(1, 0xffffffff), false);
+        shouldBe(above(0xffffffff, 0xffffffff), false);
+        shouldBe(above(-1, 0xffffffff), false);
+        shouldBe(above(-1, 0xfffffffff), false);
+    }
+}());
+
+(function aboveOrEqualTest() {
+    for (let i = 0; i < 1e5; ++i) {
+        shouldBe(aboveOrEqual(0, 20), false);
+        shouldBe(aboveOrEqual(0, 0), true);
+        shouldBe(aboveOrEqual(0, -0), true);
+        shouldBe(aboveOrEqual(-1, 0), true);
+        shouldBe(aboveOrEqual(-1, -1), true);
+        shouldBe(aboveOrEqual(-1, 1), true);
+        shouldBe(aboveOrEqual(1, -1), false);
+        shouldBe(aboveOrEqual(1, 0xffffffff), false);
+        shouldBe(aboveOrEqual(0xffffffff, 0xffffffff), true);
+        shouldBe(aboveOrEqual(-1, 0xffffffff), true);
+        shouldBe(aboveOrEqual(-1, 0xfffffffff), true);
+    }
+}());
+
+(function belowTest() {
+    for (let i = 0; i < 1e5; ++i) {
+        shouldBe(below(0, 20), true);
+        shouldBe(below(0, 0), false);
+        shouldBe(below(0, -0), false);
+        shouldBe(below(-1, 0), false);
+        shouldBe(below(-1, -1), false);
+        shouldBe(below(-1, 1), false);
+        shouldBe(below(1, -1), true);
+        shouldBe(below(1, 0xffffffff), true);
+        shouldBe(below(0xffffffff, 0xffffffff), false);
+        shouldBe(below(-1, 0xffffffff), false);
+        shouldBe(below(-1, 0xfffffffff), false);
+    }
+}());
+
+(function belowOrEqualTest() {
+    for (let i = 0; i < 1e5; ++i) {
+        shouldBe(belowOrEqual(0, 20), true);
+        shouldBe(belowOrEqual(0, 0), true);
+        shouldBe(belowOrEqual(0, -0), true);
+        shouldBe(belowOrEqual(-1, 0), false);
+        shouldBe(belowOrEqual(-1, -1), true);
+        shouldBe(belowOrEqual(-1, 1), false);
+        shouldBe(belowOrEqual(1, -1), true);
+        shouldBe(belowOrEqual(1, 0xffffffff), true);
+        shouldBe(belowOrEqual(0xffffffff, 0xffffffff), true);
+        shouldBe(belowOrEqual(-1, 0xffffffff), true);
+        shouldBe(belowOrEqual(-1, 0xfffffffff), true);
+    }
+}());

Modified: trunk/Source/_javascript_Core/ChangeLog (223317 => 223318)


--- trunk/Source/_javascript_Core/ChangeLog	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1,3 +1,135 @@
+2017-10-14  Yusuke Suzuki  <utatane....@gmail.com>
+
+        Reland "Add Above/Below comparisons for UInt32 patterns"
+        https://bugs.webkit.org/show_bug.cgi?id=177281
+
+        Reviewed by Saam Barati.
+
+        We reland this patch without DFGStrengthReduction change to see what causes
+        regression in the iOS bot.
+
+        Sometimes, we would like to have UInt32 operations in JS. While VM does
+        not support UInt32 nicely, VM supports efficient Int32 operations. As long
+        as signedness does not matter, we can just perform Int32 operations instead
+        and recognize its bit pattern as UInt32.
+
+        But of course, some operations respect signedness. The most frequently
+        used one is comparison. Octane/zlib performs UInt32 comparison by performing
+        `val >>> 0`. It emits op_urshift and op_unsigned. op_urshift produces
+        UInt32 in Int32 form. And op_unsigned will generate Double value if
+        the generated Int32 is < 0 (which should be UInt32).
+
+        There is a chance for optimization. The given code pattern is the following.
+
+            op_unsigned(op_urshift(@1)) lessThan:< op_unsigned(op_urshift(@2))
+
+        This can be converted to the following.
+
+            op_urshift(@1) below:< op_urshift(@2)
+
+        The above conversion is nice since
+
+        1. We can avoid op_unsigned. This could be unsignedness check in DFG. Since
+        this check depends on the value of Int32, dropping this check is not as easy as
+        removing Int32 edge filters.
+
+        2. We can perform unsigned comparison in Int32 form. We do not need to convert
+        them to DoubleRep.
+
+        Since the above comparison exists in Octane/zlib's *super* hot path, dropping
+        op_unsigned offers huge win.
+
+        At first, my patch attempts to convert the above thing in DFG pipeline.
+        However it poses several problems.
+
+        1. MovHint is not well removed. It makes UInt32ToNumber (which is for op_unsigned) live.
+        2. UInt32ToNumber could cause an OSR exit. So if we have the following nodes,
+
+            2: UInt32ToNumber(@0)
+            3: MovHint(@2, xxx)
+            4: UInt32ToNumber(@1)
+            5: MovHint(@1, xxx)
+
+        we could drop @5's MovHint. But @3 is difficult since @4 can exit.
+
+        So, instead, we start introducing a simple optimization in the bytecode compiler.
+        It performs pattern matching for op_urshift and comparison to drop op_unsigned.
+        We adds op_below and op_above families to bytecodes. They only accept Int32 and
+        perform unsigned comparison.
+
+        This offers 4% performance improvement in Octane/zlib.
+
+                                    baseline                  patched
+
+        zlib           x2     431.07483+-16.28434       414.33407+-9.38375         might be 1.0404x faster
+
+        * bytecode/BytecodeDumper.cpp:
+        (JSC::BytecodeDumper<Block>::printCompareJump):
+        (JSC::BytecodeDumper<Block>::dumpBytecode):
+        * bytecode/BytecodeDumper.h:
+        * 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):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::BinaryOpNode::emitBytecode):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGIntegerRangeOptimizationPhase.cpp:
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCompareUnsigned):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareBelow):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareBelowEq):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::emit_op_below):
+        (JSC::JIT::emit_op_beloweq):
+        (JSC::JIT::emit_op_jbelow):
+        (JSC::JIT::emit_op_jbeloweq):
+        (JSC::JIT::emit_compareUnsignedAndJump):
+        (JSC::JIT::emit_compareUnsigned):
+        * jit/JITArithmetic32_64.cpp:
+        (JSC::JIT::emit_compareUnsignedAndJump):
+        (JSC::JIT::emit_compareUnsigned):
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * parser/Nodes.h:
+        (JSC::ExpressionNode::isBinaryOpNode const):
+
 2017-10-12  Yusuke Suzuki  <utatane....@gmail.com>
 
         WebAssembly: Wasm functions should have either JSFunctionType or TypeOfShouldCallGetCallData

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -360,6 +360,16 @@
 }
 
 template<class Block>
+void BytecodeDumper<Block>::printCompareJump(PrintStream& out, const typename Block::Instruction*, const typename Block::Instruction*& it, int location, const char* op)
+{
+    int r0 = (++it)->u.operand;
+    int r1 = (++it)->u.operand;
+    int offset = (++it)->u.operand;
+    printLocationAndOp(out, location, it, op);
+    out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+}
+
+template<class Block>
 void BytecodeDumper<Block>::printGetByIdOp(PrintStream& out, int location, const typename Block::Instruction*& it)
 {
     const char* op;
@@ -834,6 +844,14 @@
         printBinaryOp(out, location, it, "greatereq");
         break;
     }
+    case op_below: {
+        printBinaryOp(out, location, it, "below");
+        break;
+    }
+    case op_beloweq: {
+        printBinaryOp(out, location, it, "beloweq");
+        break;
+    }
     case op_inc: {
         int r0 = (++it)->u.operand;
         printLocationOpAndRegisterOperand(out, location, it, "inc", r0);
@@ -1197,69 +1215,45 @@
         break;
     }
     case op_jless: {
-        int r0 = (++it)->u.operand;
-        int r1 = (++it)->u.operand;
-        int offset = (++it)->u.operand;
-        printLocationAndOp(out, location, it, "jless");
-        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        printCompareJump(out, begin, it, location, "jless");
         break;
     }
     case op_jlesseq: {
-        int r0 = (++it)->u.operand;
-        int r1 = (++it)->u.operand;
-        int offset = (++it)->u.operand;
-        printLocationAndOp(out, location, it, "jlesseq");
-        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        printCompareJump(out, begin, it, location, "jlesseq");
         break;
     }
     case op_jgreater: {
-        int r0 = (++it)->u.operand;
-        int r1 = (++it)->u.operand;
-        int offset = (++it)->u.operand;
-        printLocationAndOp(out, location, it, "jgreater");
-        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        printCompareJump(out, begin, it, location, "jgreater");
         break;
     }
     case op_jgreatereq: {
-        int r0 = (++it)->u.operand;
-        int r1 = (++it)->u.operand;
-        int offset = (++it)->u.operand;
-        printLocationAndOp(out, location, it, "jgreatereq");
-        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        printCompareJump(out, begin, it, location, "jgreatereq");
         break;
     }
     case op_jnless: {
-        int r0 = (++it)->u.operand;
-        int r1 = (++it)->u.operand;
-        int offset = (++it)->u.operand;
-        printLocationAndOp(out, location, it, "jnless");
-        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        printCompareJump(out, begin, it, location, "jnless");
         break;
     }
     case op_jnlesseq: {
-        int r0 = (++it)->u.operand;
-        int r1 = (++it)->u.operand;
-        int offset = (++it)->u.operand;
-        printLocationAndOp(out, location, it, "jnlesseq");
-        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        printCompareJump(out, begin, it, location, "jnlesseq");
         break;
     }
     case op_jngreater: {
-        int r0 = (++it)->u.operand;
-        int r1 = (++it)->u.operand;
-        int offset = (++it)->u.operand;
-        printLocationAndOp(out, location, it, "jngreater");
-        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        printCompareJump(out, begin, it, location, "jngreater");
         break;
     }
     case op_jngreatereq: {
-        int r0 = (++it)->u.operand;
-        int r1 = (++it)->u.operand;
-        int offset = (++it)->u.operand;
-        printLocationAndOp(out, location, it, "jngreatereq");
-        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        printCompareJump(out, begin, it, location, "jngreatereq");
         break;
     }
+    case op_jbelow: {
+        printCompareJump(out, begin, it, location, "jbelow");
+        break;
+    }
+    case op_jbeloweq: {
+        printCompareJump(out, begin, it, location, "jbeloweq");
+        break;
+    }
     case op_loop_hint: {
         printLocationAndOp(out, location, it, "loop_hint");
         break;

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeDumper.h (223317 => 223318)


--- trunk/Source/_javascript_Core/bytecode/BytecodeDumper.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeDumper.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -67,6 +67,7 @@
     void printUnaryOp(PrintStream& out, int location, const Instruction*& it, const char* op);
     void printBinaryOp(PrintStream& out, int location, const Instruction*& it, const char* op);
     void printConditionalJump(PrintStream& out, const Instruction*, const Instruction*& it, int location, const char* op);
+    void printCompareJump(PrintStream& out, const Instruction*, const Instruction*& it, int location, const char* op);
     void printGetByIdOp(PrintStream& out, int location, const Instruction*& it);
     void printGetByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&);
     void printPutByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&);

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.json (223317 => 223318)


--- trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2017-10-14 15:35:48 UTC (rev 223318)
@@ -36,6 +36,8 @@
             { "name" : "op_lesseq", "length" : 4 },
             { "name" : "op_greater", "length" : 4 },
             { "name" : "op_greatereq", "length" : 4 },
+            { "name" : "op_below", "length" : 4 },
+            { "name" : "op_beloweq", "length" : 4 },
             { "name" : "op_inc", "length" : 2 },
             { "name" : "op_dec", "length" : 2 },
             { "name" : "op_to_number", "length" : 4 },
@@ -115,6 +117,8 @@
             { "name" : "op_jnlesseq", "length" : 4 },
             { "name" : "op_jngreater", "length" : 4 },
             { "name" : "op_jngreatereq", "length" : 4 },
+            { "name" : "op_jbelow", "length" : 4 },
+            { "name" : "op_jbeloweq", "length" : 4 },
             { "name" : "op_loop_hint", "length" : 1 },
             { "name" : "op_switch_imm", "length" : 4 },
             { "name" : "op_switch_char", "length" : 4 },

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h (223317 => 223318)


--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -85,6 +85,8 @@
     case op_jngreater:
     case op_jngreatereq:
     case op_jless:
+    case op_jbelow:
+    case op_jbeloweq:
     case op_set_function_name:
     case op_log_shadow_chicken_tail: {
         ASSERT(opcodeLengths[opcodeID] > 2);
@@ -237,6 +239,8 @@
     case op_lesseq:
     case op_greater:
     case op_greatereq:
+    case op_below:
+    case op_beloweq:
     case op_nstricteq:
     case op_stricteq:
     case op_neq:
@@ -343,6 +347,8 @@
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_jbelow:
+    case op_jbeloweq:
     case op_loop_hint:
     case op_switch_imm:
     case op_switch_char:
@@ -463,6 +469,8 @@
     case op_lesseq:
     case op_greater:
     case op_greatereq:
+    case op_below:
+    case op_beloweq:
     case op_neq_null:
     case op_eq_null:
     case op_not:

Modified: trunk/Source/_javascript_Core/bytecode/Opcode.h (223317 => 223318)


--- trunk/Source/_javascript_Core/bytecode/Opcode.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/bytecode/Opcode.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -151,6 +151,8 @@
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_jbelow:
+    case op_jbeloweq:
     case op_switch_imm:
     case op_switch_char:
     case op_switch_string:

Modified: trunk/Source/_javascript_Core/bytecode/PreciseJumpTargetsInlines.h (223317 => 223318)


--- trunk/Source/_javascript_Core/bytecode/PreciseJumpTargetsInlines.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/bytecode/PreciseJumpTargetsInlines.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -55,6 +55,8 @@
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_jbelow:
+    case op_jbeloweq:
         function(current[3].u.operand);
         break;
     case op_switch_imm:

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1366,7 +1366,7 @@
 
 void BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label& target)
 {
-    if (m_lastOpcodeID == op_less) {
+    auto fuseCompareAndJump = [&] (OpcodeID jumpID) {
         int dstIndex;
         int src1Index;
         int src2Index;
@@ -1377,63 +1377,33 @@
             rewindBinaryOp();
 
             size_t begin = instructions().size();
-            emitOpcode(op_jless);
+            emitOpcode(jumpID);
             instructions().append(src1Index);
             instructions().append(src2Index);
             instructions().append(target.bind(begin, instructions().size()));
-            return;
+            return true;
         }
-    } else if (m_lastOpcodeID == op_lesseq) {
-        int dstIndex;
-        int src1Index;
-        int src2Index;
+        return false;
+    };
 
-        retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
-
-        if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
-            rewindBinaryOp();
-
-            size_t begin = instructions().size();
-            emitOpcode(op_jlesseq);
-            instructions().append(src1Index);
-            instructions().append(src2Index);
-            instructions().append(target.bind(begin, instructions().size()));
+    if (m_lastOpcodeID == op_less) {
+        if (fuseCompareAndJump(op_jless))
             return;
-        }
+    } else if (m_lastOpcodeID == op_lesseq) {
+        if (fuseCompareAndJump(op_jlesseq))
+            return;
     } else if (m_lastOpcodeID == op_greater) {
-        int dstIndex;
-        int src1Index;
-        int src2Index;
-
-        retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
-
-        if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
-            rewindBinaryOp();
-
-            size_t begin = instructions().size();
-            emitOpcode(op_jgreater);
-            instructions().append(src1Index);
-            instructions().append(src2Index);
-            instructions().append(target.bind(begin, instructions().size()));
+        if (fuseCompareAndJump(op_jgreater))
             return;
-        }
     } else if (m_lastOpcodeID == op_greatereq) {
-        int dstIndex;
-        int src1Index;
-        int src2Index;
-
-        retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
-
-        if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
-            rewindBinaryOp();
-
-            size_t begin = instructions().size();
-            emitOpcode(op_jgreatereq);
-            instructions().append(src1Index);
-            instructions().append(src2Index);
-            instructions().append(target.bind(begin, instructions().size()));
+        if (fuseCompareAndJump(op_jgreatereq))
             return;
-        }
+    } else if (m_lastOpcodeID == op_below) {
+        if (fuseCompareAndJump(op_jbelow))
+            return;
+    } else if (m_lastOpcodeID == op_beloweq) {
+        if (fuseCompareAndJump(op_jbeloweq))
+            return;
     } else if (m_lastOpcodeID == op_eq_null && target.isForward()) {
         int dstIndex;
         int srcIndex;
@@ -1475,7 +1445,7 @@
 
 void BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label& target)
 {
-    if (m_lastOpcodeID == op_less && target.isForward()) {
+    auto fuseCompareAndJump = [&] (OpcodeID jumpID, bool replaceOperands) {
         int dstIndex;
         int src1Index;
         int src2Index;
@@ -1486,63 +1456,36 @@
             rewindBinaryOp();
 
             size_t begin = instructions().size();
-            emitOpcode(op_jnless);
+            emitOpcode(jumpID);
+            // Since op_below and op_beloweq only accepts Int32, replacing operands is not observable to users.
+            if (replaceOperands)
+                std::swap(src1Index, src2Index);
             instructions().append(src1Index);
             instructions().append(src2Index);
             instructions().append(target.bind(begin, instructions().size()));
-            return;
+            return true;
         }
-    } else if (m_lastOpcodeID == op_lesseq && target.isForward()) {
-        int dstIndex;
-        int src1Index;
-        int src2Index;
+        return false;
+    };
 
-        retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
-
-        if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
-            rewindBinaryOp();
-
-            size_t begin = instructions().size();
-            emitOpcode(op_jnlesseq);
-            instructions().append(src1Index);
-            instructions().append(src2Index);
-            instructions().append(target.bind(begin, instructions().size()));
+    if (m_lastOpcodeID == op_less && target.isForward()) {
+        if (fuseCompareAndJump(op_jnless, false))
             return;
-        }
+    } else if (m_lastOpcodeID == op_lesseq && target.isForward()) {
+        if (fuseCompareAndJump(op_jnlesseq, false))
+            return;
     } else if (m_lastOpcodeID == op_greater && target.isForward()) {
-        int dstIndex;
-        int src1Index;
-        int src2Index;
-
-        retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
-
-        if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
-            rewindBinaryOp();
-
-            size_t begin = instructions().size();
-            emitOpcode(op_jngreater);
-            instructions().append(src1Index);
-            instructions().append(src2Index);
-            instructions().append(target.bind(begin, instructions().size()));
+        if (fuseCompareAndJump(op_jngreater, false))
             return;
-        }
     } else if (m_lastOpcodeID == op_greatereq && target.isForward()) {
-        int dstIndex;
-        int src1Index;
-        int src2Index;
-
-        retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
-
-        if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
-            rewindBinaryOp();
-
-            size_t begin = instructions().size();
-            emitOpcode(op_jngreatereq);
-            instructions().append(src1Index);
-            instructions().append(src2Index);
-            instructions().append(target.bind(begin, instructions().size()));
+        if (fuseCompareAndJump(op_jngreatereq, false))
             return;
-        }
+    } else if (m_lastOpcodeID == op_below && target.isForward()) {
+        if (fuseCompareAndJump(op_jbeloweq, true))
+            return;
+    } else if (m_lastOpcodeID == op_beloweq && target.isForward()) {
+        if (fuseCompareAndJump(op_jbelow, true))
+            return;
     } else if (m_lastOpcodeID == op_not) {
         int dstIndex;
         int srcIndex;

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1988,6 +1988,64 @@
 {
     OpcodeID opcodeID = this->opcodeID();
 
+    if (opcodeID == op_less || opcodeID == op_lesseq || opcodeID == op_greater || opcodeID == op_greatereq) {
+        auto isUInt32 = [&] (ExpressionNode* node) -> std::optional<UInt32Result> {
+            if (node->isBinaryOpNode() && static_cast<BinaryOpNode*>(node)->opcodeID() == op_urshift)
+                return UInt32Result::UInt32;
+            if (node->isNumber() && static_cast<NumberNode*>(node)->isIntegerNode()) {
+                int32_t value = static_cast<int32_t>(static_cast<IntegerNode*>(node)->value());
+                if (value >= 0)
+                    return UInt32Result::Constant;
+            }
+            return std::nullopt;
+        };
+        auto leftResult = isUInt32(m_expr1);
+        auto rightResult = isUInt32(m_expr2);
+        if ((leftResult && rightResult) && (leftResult.value() == UInt32Result::UInt32 || rightResult.value() == UInt32Result::UInt32)) {
+            auto* left = m_expr1;
+            auto* right = m_expr2;
+            if (left->isBinaryOpNode()) {
+                ASSERT(static_cast<BinaryOpNode*>(left)->opcodeID() == op_urshift);
+                static_cast<BinaryOpNode*>(left)->m_shouldToUnsignedResult = false;
+            }
+            if (right->isBinaryOpNode()) {
+                ASSERT(static_cast<BinaryOpNode*>(right)->opcodeID() == op_urshift);
+                static_cast<BinaryOpNode*>(right)->m_shouldToUnsignedResult = false;
+            }
+            RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator));
+            RefPtr<RegisterID> src2 = generator.emitNode(right);
+            generator.emitExpressionInfo(position(), position(), position());
+
+            // Since the both sides only accept Int32, replacing operands is not observable to users.
+            bool replaceOperands = false;
+            OpcodeID resultOp = opcodeID;
+            switch (opcodeID) {
+            case op_less:
+                resultOp = op_below;
+                break;
+            case op_lesseq:
+                resultOp = op_beloweq;
+                break;
+            case op_greater:
+                resultOp = op_below;
+                replaceOperands = true;
+                break;
+            case op_greatereq:
+                resultOp = op_beloweq;
+                replaceOperands = true;
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+            }
+            OperandTypes operandTypes(left->resultDescriptor(), right->resultDescriptor());
+            if (replaceOperands) {
+                std::swap(src1, src2);
+                operandTypes = OperandTypes(right->resultDescriptor(), left->resultDescriptor());
+            }
+            return generator.emitBinaryOp(resultOp, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), operandTypes);
+        }
+    }
+
     if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) {
         generator.emitExpressionInfo(position(), position(), position());
         return emitStrcat(generator, dst);
@@ -2023,8 +2081,10 @@
         return generator.emitUnaryOp(op_not, generator.finalDestination(dst, tmp.get()), tmp.get());
     }
     RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(left->resultDescriptor(), right->resultDescriptor()));
-    if (opcodeID == op_urshift && dst != generator.ignoredResult())
-        return generator.emitUnaryOp(op_unsigned, result, result);
+    if (m_shouldToUnsignedResult) {
+        if (opcodeID == op_urshift && dst != generator.ignoredResult())
+            return generator.emitUnaryOp(op_unsigned, result, result);
+    }
     return result;
 }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1407,7 +1407,48 @@
         forNode(node).setType(m_graph, SpecStringIdent);
         break;
     }
-            
+
+    case CompareBelow:
+    case CompareBelowEq: {
+        JSValue leftConst = forNode(node->child1()).value();
+        JSValue rightConst = forNode(node->child2()).value();
+        if (leftConst && rightConst) {
+            if (leftConst.isInt32() && rightConst.isInt32()) {
+                uint32_t a = static_cast<uint32_t>(leftConst.asInt32());
+                uint32_t b = static_cast<uint32_t>(rightConst.asInt32());
+                switch (node->op()) {
+                case CompareBelow:
+                    setConstant(node, jsBoolean(a < b));
+                    break;
+                case CompareBelowEq:
+                    setConstant(node, jsBoolean(a <= b));
+                    break;
+                default:
+                    RELEASE_ASSERT_NOT_REACHED();
+                    break;
+                }
+                break;
+            }
+        }
+
+        if (node->child1() == node->child2()) {
+            switch (node->op()) {
+            case CompareBelow:
+                setConstant(node, jsBoolean(false));
+                break;
+            case CompareBelowEq:
+                setConstant(node, jsBoolean(true));
+                break;
+            default:
+                DFG_CRASH(m_graph, node, "Unexpected node type");
+                break;
+            }
+            break;
+        }
+        forNode(node).setType(SpecBoolean);
+        break;
+    }
+
     case CompareLess:
     case CompareLessEq:
     case CompareGreater:

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -4634,6 +4634,20 @@
             NEXT_OPCODE(op_greatereq);
         }
 
+        case op_below: {
+            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
+            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareBelow, op1, op2));
+            NEXT_OPCODE(op_below);
+        }
+
+        case op_beloweq: {
+            Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
+            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareBelowEq, op1, op2));
+            NEXT_OPCODE(op_beloweq);
+        }
+
         case op_eq: {
             Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand));
             Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand));
@@ -5079,7 +5093,25 @@
             addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jngreatereq), m_currentIndex + relativeOffset)), condition);
             LAST_OPCODE(op_jngreatereq);
         }
-            
+
+        case op_jbelow: {
+            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(CompareBelow, op1, op2);
+            addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jbelow))), condition);
+            LAST_OPCODE(op_jbelow);
+        }
+
+        case op_jbeloweq: {
+            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(CompareBelowEq, op1, op2);
+            addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jbeloweq))), condition);
+            LAST_OPCODE(op_jbeloweq);
+        }
+
         case op_switch_imm: {
             SwitchData& data = ""
             data.kind = SwitchImm;

Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -151,6 +151,8 @@
     case op_lesseq:
     case op_greater:
     case op_greatereq:
+    case op_below:
+    case op_beloweq:
     case op_eq:
     case op_eq_null:
     case op_stricteq:
@@ -192,6 +194,8 @@
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_jbelow:
+    case op_jbeloweq:
     case op_loop_hint:
     case op_check_traps:
     case op_nop:

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1486,6 +1486,11 @@
         }
         def(PureValue(node));
         return;
+
+    case CompareBelow:
+    case CompareBelowEq:
+        def(PureValue(node));
+        return;
         
     case CompareEq:
     case CompareLess:

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -143,6 +143,8 @@
     case CompareLessEq:
     case CompareGreater:
     case CompareGreaterEq:
+    case CompareBelow:
+    case CompareBelowEq:
     case CompareEq:
     case CompareStrictEq:
     case CompareEqPtr:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -142,7 +142,6 @@
                 node->setArithMode(Arith::CheckOverflow);
             else {
                 node->setArithMode(Arith::DoOverflow);
-                node->clearFlags(NodeMustGenerate);
                 node->setResult(enableInt52() ? NodeResultInt52 : NodeResultDouble);
             }
             break;
@@ -1597,6 +1596,13 @@
             break;
         }
 
+        case CompareBelow:
+        case CompareBelowEq: {
+            fixEdge<Int32Use>(node->child1());
+            fixEdge<Int32Use>(node->child2());
+            break;
+        }
+
         case Phi:
         case Upsilon:
         case EntrySwitch:

Modified: trunk/Source/_javascript_Core/dfg/DFGIntegerRangeOptimizationPhase.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGIntegerRangeOptimizationPhase.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGIntegerRangeOptimizationPhase.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1140,6 +1140,7 @@
                         relationshipForTrue = Relationship::safeCreate(
                             terminal->child1().node(), m_zero, Relationship::NotEqual, 0);
                     } else {
+                        // FIXME: Handle CompareBelow and CompareBelowEq.
                         Node* compare = terminal->child1().node();
                         switch (compare->op()) {
                         case CompareEq:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -121,7 +121,7 @@
     /* Bitwise operators call ToInt32 on their operands. */\
     macro(ValueToInt32, NodeResultInt32) \
     /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\
-    macro(UInt32ToNumber, NodeResultNumber | NodeMustGenerate) \
+    macro(UInt32ToNumber, NodeResultNumber) \
     /* Converts booleans to numbers but passes everything else through. */\
     macro(BooleanToNumber, NodeResultJS) \
     \
@@ -286,6 +286,8 @@
     macro(CompareLessEq, NodeResultBoolean | NodeMustGenerate) \
     macro(CompareGreater, NodeResultBoolean | NodeMustGenerate) \
     macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate) \
+    macro(CompareBelow, NodeResultBoolean) \
+    macro(CompareBelowEq, NodeResultBoolean) \
     macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \
     macro(CompareStrictEq, NodeResultBoolean) \
     macro(CompareEqPtr, NodeResultBoolean) \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -818,6 +818,8 @@
         case CompareLessEq:
         case CompareGreater:
         case CompareGreaterEq:
+        case CompareBelow:
+        case CompareBelowEq:
         case CompareEq:
         case CompareStrictEq:
         case CompareEqPtr:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -266,6 +266,8 @@
     case CompareLessEq:
     case CompareGreater:
     case CompareGreaterEq:
+    case CompareBelow:
+    case CompareBelowEq:
     case CompareEq:
     case CompareStrictEq:
     case CompareEqPtr:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -5729,6 +5729,11 @@
     return false;
 }
 
+void SpeculativeJIT::compileCompareUnsigned(Node* node, MacroAssembler::RelationalCondition condition)
+{
+    compileInt32Compare(node, condition);
+}
+
 bool SpeculativeJIT::compileStrictEq(Node* node)
 {
     // FIXME: Currently, we have op_jless, op_jgreater etc. But we don't have op_jeq, op_jstricteq etc.

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -2740,6 +2740,7 @@
     }
     
     bool compare(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_EJJ);
+    void compileCompareUnsigned(Node*, MacroAssembler::RelationalCondition);
     bool compilePeepHoleBranch(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_EJJ);
     void compilePeepHoleInt32Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
     void compilePeepHoleInt52Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -2522,6 +2522,14 @@
             return;
         break;
 
+    case CompareBelow:
+        compileCompareUnsigned(node, JITCompiler::Below);
+        break;
+
+    case CompareBelowEq:
+        compileCompareUnsigned(node, JITCompiler::BelowOrEqual);
+        break;
+
     case CompareEq:
         if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
             return;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -2664,6 +2664,14 @@
             return;
         break;
 
+    case CompareBelow:
+        compileCompareUnsigned(node, JITCompiler::Below);
+        break;
+
+    case CompareBelowEq:
+        compileCompareUnsigned(node, JITCompiler::BelowOrEqual);
+        break;
+
     case CompareEq:
         if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
             return;

Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -267,6 +267,8 @@
                 case CompareLessEq:
                 case CompareGreater:
                 case CompareGreaterEq:
+                case CompareBelow:
+                case CompareBelowEq:
                 case CompareEq:
                 case CompareStrictEq:
                 case StrCat:

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -284,6 +284,8 @@
     case CompareLessEq:
     case CompareGreater:
     case CompareGreaterEq:
+    case CompareBelow:
+    case CompareBelowEq:
     case CompareStrictEq:
     case DefineDataProperty:
     case DefineAccessorProperty:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -932,6 +932,12 @@
         case CompareGreaterEq:
             compileCompareGreaterEq();
             break;
+        case CompareBelow:
+            compileCompareBelow();
+            break;
+        case CompareBelowEq:
+            compileCompareBelowEq();
+            break;
         case CompareEqPtr:
             compileCompareEqPtr();
             break;
@@ -6404,6 +6410,16 @@
             operationCompareStringGreaterEq,
             operationCompareGreaterEq);
     }
+
+    void compileCompareBelow()
+    {
+        setBoolean(m_out.below(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
+    }
+
+    void compileCompareBelowEq()
+    {
+        setBoolean(m_out.belowOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
+    }
     
     void compileLogicalNot()
     {

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -301,6 +301,8 @@
         DEFINE_OP(op_get_scope)
         DEFINE_OP(op_eq)
         DEFINE_OP(op_eq_null)
+        DEFINE_OP(op_below)
+        DEFINE_OP(op_beloweq)
         DEFINE_OP(op_try_get_by_id)
         case op_get_array_length:
         case op_get_by_id_proto_load:
@@ -331,6 +333,8 @@
         DEFINE_OP(op_jnlesseq)
         DEFINE_OP(op_jngreater)
         DEFINE_OP(op_jngreatereq)
+        DEFINE_OP(op_jbelow)
+        DEFINE_OP(op_jbeloweq)
         DEFINE_OP(op_jtrue)
         DEFINE_OP(op_loop_hint)
         DEFINE_OP(op_check_traps)

Modified: trunk/Source/_javascript_Core/jit/JIT.h (223317 => 223318)


--- trunk/Source/_javascript_Core/jit/JIT.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -460,6 +460,8 @@
 #endif // USE(JSVALUE32_64)
 
         void emit_compareAndJump(OpcodeID, int op1, int op2, unsigned target, RelationalCondition);
+        void emit_compareUnsigned(int dst, int op1, int op2, RelationalCondition);
+        void emit_compareUnsignedAndJump(int op1, int op2, unsigned target, RelationalCondition);
         void emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator&);
         
         void assertStackPointerOffset();
@@ -499,6 +501,8 @@
         void emit_op_get_scope(Instruction*);
         void emit_op_eq(Instruction*);
         void emit_op_eq_null(Instruction*);
+        void emit_op_below(Instruction*);
+        void emit_op_beloweq(Instruction*);
         void emit_op_try_get_by_id(Instruction*);
         void emit_op_get_by_id(Instruction*);
         void emit_op_get_by_id_with_this(Instruction*);
@@ -529,6 +533,8 @@
         void emit_op_jnlesseq(Instruction*);
         void emit_op_jngreater(Instruction*);
         void emit_op_jngreatereq(Instruction*);
+        void emit_op_jbelow(Instruction*);
+        void emit_op_jbeloweq(Instruction*);
         void emit_op_jtrue(Instruction*);
         void emit_op_loop_hint(Instruction*);
         void emit_op_check_traps(Instruction*);

Modified: trunk/Source/_javascript_Core/jit/JITArithmetic.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/jit/JITArithmetic.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/jit/JITArithmetic.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -197,6 +197,40 @@
     emit_compareAndJumpSlow(op1, op2, target, DoubleLessThanOrUnordered, operationCompareGreaterEq, true, iter);
 }
 
+void JIT::emit_op_below(Instruction* currentInstruction)
+{
+    int dst = currentInstruction[1].u.operand;
+    int op1 = currentInstruction[2].u.operand;
+    int op2 = currentInstruction[3].u.operand;
+    emit_compareUnsigned(dst, op1, op2, Below);
+}
+
+void JIT::emit_op_beloweq(Instruction* currentInstruction)
+{
+    int dst = currentInstruction[1].u.operand;
+    int op1 = currentInstruction[2].u.operand;
+    int op2 = currentInstruction[3].u.operand;
+    emit_compareUnsigned(dst, op1, op2, BelowOrEqual);
+}
+
+void JIT::emit_op_jbelow(Instruction* currentInstruction)
+{
+    int op1 = currentInstruction[1].u.operand;
+    int op2 = currentInstruction[2].u.operand;
+    unsigned target = currentInstruction[3].u.operand;
+
+    emit_compareUnsignedAndJump(op1, op2, target, Below);
+}
+
+void JIT::emit_op_jbeloweq(Instruction* currentInstruction)
+{
+    int op1 = currentInstruction[1].u.operand;
+    int op2 = currentInstruction[2].u.operand;
+    unsigned target = currentInstruction[3].u.operand;
+
+    emit_compareUnsignedAndJump(op1, op2, target, BelowOrEqual);
+}
+
 #if USE(JSVALUE64)
 
 void JIT::emit_op_unsigned(Instruction* currentInstruction)
@@ -264,6 +298,40 @@
     }
 }
 
+void JIT::emit_compareUnsignedAndJump(int op1, int op2, unsigned target, RelationalCondition condition)
+{
+    if (isOperandConstantInt(op2)) {
+        emitGetVirtualRegister(op1, regT0);
+        int32_t op2imm = getOperandConstantInt(op2);
+        addJump(branch32(condition, regT0, Imm32(op2imm)), target);
+    } else if (isOperandConstantInt(op1)) {
+        emitGetVirtualRegister(op2, regT1);
+        int32_t op1imm = getOperandConstantInt(op1);
+        addJump(branch32(commute(condition), regT1, Imm32(op1imm)), target);
+    } else {
+        emitGetVirtualRegisters(op1, regT0, op2, regT1);
+        addJump(branch32(condition, regT0, regT1), target);
+    }
+}
+
+void JIT::emit_compareUnsigned(int dst, int op1, int op2, RelationalCondition condition)
+{
+    if (isOperandConstantInt(op2)) {
+        emitGetVirtualRegister(op1, regT0);
+        int32_t op2imm = getOperandConstantInt(op2);
+        compare32(condition, regT0, Imm32(op2imm), regT0);
+    } else if (isOperandConstantInt(op1)) {
+        emitGetVirtualRegister(op2, regT0);
+        int32_t op1imm = getOperandConstantInt(op1);
+        compare32(commute(condition), regT0, Imm32(op1imm), regT0);
+    } else {
+        emitGetVirtualRegisters(op1, regT0, op2, regT1);
+        compare32(condition, regT0, regT1, regT0);
+    }
+    emitTagBool(regT0);
+    emitPutVirtualRegister(dst);
+}
+
 void JIT::emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition condition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator& iter)
 {
     COMPILE_ASSERT(OPCODE_LENGTH(op_jless) == OPCODE_LENGTH(op_jlesseq), OPCODE_LENGTH_op_jlesseq_equals_op_jless);

Modified: trunk/Source/_javascript_Core/jit/JITArithmetic32_64.cpp (223317 => 223318)


--- trunk/Source/_javascript_Core/jit/JITArithmetic32_64.cpp	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/jit/JITArithmetic32_64.cpp	2017-10-14 15:35:48 UTC (rev 223318)
@@ -92,6 +92,36 @@
     end.link(this);
 }
 
+void JIT::emit_compareUnsignedAndJump(int op1, int op2, unsigned target, RelationalCondition condition)
+{
+    if (isOperandConstantInt(op1)) {
+        emitLoad(op2, regT3, regT2);
+        addJump(branch32(commute(condition), regT2, Imm32(getConstantOperand(op1).asInt32())), target);
+    } else if (isOperandConstantInt(op2)) {
+        emitLoad(op1, regT1, regT0);
+        addJump(branch32(condition, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
+    } else {
+        emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
+        addJump(branch32(condition, regT0, regT2), target);
+    }
+}
+
+
+void JIT::emit_compareUnsigned(int dst, int op1, int op2, RelationalCondition condition)
+{
+    if (isOperandConstantInt(op1)) {
+        emitLoad(op2, regT3, regT2);
+        compare32(commute(condition), regT2, Imm32(getConstantOperand(op1).asInt32()), regT0);
+    } else if (isOperandConstantInt(op2)) {
+        emitLoad(op1, regT1, regT0);
+        compare32(condition, regT0, Imm32(getConstantOperand(op2).asInt32()), regT0);
+    } else {
+        emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
+        compare32(condition, regT0, regT2, regT0);
+    }
+    emitStoreBool(dst, regT0);
+}
+
 void JIT::emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator& iter)
 {
     if (isOperandConstantChar(op1) || isOperandConstantChar(op2)) {

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (223317 => 223318)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1398,6 +1398,18 @@
     dispatch(constexpr op_greatereq_length)
 
 
+_llint_op_below:
+    traceExecution()
+    compareUnsigned(
+        macro (left, right, result) cib left, right, result end)
+
+
+_llint_op_beloweq:
+    traceExecution()
+    compareUnsigned(
+        macro (left, right, result) cibeq left, right, result end)
+
+
 _llint_op_mod:
     traceExecution()
     callOpcodeSlowPath(_slow_path_mod)
@@ -1577,6 +1589,18 @@
         _llint_slow_path_jngreatereq)
 
 
+_llint_op_jbelow:
+    traceExecution()
+    compareUnsignedJump(
+        macro (left, right, target) bib left, right, target end)
+
+
+_llint_op_jbeloweq:
+    traceExecution()
+    compareUnsignedJump(
+        macro (left, right, target) bibeq left, right, target end)
+
+
 _llint_op_loop_hint:
     traceExecution()
     checkSwitchToJITForLoop()

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (223317 => 223318)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1796,6 +1796,32 @@
     dispatch(constexpr op_jneq_ptr_length)
 
 
+macro compareUnsignedJump(integerCompare)
+    loadi 4[PC], t2
+    loadi 8[PC], t3
+    loadConstantOrVariable(t2, t0, t1)
+    loadConstantOrVariable2Reg(t3, t2, t3)
+    integerCompare(t1, t3, .jumpTarget)
+    dispatch(4)
+
+.jumpTarget:
+    dispatchBranch(12[PC])
+end
+
+
+macro compareUnsigned(integerCompareAndSet)
+    loadi 12[PC], t2
+    loadi 8[PC], t0
+    loadConstantOrVariable(t2, t3, t1)
+    loadConstantOrVariable2Reg(t0, t2, t0)
+    integerCompareAndSet(t0, t1, t0)
+    loadi 4[PC], t2
+    storei BooleanTag, TagOffset[cfr, t2, 8]
+    storei t0, PayloadOffset[cfr, t2, 8]
+    dispatch(4)
+end
+
+
 macro compare(integerCompare, doubleCompare, slowPath)
     loadi 4[PC], t2
     loadi 8[PC], t3

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (223317 => 223318)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2017-10-14 15:35:48 UTC (rev 223318)
@@ -1813,6 +1813,33 @@
 end
 
 
+macro compareUnsignedJump(integerCompare)
+    loadisFromInstruction(1, t2)
+    loadisFromInstruction(2, t3)
+    loadConstantOrVariable(t2, t0)
+    loadConstantOrVariable(t3, t1)
+    integerCompare(t0, t1, .jumpTarget)
+    dispatch(4)
+
+.jumpTarget:
+    dispatchIntIndirect(3)
+end
+
+
+macro compareUnsigned(integerCompareAndSet)
+    traceExecution()
+    loadisFromInstruction(3, t0)
+    loadisFromInstruction(2, t2)
+    loadisFromInstruction(1, t3)
+    loadConstantOrVariable(t0, t1)
+    loadConstantOrVariable(t2, t0)
+    integerCompareAndSet(t0, t1, t0)
+    orq ValueFalse, t0
+    storeq t0, [cfr, t3, 8]
+    dispatch(4)
+end
+
+
 _llint_op_switch_imm:
     traceExecution()
     loadisFromInstruction(3, t2)

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (223317 => 223318)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2017-10-14 15:07:44 UTC (rev 223317)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2017-10-14 15:35:48 UTC (rev 223318)
@@ -190,6 +190,7 @@
         virtual bool isNewTarget() const { return false; }
         virtual bool isImportMeta() const { return false; }
         virtual bool isBytecodeIntrinsicNode() const { return false; }
+        virtual bool isBinaryOpNode() const { return false; }
 
         virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label&, Label&, FallThroughMode);
 
@@ -1085,7 +1086,11 @@
         ExpressionNode* lhs() { return m_expr1; };
         ExpressionNode* rhs() { return m_expr2; };
 
+        bool isBinaryOpNode() const override { return true; }
+
     private:
+        enum class UInt32Result { UInt32, Constant, };
+
         void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression);
         RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
 
@@ -1099,6 +1104,7 @@
         OpcodeID m_opcodeID;
     protected:
         bool m_rightHasAssignments;
+        bool m_shouldToUnsignedResult { true };
     };
 
     class PowNode : public BinaryOpNode {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to