[BigInt] Add ValueBitRShift into DFG
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Sep 2019 19:09:03 +0000 (19:09 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Sep 2019 19:09:03 +0000 (19:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=192663

Reviewed by Robin Morisset.

JSTests:

* stress/big-int-right-shift-jit-osr.js: Added.
* stress/big-int-right-shift-jit-untyped.js: Added.
* stress/big-int-right-shift-jit.js: Added.
* stress/value-rshift-ai-rule.js: Added.

PerformanceTests:

* BigIntBench/big-int-simple-rshift.js: Added.
(bigInt):

Source/JavaScriptCore:

We are introducing a new node called ValueBitRShift that is
responsible to handle speculation of `UntypedUse` and `BigIntUse` during
DFG. Following the approach of other bitwise operations, we
now have 2 nodes to handle ">>" operator during JIT, mainly because
of the introduction of BigInt, that makes this operator result into
Int32 or BigInt. We renamed `BitRShift` to `ArithBitRShift` and such
node handles Integers and Numbers speculation and can only return
Int32 values.

* bytecode/BytecodeList.rb:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
* bytecode/Opcode.h:

Adding support to ValueProfile to `op_rshift` to be used during
prediction propagation.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

Adding support to still do constant propagation of ValueBitRShift when
it is `UntypedUse`.

* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):

`ValueBitRshift` can trigger GC when it is `BigIntUse` because the
operation `JSBigInt::signedRightShift` potentially allocates new
JSBigInts. It also can trigger GC when it is `UntypedUse` because it
can execute arbitrary code.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):

The fixup rule of `ValueBitRShift` checks if it should fixup for
`BigIntUse` or `UntypedUse`. If those checks fail, we fallback to
`ArithBitRShift`.

* dfg/DFGNode.h:
(JSC::DFG::Node::hasNumericResult):
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:

We are using the same rule used by `ValueBitLShift` to propagate
types. We try to propagate the type based on operation's input, but
fallback to `getHeapPrediction()` if this is not possible.

* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitUntypedRightShiftBitOp):
(JSC::DFG::SpeculativeJIT::compileValueBitRShift):
(JSC::DFG::SpeculativeJIT::compileShiftOp):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::shiftOp):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitRShift):
(JSC::FTL::DFG::LowerDFGToB3::compileArithBitRShift):
(JSC::FTL::DFG::LowerDFGToB3::compileBitRShift): Deleted.
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@250313 268f45cc-cd09-0410-ab3c-d52691b4dbfc

32 files changed:
JSTests/ChangeLog
JSTests/stress/big-int-right-shift-jit-osr.js [new file with mode: 0644]
JSTests/stress/big-int-right-shift-jit-untyped.js [new file with mode: 0644]
JSTests/stress/big-int-right-shift-jit.js [new file with mode: 0644]
JSTests/stress/value-rshift-ai-rule.js [new file with mode: 0644]
PerformanceTests/BigIntBench/big-int-simple-rshift.js [new file with mode: 0644]
PerformanceTests/ChangeLog
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/BytecodeList.rb
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/Opcode.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

index a2c1d16..f111480 100644 (file)
@@ -1,3 +1,15 @@
+2019-09-24  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueBitRShift into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=192663
+
+        Reviewed by Robin Morisset.
+
+        * stress/big-int-right-shift-jit-osr.js: Added.
+        * stress/big-int-right-shift-jit-untyped.js: Added.
+        * stress/big-int-right-shift-jit.js: Added.
+        * stress/value-rshift-ai-rule.js: Added.
+
 2019-09-23  Ross Kirsling  <ross.kirsling@sony.com>
 
         Array methods should throw TypeError upon attempting to modify a string
diff --git a/JSTests/stress/big-int-right-shift-jit-osr.js b/JSTests/stress/big-int-right-shift-jit-osr.js
new file mode 100644 (file)
index 0000000..248fc8d
--- /dev/null
@@ -0,0 +1,25 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntRShift(x, y) {
+    return x >> y;
+}
+noInline(bigIntRShift);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntRShift(0b100111n, 2n);
+    assert.sameValue(r, 0b1001n, 0b100111n + " >> " + 2n + " = " + r);
+}
+
+let r = bigIntRShift(3, 10);
+assert.sameValue(r, 0, 3 + " >> " + 10 + " = " + r);
+
+r = bigIntRShift("3", "10");
+assert.sameValue(r, 0, 3 + " >> " + 10 + " = " + r);
+
diff --git a/JSTests/stress/big-int-right-shift-jit-untyped.js b/JSTests/stress/big-int-right-shift-jit-untyped.js
new file mode 100644 (file)
index 0000000..b0d6131
--- /dev/null
@@ -0,0 +1,36 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntRShift(x, y) {
+    return x >> y;
+}
+noInline(bigIntRShift);
+
+let o =  {valueOf: () => 4n};
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntRShift(0b10001n, o);
+    assert.sameValue(r, 1n, 0b10001n + " >> {valueOf: () => 4n} = " + r);
+}
+
+o2 =  {valueOf: () => 0b10000n};
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntRShift(o2, o);
+    assert.sameValue(r, 1n, "{valueOf: () => 0b10000n} >> {valueOf: () => 4n}  = " + r);
+}
+
+o = Object(0b10n);
+let r = bigIntRShift(0b11n, o);
+assert.sameValue(r, 0n, 0b11n + " >> Object(0b10n) = " + r);
+
+o2 = Object(0b1100001n);
+r = bigIntRShift(o2, o);
+assert.sameValue(r, 0b11000n, "Object(0b1100001n) * Object(10n) = " + r);
+
diff --git a/JSTests/stress/big-int-right-shift-jit.js b/JSTests/stress/big-int-right-shift-jit.js
new file mode 100644 (file)
index 0000000..6bc3f84
--- /dev/null
@@ -0,0 +1,19 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntRShift(x, y) {
+    return x >> y;
+}
+noInline(bigIntRShift);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntRShift(0b10001n, 4n);
+    assert.sameValue(r, 1n, 0b10001n + " >> " + 4n + " = " + r);
+}
+
diff --git a/JSTests/stress/value-rshift-ai-rule.js b/JSTests/stress/value-rshift-ai-rule.js
new file mode 100644 (file)
index 0000000..4c3e026
--- /dev/null
@@ -0,0 +1,21 @@
+function assert(a, e) {
+    if (a !== e)
+        throw new Error("Expected: " + e + " bug got: " + a);
+}
+
+(() => {
+    let predicate = true;
+    function foo(a) {
+        let v = a;
+        if (predicate)
+            v = 10;
+
+        let c = v >> 2;
+        return c;
+    }
+    noInline(foo);
+
+    for (let i = 0; i < 10000; i++) {
+        assert(foo(10.5), 2);
+    }
+})();
diff --git a/PerformanceTests/BigIntBench/big-int-simple-rshift.js b/PerformanceTests/BigIntBench/big-int-simple-rshift.js
new file mode 100644 (file)
index 0000000..a385fe6
--- /dev/null
@@ -0,0 +1,15 @@
+function bigInt(a, b) {
+    let c = a >> b;
+    return (a >> c) - b;
+}
+noInline(bigInt);
+
+for (let i = 0; i < 100000; i++) {
+    bigInt(0b1111n, 2n);
+}
+
+let out;
+for (let i = 0; i < 100000; i++) {
+    out = bigInt(0xffffffffffffffffffn, 64n);
+}
+
index 0aa6e7a..672439c 100644 (file)
@@ -1,3 +1,13 @@
+2019-09-24  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueBitRShift into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=192663
+
+        Reviewed by Robin Morisset.
+
+        * BigIntBench/big-int-simple-rshift.js: Added.
+        (bigInt):
+
 2019-09-09  Jon Lee  <jonlee@apple.com>
 
         Upload triangles tests for 3D suite in MotionMark
index 0362fe9..50eb07d 100644 (file)
@@ -1,3 +1,93 @@
+2019-09-24  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueBitRShift into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=192663
+
+        Reviewed by Robin Morisset.
+
+        We are introducing a new node called ValueBitRShift that is
+        responsible to handle speculation of `UntypedUse` and `BigIntUse` during
+        DFG. Following the approach of other bitwise operations, we
+        now have 2 nodes to handle ">>" operator during JIT, mainly because
+        of the introduction of BigInt, that makes this operator result into
+        Int32 or BigInt. We renamed `BitRShift` to `ArithBitRShift` and such
+        node handles Integers and Numbers speculation and can only return
+        Int32 values.
+
+        * bytecode/BytecodeList.rb:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        * bytecode/Opcode.h:
+
+        Adding support to ValueProfile to `op_rshift` to be used during
+        prediction propagation.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp):
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+
+        Adding support to still do constant propagation of ValueBitRShift when
+        it is `UntypedUse`.
+
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+
+        `ValueBitRshift` can trigger GC when it is `BigIntUse` because the
+        operation `JSBigInt::signedRightShift` potentially allocates new
+        JSBigInts. It also can trigger GC when it is `UntypedUse` because it
+        can execute arbitrary code.
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+
+        The fixup rule of `ValueBitRShift` checks if it should fixup for
+        `BigIntUse` or `UntypedUse`. If those checks fail, we fallback to
+        `ArithBitRShift`.
+
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasNumericResult):
+        (JSC::DFG::Node::hasHeapPrediction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+
+        We are using the same rule used by `ValueBitLShift` to propagate
+        types. We try to propagate the type based on operation's input, but
+        fallback to `getHeapPrediction()` if this is not possible.
+
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::emitUntypedRightShiftBitOp):
+        (JSC::DFG::SpeculativeJIT::compileValueBitRShift):
+        (JSC::DFG::SpeculativeJIT::compileShiftOp):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::shiftOp):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStrengthReductionPhase.cpp:
+        (JSC::DFG::StrengthReductionPhase::handleNode):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitRShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithBitRShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileBitRShift): Deleted.
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+
 2019-09-24  Mark Lam  <mark.lam@apple.com>
 
         Refactor cellSize() out of VMInspector::verifyCellSize().
index 1ba41f1..8bc0182 100644 (file)
@@ -256,7 +256,6 @@ op_group :BinaryOp,
         :beloweq,
         :mod,
         :pow,
-        :rshift,
         :urshift,
     ],
     args: {
@@ -291,6 +290,7 @@ op_group :ValueProfiledBinaryOp,
         :bitor,
         :bitxor,
         :lshift,
+        :rshift,
     ],
     args: {
         dst: VirtualRegister,
index b790947..fad95e2 100644 (file)
@@ -547,6 +547,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
         LINK(OpBitnot, profile)
         LINK(OpBitxor, profile)
         LINK(OpLshift, profile)
+        LINK(OpRshift, profile)
 
         LINK(OpGetById, profile)
 
index 42a56fb..f314709 100644 (file)
@@ -109,6 +109,7 @@ extern const unsigned opcodeLengths[];
     macro(OpBitnot) \
     macro(OpBitxor) \
     macro(OpLshift) \
+    macro(OpRshift) \
 
 #define FOR_EACH_OPCODE_WITH_ARRAY_PROFILE(macro) \
     macro(OpHasIndexedProperty) \
index 9b637fd..1e64abc 100644 (file)
@@ -261,7 +261,8 @@ bool AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp(Node*
         case ArithBitXor:
             setConstant(node, JSValue(a ^ b));
             break;
-        case BitRShift:
+        case ArithBitRShift:
+        case ValueBitRShift:
             setConstant(node, JSValue(a >> (static_cast<uint32_t>(b) & 0x1f)));
             break;
         case ValueBitLShift:
@@ -512,6 +513,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case ValueBitXor:
     case ValueBitAnd:
     case ValueBitOr:
+    case ValueBitRShift:
     case ValueBitLShift: {
         if (handleConstantBinaryBitwiseOp(node))
             break;
@@ -528,7 +530,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
-    case BitRShift:
+    case ArithBitRShift:
     case ArithBitLShift:
     case BitURShift: {
         if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
index 7f3a2a5..0280171 100644 (file)
@@ -128,7 +128,8 @@ private:
             return power > 31;
         }
             
-        case BitRShift:
+        case ArithBitRShift:
+        case ValueBitRShift:
         case BitURShift: {
             if (power > 31)
                 return true;
@@ -226,9 +227,10 @@ private:
         case ValueBitAnd:
         case ValueBitOr:
         case ValueBitXor:
-        case BitRShift:
         case ValueBitLShift:
         case ArithBitLShift:
+        case ArithBitRShift:
+        case ValueBitRShift:
         case BitURShift:
         case ArithIMul: {
             flags |= NodeBytecodeUsesAsInt;
index 07f69e6..d6d2701 100644 (file)
@@ -5159,7 +5159,12 @@ void ByteCodeParser::parseBlock(unsigned limit)
             auto bytecode = currentInstruction->as<OpRshift>();
             Node* op1 = get(bytecode.m_lhs);
             Node* op2 = get(bytecode.m_rhs);
-            set(bytecode.m_dst, addToGraph(BitRShift, op1, op2));
+            if (op1->hasNumberOrAnyIntResult() && op2->hasNumberOrAnyIntResult())
+                set(bytecode.m_dst, addToGraph(ArithBitRShift, op1, op2));
+            else {
+                SpeculatedType prediction = getPredictionWithoutOSRExit();
+                set(bytecode.m_dst, addToGraph(ValueBitRShift, OpInfo(), OpInfo(prediction), op1, op2));
+            }
             NEXT_OPCODE(op_rshift);
         }
 
index 9a8ad07..0828fd8 100644 (file)
@@ -282,7 +282,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case ArithBitOr:
     case ArithBitXor:
     case ArithBitLShift:
-    case BitRShift:
+    case ArithBitRShift:
     case BitURShift:
         if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
             read(World);
@@ -686,6 +686,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case ValueMod:
     case ValuePow:
     case ValueBitLShift:
+    case ValueBitRShift:
         if (node->isBinaryUseKind(BigIntUse)) {
             def(PureValue(node));
             return;
index c9733d0..a98f795 100644 (file)
@@ -85,7 +85,7 @@ bool doesGC(Graph& graph, Node* node)
     case ArithBitOr:
     case ArithBitXor:
     case ArithBitLShift:
-    case BitRShift:
+    case ArithBitRShift:
     case BitURShift:
     case ValueToInt32:
     case UInt32ToNumber:
@@ -383,6 +383,7 @@ bool doesGC(Graph& graph, Node* node)
     case ValueBitOr:
     case ValueBitXor:
     case ValueBitLShift:
+    case ValueBitRShift:
     case ValueAdd:
     case ValueSub:
     case ValueMul:
index d064322..c7d7418 100644 (file)
@@ -216,6 +216,7 @@ private:
         }
 
         case ValueBitLShift:
+        case ValueBitRShift:
         case ValueBitXor:
         case ValueBitOr:
         case ValueBitAnd: {
@@ -245,6 +246,9 @@ private:
             case ValueBitLShift:
                 node->setOp(ArithBitLShift);
                 break;
+            case ValueBitRShift:
+                node->setOp(ArithBitRShift);
+                break;
             default:
                 DFG_CRASH(m_graph, node, "Unexpected node during ValueBit operation fixup");
                 break;
@@ -281,6 +285,7 @@ private:
             break;
         }
 
+        case ArithBitRShift:
         case ArithBitLShift: 
         case ArithBitXor:
         case ArithBitOr:
@@ -290,7 +295,6 @@ private:
             break;
         }
 
-        case BitRShift:
         case BitURShift: {
             if (Node::shouldSpeculateUntypedForBitOps(node->child1().node(), node->child2().node())) {
                 fixEdge<UntypedUse>(node->child1());
index 2d5524a..d68ba6e 100644 (file)
@@ -1419,6 +1419,9 @@ public:
         case ValueBitAnd:
         case ValueBitOr:
         case ValueBitXor:
+        case ValueBitNot:
+        case ValueBitLShift:
+        case ValueBitRShift:
         case ValueNegate:
             return true;
         default:
@@ -1729,6 +1732,7 @@ public:
         case ValueBitXor:
         case ValueBitNot:
         case ValueBitLShift:
+        case ValueBitRShift:
         case CallObjectConstructor:
         case LoadKeyFromMapBucket:
         case LoadValueFromMapBucket:
index 1ebdfd1..4101f5c 100644 (file)
@@ -125,7 +125,8 @@ namespace JSC { namespace DFG {
     macro(ArithBitXor, NodeResultInt32) \
     macro(ArithBitLShift, NodeResultInt32) \
     macro(ValueBitLShift, NodeResultJS | NodeMustGenerate) \
-    macro(BitRShift, NodeResultInt32) \
+    macro(ArithBitRShift, NodeResultInt32) \
+    macro(ValueBitRShift, NodeResultJS | NodeMustGenerate) \
     macro(BitURShift, NodeResultInt32) \
     /* Bitwise operators call ToInt32 on their operands. */\
     macro(ValueToInt32, NodeResultInt32) \
index c315c26..e0f7082 100644 (file)
@@ -524,18 +524,15 @@ EncodedJSValue JIT_OPERATION operationValueBitLShift(ExecState* exec, EncodedJSV
 
 EncodedJSValue JIT_OPERATION operationValueBitRShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
 {
-    VM& vm = exec->vm();
-    NativeCallFrameTracer tracer(vm, exec);
-    auto scope = DECLARE_THROW_SCOPE(vm);
+    auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
+        return JSBigInt::signedRightShift(exec, left, right);
+    };
 
-    JSValue op1 = JSValue::decode(encodedOp1);
-    JSValue op2 = JSValue::decode(encodedOp2);
+    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
+        return left >> (right & 0x1f);
+    };
 
-    int32_t a = op1.toInt32(exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    scope.release();
-    uint32_t b = op2.toUInt32(exec);
-    return JSValue::encode(jsNumber(a >> (b & 0x1f)));
+    return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in signed right shift operation."_s);
 }
 
 EncodedJSValue JIT_OPERATION operationValueBitURShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
@@ -1483,6 +1480,17 @@ JSCell* JIT_OPERATION operationAddBigInt(ExecState* exec, JSCell* op1, JSCell* o
     return JSBigInt::add(exec, leftOperand, rightOperand);
 }
 
+JSCell* JIT_OPERATION operationBitRShiftBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    
+    JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
+    JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
+    
+    return JSBigInt::signedRightShift(exec, leftOperand, rightOperand);
+}
+
 JSCell* JIT_OPERATION operationBitOrBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
 {
     VM& vm = exec->vm();
index 744a50d..294392e 100644 (file)
@@ -181,6 +181,7 @@ JSCell* JIT_OPERATION operationBitNotBigInt(ExecState*, JSCell* op1) WTF_INTERNA
 JSCell* JIT_OPERATION operationBitOrBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationBitLShiftBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationAddBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationBitRShiftBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationBitXorBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 size_t JIT_OPERATION operationSameValue(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*, EncodedJSValue);
index c3d921c..41f6c37 100644 (file)
@@ -179,6 +179,7 @@ private:
             break;
         }
 
+        case ValueBitRShift:
         case ValueBitLShift: {
             SpeculatedType left = node->child1()->prediction();
             SpeculatedType right = node->child2()->prediction();
@@ -783,7 +784,7 @@ private:
         case ArithBitAnd:
         case ArithBitOr:
         case ArithBitXor:
-        case BitRShift:
+        case ArithBitRShift:
         case ArithBitLShift:
         case BitURShift:
         case ArithIMul:
@@ -1166,6 +1167,7 @@ private:
         case ValueMod:
         case ValuePow:
         case ValueBitLShift:
+        case ValueBitRShift:
         case ArithAdd:
         case ArithSub:
         case ArithNegate:
index 7d8eee8..588b98d 100644 (file)
@@ -207,7 +207,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ArithBitOr:
     case ArithBitXor:
     case ArithBitLShift:
-    case BitRShift:
+    case ArithBitRShift:
     case BitURShift:
     case ValueToInt32:
     case UInt32ToNumber:
@@ -237,6 +237,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ValueBitOr:
     case ValueBitNot:
     case ValueBitLShift:
+    case ValueBitRShift:
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
index 51ba348..cede902 100644 (file)
@@ -3764,9 +3764,9 @@ void SpeculativeJIT::compileBitwiseOp(Node* node)
 
 void SpeculativeJIT::emitUntypedRightShiftBitOp(Node* node)
 {
-    J_JITOperation_EJJ snippetSlowPathFunction = node->op() == BitRShift
+    J_JITOperation_EJJ snippetSlowPathFunction = node->op() == ValueBitRShift
         ? operationValueBitRShift : operationValueBitURShift;
-    JITRightShiftGenerator::ShiftType shiftType = node->op() == BitRShift
+    JITRightShiftGenerator::ShiftType shiftType = node->op() == ValueBitRShift
         ? JITRightShiftGenerator::SignedShift : JITRightShiftGenerator::UnsignedShift;
 
     Edge& leftChild = node->child1();
@@ -3889,6 +3889,34 @@ void SpeculativeJIT::compileValueLShiftOp(Node* node)
     emitUntypedBitOp<JITLeftShiftGenerator, operationValueBitLShift>(node);
 }
 
+void SpeculativeJIT::compileValueBitRShift(Node* node)
+{
+    Edge& leftChild = node->child1();
+    Edge& rightChild = node->child2();
+
+    if (node->isBinaryUseKind(BigIntUse)) {
+        SpeculateCellOperand left(this, leftChild);
+        SpeculateCellOperand right(this, rightChild);
+        GPRReg leftGPR = left.gpr();
+        GPRReg rightGPR = right.gpr();
+
+        speculateBigInt(leftChild, leftGPR);
+        speculateBigInt(rightChild, rightGPR);
+
+        flushRegisters();
+        GPRFlushedCallResult result(this);
+        GPRReg resultGPR = result.gpr();
+        callOperation(operationBitRShiftBigInt, resultGPR, leftGPR, rightGPR);
+        m_jit.exceptionCheck();
+
+        cellResult(resultGPR, node);
+        return;
+    }
+
+    ASSERT(leftChild.useKind() == UntypedUse && rightChild.useKind() == UntypedUse);
+    emitUntypedRightShiftBitOp(node);
+}
+
 void SpeculativeJIT::compileShiftOp(Node* node)
 {
     NodeType op = node->op();
@@ -3896,14 +3924,9 @@ void SpeculativeJIT::compileShiftOp(Node* node)
     Edge& rightChild = node->child2();
 
     if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
-        switch (op) {
-        case BitRShift:
-        case BitURShift:
-            emitUntypedRightShiftBitOp(node);
-            return;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-        }
+        RELEASE_ASSERT(op == BitURShift);
+        emitUntypedRightShiftBitOp(node);
+        return;
     }
 
     if (rightChild->isInt32Constant()) {
index 3ee7ace..e372e91 100644 (file)
@@ -660,7 +660,7 @@ public:
     void shiftOp(NodeType op, GPRReg op1, int32_t shiftAmount, GPRReg result)
     {
         switch (op) {
-        case BitRShift:
+        case ArithBitRShift:
             m_jit.rshift32(op1, Imm32(shiftAmount), result);
             break;
         case ArithBitLShift:
@@ -676,7 +676,7 @@ public:
     void shiftOp(NodeType op, GPRReg op1, GPRReg shiftAmount, GPRReg result)
     {
         switch (op) {
-        case BitRShift:
+        case ArithBitRShift:
             m_jit.rshift32(op1, shiftAmount, result);
             break;
         case ArithBitLShift:
@@ -1325,6 +1325,7 @@ public:
 
     void emitUntypedRightShiftBitOp(Node*);
     void compileValueLShiftOp(Node*);
+    void compileValueBitRShift(Node*);
     void compileShiftOp(Node*);
 
     template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction>
index 8430570..41c4467 100644 (file)
@@ -2002,7 +2002,11 @@ void SpeculativeJIT::compile(Node* node)
         compileValueLShiftOp(node);
         break;
 
-    case BitRShift:
+    case ValueBitRShift:
+        compileValueBitRShift(node);
+        break;
+
+    case ArithBitRShift:
     case ArithBitLShift:
     case BitURShift:
         compileShiftOp(node);
index bd9c3bb..a35b4ed 100644 (file)
@@ -2104,7 +2104,11 @@ void SpeculativeJIT::compile(Node* node)
         compileValueLShiftOp(node);
         break;
 
-    case BitRShift:
+    case ValueBitRShift:
+        compileValueBitRShift(node);
+        break;
+
+    case ArithBitRShift:
     case ArithBitLShift:
     case BitURShift:
         compileShiftOp(node);
index 3c0c596..1a8f72d 100644 (file)
@@ -93,7 +93,7 @@ private:
             break;
             
         case ArithBitLShift:
-        case BitRShift:
+        case ArithBitRShift:
         case BitURShift:
             if (m_node->child1().useKind() != UntypedUse && m_node->child2()->isInt32Constant() && !(m_node->child2()->asInt32() & 0x1f)) {
                 convertToIdentityOverChild1();
index ead259a..d5b5528 100644 (file)
@@ -63,7 +63,7 @@ inline CapabilityLevel canCompile(Node* node)
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
-    case BitRShift:
+    case ArithBitRShift:
     case ArithBitLShift:
     case BitURShift:
     case CheckStructure:
@@ -96,6 +96,7 @@ inline CapabilityLevel canCompile(Node* node)
     case ValueBitOr:
     case ValueBitNot:
     case ValueBitLShift:
+    case ValueBitRShift:
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
index a140b0b..867bd77 100644 (file)
@@ -851,8 +851,11 @@ private:
         case ValueBitXor:
             compileValueBitXor();
             break;
-        case BitRShift:
-            compileBitRShift();
+        case ValueBitRShift:
+            compileValueBitRShift();
+            break;
+        case ArithBitRShift:
+            compileArithBitRShift();
             break;
         case ArithBitLShift:
             compileArithBitLShift();
@@ -3197,12 +3200,22 @@ private:
         setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
     }
     
-    void compileBitRShift()
+    void compileValueBitRShift()
     {
-        if (m_node->isBinaryUseKind(UntypedUse)) {
-            emitRightShiftSnippet(JITRightShiftGenerator::SignedShift);
+        if (m_node->isBinaryUseKind(BigIntUse)) {
+            LValue left = lowBigInt(m_node->child1());
+            LValue right = lowBigInt(m_node->child2());
+
+            LValue result = vmCall(pointerType(), m_out.operation(operationBitRShiftBigInt), m_callFrame, left, right);
+            setJSValue(result);
             return;
         }
+
+        emitRightShiftSnippet(JITRightShiftGenerator::SignedShift);
+    }
+
+    void compileArithBitRShift()
+    {
         setInt32(m_out.aShr(
             lowInt32(m_node->child1()),
             m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
index 16a2393..7f4eb83 100644 (file)
@@ -1157,7 +1157,7 @@ bitOpProfiled(lshift, OpLshift,
     macro (left, right) lshifti left, right end)
 
 
-bitOp(rshift, OpRshift,
+bitOpProfiled(rshift, OpRshift,
     macro (left, right) rshifti left, right end)
 
 
index 1123d17..a908e03 100644 (file)
@@ -772,13 +772,13 @@ SLOW_PATH_DECL(slow_path_rshift)
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
             JSBigInt* result = JSBigInt::signedRightShift(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             CHECK_EXCEPTION();
-            RETURN(result);
+            RETURN_PROFILED(result);
         }
 
-        THROW(createTypeError(exec, "Invalid mix of BigInt and other type in signed right shift operation."));
+        THROW(createTypeError(exec, "Invalid mix of BigInt and other type in signed right shift operation."_s));
     }
 
-    RETURN(jsNumber(WTF::get<int32_t>(leftNumeric) >> (WTF::get<int32_t>(rightNumeric) & 31)));
+    RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) >> (WTF::get<int32_t>(rightNumeric) & 31)));
 }
 
 SLOW_PATH_DECL(slow_path_urshift)