[BigInt] Add ValueBitLShift into DFG
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Jul 2019 14:47:36 +0000 (14:47 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Jul 2019 14:47:36 +0000 (14:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=192664

Reviewed by Saam Barati.

JSTests:

We are adding tests to cover ValueBitwise operations AI changes.

* stress/big-int-left-shift-untyped.js: Added.
* stress/bit-op-with-object-returning-int32.js:
* stress/value-bit-and-ai-rule.js: Added.
* stress/value-bit-lshift-ai-rule.js: Added.
* stress/value-bit-or-ai-rule.js: Added.
* stress/value-bit-xor-ai-rule.js: Added.

PerformanceTests:

* BigIntBench/big-int-simple-lshift.js: Added.

Source/JavaScriptCore:

This patch is splitting the `BitLShift` into `ArithBitLShift` and
`ValueBitLShift` to handle BigInt speculation more efficiently during
DFG and FTL layers. Following the same approach of other `ValueBitOps`,
`ValueBitLShift` handles Untyped and BigInt speculations, while
`ArithBitLShift` handles number and boolean operands and always results into
Int32.

* bytecode/BytecodeList.rb:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
* bytecode/Opcode.h:
* dfg/DFGAbstractInterpreter.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

We moved `BitLShift` constant fold rules to a new method
`handleConstantBinaryBitwiseOp` to be reused by `ArithBitLShift` and
`ValueBitLShift`. This also enables support of constant folding on other
bitwise operations like `ValueBitAnd`, `ValueBitOr` and `ValueBitXor`, when
their binary use kind is UntypedUse. Such cases can happen on those
nodes because fixup phase is conservative.

* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
(JSC::DFG::ByteCodeParser::parseBlock):

We parse `op_lshift` as `ArithBitLShift` when its operands are numbers.
Otherwise, we fallback to `ValueBitLShift` and rely on fixup phase to
convert `ValueBitLShift` into `ArithBitLShift` when possible.

* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):

`ArithBitLShift` has the same clobberize rules as former `BitLShift`.
`ValueBitLShift` only clobberize world when it is UntypedUse.

* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):

`ValueBitLShift` can GC when `BigIntUse` because it allocates new
JSBigInts to perform this operation. It also can GC on UntypedUse
because of observable user code.

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

`ValueBitLShift` and `ArithBitLShift` has the same fixup rules of
other binary bitwise operations. In the case of `ValueBitLShift`
We check if we should speculate on BigInt or Untyped and fallback to
`ArithBitLShift` when both cheks fail.

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

We updated `operationValueBitLShift` to handle BigInt cases. Also, we
added `operationBitLShiftBigInt` that is used when we compile
`ValueBitLValueBitLShift(BigIntUse)`.

* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:

`ValueBitLShift`'s prediction propagation rules differs from other
bitwise operations, because using only heap prediction for this node causes
significant performance regression on Octane's zlib and mandreel.
The reason is because of cases where a function is compiled but the
instruction `op_lshift` was never executed before. If we use
`getPrediction()` we will emit a `ForceOSRExit`, resulting in more OSR
than desired. To solve such issue, we are then using
`getPredictionWithoutOSR()` and falling back to `getHeapPrediction()`
only on cases where we can't rely on node's input types.

* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileValueLShiftOp):
(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::compileArithBitLShift):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitLShift):
(JSC::FTL::DFG::LowerDFGToB3::compileBitLShift): Deleted.
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):

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

36 files changed:
JSTests/ChangeLog
JSTests/stress/big-int-left-shift-untyped.js [new file with mode: 0644]
JSTests/stress/bit-op-with-object-returning-int32.js
JSTests/stress/value-bit-and-ai-rule.js [new file with mode: 0644]
JSTests/stress/value-bit-lshift-ai-rule.js [new file with mode: 0644]
JSTests/stress/value-bit-or-ai-rule.js [new file with mode: 0644]
JSTests/stress/value-bit-xor-ai-rule.js [new file with mode: 0644]
PerformanceTests/BigIntBench/big-int-simple-lshift.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/DFGAbstractInterpreter.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/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

index d0f1732..f73390e 100644 (file)
@@ -1,3 +1,19 @@
+2019-07-12  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueBitLShift into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=192664
+
+        Reviewed by Saam Barati.
+
+        We are adding tests to cover ValueBitwise operations AI changes.
+
+        * stress/big-int-left-shift-untyped.js: Added.
+        * stress/bit-op-with-object-returning-int32.js:
+        * stress/value-bit-and-ai-rule.js: Added.
+        * stress/value-bit-lshift-ai-rule.js: Added.
+        * stress/value-bit-or-ai-rule.js: Added.
+        * stress/value-bit-xor-ai-rule.js: Added.
+
 2019-07-11  Justin Michaud  <justin_michaud@apple.com>
 
         Add b3 macro lowering for CheckMul on arm64
 2019-07-11  Justin Michaud  <justin_michaud@apple.com>
 
         Add b3 macro lowering for CheckMul on arm64
diff --git a/JSTests/stress/big-int-left-shift-untyped.js b/JSTests/stress/big-int-left-shift-untyped.js
new file mode 100644 (file)
index 0000000..3d36bd3
--- /dev/null
@@ -0,0 +1,22 @@
+//@ runBigIntEnabled
+
+function assert(a, e) {
+    if (a !== e)
+        throw new Error("Expected: " + e + " but got: " + a);
+}
+
+function untypedLShift(a, b) {
+    return a << b;
+}
+noInline(untypedLShift);
+
+let o = {
+    valueOf: () => 0b11101n
+}
+
+for (var i = 0; i < 10000; i++) {
+    assert(untypedLShift(0b11101n, 10n), 0b111010000000000n);
+    assert(untypedLShift(o, 10n), 0b111010000000000n);
+    assert(untypedLShift(0b11101, 10), 0b111010000000000);
+}
+
index 1749afb..609d9f2 100644 (file)
@@ -46,3 +46,13 @@ for (var i = 0; i < 10000; i++)
 
 assert(numberOfDFGCompiles(bitNot) <= 1, true);
 
 
 assert(numberOfDFGCompiles(bitNot) <= 1, true);
 
+function bitLShift(a, b) {
+    return a << b;
+}
+noInline(bitLShift);
+
+for (var i = 0; i < 10000; i++)
+    assert(bitLShift(o, 3), 0b1101000);
+
+assert(numberOfDFGCompiles(bitLShift) <= 1, true);
+
diff --git a/JSTests/stress/value-bit-and-ai-rule.js b/JSTests/stress/value-bit-and-ai-rule.js
new file mode 100644 (file)
index 0000000..bb9ba9b
--- /dev/null
@@ -0,0 +1,22 @@
+//@ runBigIntEnabled
+
+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 = 0b1010;
+
+    let c = v & 0b11;
+    return c;
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    assert(foo(0b1010n), 0b10);
+}
+
diff --git a/JSTests/stress/value-bit-lshift-ai-rule.js b/JSTests/stress/value-bit-lshift-ai-rule.js
new file mode 100644 (file)
index 0000000..4b15fb2
--- /dev/null
@@ -0,0 +1,22 @@
+//@ runBigIntEnabled
+
+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 = 1;
+
+    let c = v << 4;
+    return c;
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    assert(foo(1n), 16);
+}
+
diff --git a/JSTests/stress/value-bit-or-ai-rule.js b/JSTests/stress/value-bit-or-ai-rule.js
new file mode 100644 (file)
index 0000000..b12f554
--- /dev/null
@@ -0,0 +1,22 @@
+//@ runBigIntEnabled
+
+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 = 0b1000;
+
+    let c = v | 0b11;
+    return c;
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    assert(foo(0b1000n), 0b1011);
+}
+
diff --git a/JSTests/stress/value-bit-xor-ai-rule.js b/JSTests/stress/value-bit-xor-ai-rule.js
new file mode 100644 (file)
index 0000000..13c1fa3
--- /dev/null
@@ -0,0 +1,22 @@
+//@ runBigIntEnabled
+
+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 = 0b1010;
+
+    let c = v ^ 0b0101;
+    return c;
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    assert(foo(0b1010n), 0b1111);
+}
+
diff --git a/PerformanceTests/BigIntBench/big-int-simple-lshift.js b/PerformanceTests/BigIntBench/big-int-simple-lshift.js
new file mode 100644 (file)
index 0000000..533e799
--- /dev/null
@@ -0,0 +1,15 @@
+function bigInt(a, b) {
+    let c = a << b;
+    return c + b;
+}
+noInline(bigInt);
+
+for (let i = 0; i < 100000; i++) {
+    bigInt(0b1111n, 0x100n);
+}
+
+let out;
+for (let i = 0; i < 100000; i++) {
+    out = bigInt(0xfffffffffffffffffffffffn, 10n);
+}
+
index 6e15a28..5d1627d 100644 (file)
@@ -1,3 +1,12 @@
+2019-07-12  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueBitLShift into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=192664
+
+        Reviewed by Saam Barati.
+
+        * BigIntBench/big-int-simple-lshift.js: Added.
+
 2019-06-28  Konstantin Tokarev  <annulen@yandex.ru>
 
         Remove traces of ENABLE_ICONDATABASE remaining after its removal in 219733
 2019-06-28  Konstantin Tokarev  <annulen@yandex.ru>
 
         Remove traces of ENABLE_ICONDATABASE remaining after its removal in 219733
index 277420c..36fcdad 100644 (file)
@@ -1,3 +1,112 @@
+2019-07-12  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueBitLShift into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=192664
+
+        Reviewed by Saam Barati.
+
+        This patch is splitting the `BitLShift` into `ArithBitLShift` and
+        `ValueBitLShift` to handle BigInt speculation more efficiently during
+        DFG and FTL layers. Following the same approach of other `ValueBitOps`,
+        `ValueBitLShift` handles Untyped and BigInt speculations, while
+        `ArithBitLShift` handles number and boolean operands and always results into
+        Int32. 
+
+        * bytecode/BytecodeList.rb:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        * bytecode/Opcode.h:
+        * dfg/DFGAbstractInterpreter.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp):
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+
+        We moved `BitLShift` constant fold rules to a new method
+        `handleConstantBinaryBitwiseOp` to be reused by `ArithBitLShift` and
+        `ValueBitLShift`. This also enables support of constant folding on other
+        bitwise operations like `ValueBitAnd`, `ValueBitOr` and `ValueBitXor`, when
+        their binary use kind is UntypedUse. Such cases can happen on those
+        nodes because fixup phase is conservative.
+
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo):
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+
+        We parse `op_lshift` as `ArithBitLShift` when its operands are numbers.
+        Otherwise, we fallback to `ValueBitLShift` and rely on fixup phase to
+        convert `ValueBitLShift` into `ArithBitLShift` when possible.
+
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+
+        `ArithBitLShift` has the same clobberize rules as former `BitLShift`.
+        `ValueBitLShift` only clobberize world when it is UntypedUse.
+
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+
+        `ValueBitLShift` can GC when `BigIntUse` because it allocates new
+        JSBigInts to perform this operation. It also can GC on UntypedUse
+        because of observable user code.
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+
+        `ValueBitLShift` and `ArithBitLShift` has the same fixup rules of
+        other binary bitwise operations. In the case of `ValueBitLShift`
+        We check if we should speculate on BigInt or Untyped and fallback to
+        `ArithBitLShift` when both cheks fail.
+
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasHeapPrediction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+
+        We updated `operationValueBitLShift` to handle BigInt cases. Also, we
+        added `operationBitLShiftBigInt` that is used when we compile
+        `ValueBitLValueBitLShift(BigIntUse)`.
+
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+
+        `ValueBitLShift`'s prediction propagation rules differs from other
+        bitwise operations, because using only heap prediction for this node causes
+        significant performance regression on Octane's zlib and mandreel.
+        The reason is because of cases where a function is compiled but the
+        instruction `op_lshift` was never executed before. If we use
+        `getPrediction()` we will emit a `ForceOSRExit`, resulting in more OSR
+        than desired. To solve such issue, we are then using
+        `getPredictionWithoutOSR()` and falling back to `getHeapPrediction()`
+        only on cases where we can't rely on node's input types.
+
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileValueLShiftOp):
+        (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::compileArithBitLShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitLShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileBitLShift): Deleted.
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+
 2019-07-12  Keith Miller  <keith_miller@apple.com>
 
         getIndexQuickly should be const
 2019-07-12  Keith Miller  <keith_miller@apple.com>
 
         getIndexQuickly should be const
index ea1bbe2..8f769bd 100644 (file)
@@ -226,7 +226,6 @@ op_group :BinaryOp,
         :beloweq,
         :mod,
         :pow,
         :beloweq,
         :mod,
         :pow,
-        :lshift,
         :rshift,
         :urshift,
     ],
         :rshift,
         :urshift,
     ],
@@ -261,6 +260,7 @@ op_group :ValueProfiledBinaryOp,
         :bitand,
         :bitor,
         :bitxor,
         :bitand,
         :bitor,
         :bitxor,
+        :lshift,
     ],
     args: {
         dst: VirtualRegister,
     ],
     args: {
         dst: VirtualRegister,
index dacae67..93d0fa9 100644 (file)
@@ -545,6 +545,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
         LINK(OpBitor, profile)
         LINK(OpBitnot, profile)
         LINK(OpBitxor, profile)
         LINK(OpBitor, profile)
         LINK(OpBitnot, profile)
         LINK(OpBitxor, profile)
+        LINK(OpLshift, profile)
 
         LINK(OpGetById, profile)
 
 
         LINK(OpGetById, profile)
 
index c921dd8..70ce05b 100644 (file)
@@ -107,6 +107,7 @@ extern const unsigned opcodeLengths[];
     macro(OpBitor) \
     macro(OpBitnot) \
     macro(OpBitxor) \
     macro(OpBitor) \
     macro(OpBitnot) \
     macro(OpBitxor) \
+    macro(OpLshift) \
 
 #define FOR_EACH_OPCODE_WITH_ARRAY_PROFILE(macro) \
     macro(OpHasIndexedProperty) \
 
 #define FOR_EACH_OPCODE_WITH_ARRAY_PROFILE(macro) \
     macro(OpHasIndexedProperty) \
index 5d5988c..974b0cf 100644 (file)
@@ -218,6 +218,8 @@ private:
     void clobberWorld();
     void didFoldClobberWorld();
     
     void clobberWorld();
     void didFoldClobberWorld();
     
+    bool handleConstantBinaryBitwiseOp(Node*);
+
     template<typename Functor>
     void forAllValues(unsigned indexInBlock, Functor&);
     
     template<typename Functor>
     void forAllValues(unsigned indexInBlock, Functor&);
     
index 2e0d01d..89daeb9 100644 (file)
@@ -234,6 +234,51 @@ inline ToThisResult isToThisAnIdentity(VM& vm, bool isStrictMode, AbstractValue&
 }
 
 template<typename AbstractStateType>
 }
 
 template<typename AbstractStateType>
+bool AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp(Node* node)
+{
+    JSValue left = forNode(node->child1()).value();
+    JSValue right = forNode(node->child2()).value();
+    if (left && right && left.isInt32() && right.isInt32()) {
+        int32_t a = left.asInt32();
+        int32_t b = right.asInt32();
+        if (node->isBinaryUseKind(UntypedUse))
+            didFoldClobberWorld();
+        NodeType op = node->op();
+        switch (op) {
+        case ValueBitAnd:
+        case ArithBitAnd:
+            setConstant(node, JSValue(a & b));
+            break;
+        case ValueBitOr:
+        case ArithBitOr:
+            setConstant(node, JSValue(a | b));
+            break;
+        case ValueBitXor:
+        case ArithBitXor:
+            setConstant(node, JSValue(a ^ b));
+            break;
+        case BitRShift:
+            setConstant(node, JSValue(a >> (static_cast<uint32_t>(b) & 0x1f)));
+            break;
+        case ValueBitLShift:
+        case ArithBitLShift:
+            setConstant(node, JSValue(a << (static_cast<uint32_t>(b) & 0x1f)));
+            break;
+        case BitURShift:
+            setConstant(node, JSValue(static_cast<int32_t>(static_cast<uint32_t>(a) >> (static_cast<uint32_t>(b) & 0x1f))));
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+template<typename AbstractStateType>
 bool AbstractInterpreter<AbstractStateType>::handleConstantDivOp(Node* node)
 {
     JSValue left = forNode(node->child1()).value();
 bool AbstractInterpreter<AbstractStateType>::handleConstantDivOp(Node* node)
 {
     JSValue left = forNode(node->child1()).value();
@@ -463,6 +508,10 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case ValueBitXor:
     case ValueBitAnd:
     case ValueBitOr:
     case ValueBitXor:
     case ValueBitAnd:
     case ValueBitOr:
+    case ValueBitLShift: {
+        if (handleConstantBinaryBitwiseOp(node))
+            break;
+
         if (node->binaryUseKind() == BigIntUse)
             setTypeForNode(node, SpecBigInt);
         else {
         if (node->binaryUseKind() == BigIntUse)
             setTypeForNode(node, SpecBigInt);
         else {
@@ -470,12 +519,13 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             setTypeForNode(node, SpecInt32Only | SpecBigInt);
         }
         break;
             setTypeForNode(node, SpecInt32Only | SpecBigInt);
         }
         break;
+    }
             
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
     case BitRShift:
             
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
     case BitRShift:
-    case BitLShift:
+    case ArithBitLShift:
     case BitURShift: {
         if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
             clobberWorld();
     case BitURShift: {
         if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
             clobberWorld();
@@ -483,36 +533,8 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             break;
         }
 
             break;
         }
 
-        JSValue left = forNode(node->child1()).value();
-        JSValue right = forNode(node->child2()).value();
-        if (left && right && left.isInt32() && right.isInt32()) {
-            int32_t a = left.asInt32();
-            int32_t b = right.asInt32();
-            switch (node->op()) {
-            case ArithBitAnd:
-                setConstant(node, JSValue(a & b));
-                break;
-            case ArithBitOr:
-                setConstant(node, JSValue(a | b));
-                break;
-            case ArithBitXor:
-                setConstant(node, JSValue(a ^ b));
-                break;
-            case BitRShift:
-                setConstant(node, JSValue(a >> (static_cast<uint32_t>(b) & 0x1f)));
-                break;
-            case BitLShift:
-                setConstant(node, JSValue(a << (static_cast<uint32_t>(b) & 0x1f)));
-                break;
-            case BitURShift:
-                setConstant(node, JSValue(static_cast<int32_t>(static_cast<uint32_t>(a) >> (static_cast<uint32_t>(b) & 0x1f))));
-                break;
-            default:
-                RELEASE_ASSERT_NOT_REACHED();
-                break;
-            }
+        if (handleConstantBinaryBitwiseOp(node))
             break;
             break;
-        }
         
         if (node->op() == ArithBitAnd
             && (isBoolInt32Speculation(forNode(node->child1()).m_type) ||
         
         if (node->op() == ArithBitAnd
             && (isBoolInt32Speculation(forNode(node->child1()).m_type) ||
index 90d575b..0175926 100644 (file)
@@ -123,7 +123,8 @@ private:
         case ArithBitXor:
         case ValueBitOr:
         case ValueBitXor:
         case ArithBitXor:
         case ValueBitOr:
         case ValueBitXor:
-        case BitLShift: {
+        case ValueBitLShift:
+        case ArithBitLShift: {
             return power > 31;
         }
             
             return power > 31;
         }
             
@@ -226,7 +227,8 @@ private:
         case ValueBitOr:
         case ValueBitXor:
         case BitRShift:
         case ValueBitOr:
         case ValueBitXor:
         case BitRShift:
-        case BitLShift:
+        case ValueBitLShift:
+        case ArithBitLShift:
         case BitURShift:
         case ArithIMul: {
             flags |= NodeBytecodeUsesAsInt;
         case BitURShift:
         case ArithIMul: {
             flags |= NodeBytecodeUsesAsInt;
index a69b01c..aec5871 100644 (file)
@@ -3509,7 +3509,7 @@ bool ByteCodeParser::handleIntrinsicGetter(VirtualRegister result, SpeculatedTyp
         // We can use a BitLShift here because typed arrays will never have a byteLength
         // that overflows int32.
         Node* shiftNode = jsConstant(jsNumber(logSize));
         // We can use a BitLShift here because typed arrays will never have a byteLength
         // that overflows int32.
         Node* shiftNode = jsConstant(jsNumber(logSize));
-        set(result, addToGraph(BitLShift, lengthNode, shiftNode));
+        set(result, addToGraph(ArithBitLShift, lengthNode, shiftNode));
 
         return true;
     }
 
         return true;
     }
@@ -5031,7 +5031,12 @@ void ByteCodeParser::parseBlock(unsigned limit)
             auto bytecode = currentInstruction->as<OpLshift>();
             Node* op1 = get(bytecode.m_lhs);
             Node* op2 = get(bytecode.m_rhs);
             auto bytecode = currentInstruction->as<OpLshift>();
             Node* op1 = get(bytecode.m_lhs);
             Node* op2 = get(bytecode.m_rhs);
-            set(bytecode.m_dst, addToGraph(BitLShift, op1, op2));
+            if (op1->hasNumberOrAnyIntResult() && op2->hasNumberOrAnyIntResult())
+                set(bytecode.m_dst, addToGraph(ArithBitLShift, op1, op2));
+            else {
+                SpeculatedType prediction = getPredictionWithoutOSRExit();
+                set(bytecode.m_dst, addToGraph(ValueBitLShift, OpInfo(), OpInfo(prediction), op1, op2));
+            }
             NEXT_OPCODE(op_lshift);
         }
 
             NEXT_OPCODE(op_lshift);
         }
 
index 81033e9..5a0f117 100644 (file)
@@ -280,7 +280,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
-    case BitLShift:
+    case ArithBitLShift:
     case BitRShift:
     case BitURShift:
         if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
     case BitRShift:
     case BitURShift:
         if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
@@ -682,6 +682,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case ValueDiv:
     case ValueMod:
     case ValuePow:
     case ValueDiv:
     case ValueMod:
     case ValuePow:
+    case ValueBitLShift:
         if (node->isBinaryUseKind(BigIntUse)) {
             def(PureValue(node));
             return;
         if (node->isBinaryUseKind(BigIntUse)) {
             def(PureValue(node));
             return;
index 8d8d6cd..6e8957e 100644 (file)
@@ -84,7 +84,7 @@ bool doesGC(Graph& graph, Node* node)
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
-    case BitLShift:
+    case ArithBitLShift:
     case BitRShift:
     case BitURShift:
     case ValueToInt32:
     case BitRShift:
     case BitURShift:
     case ValueToInt32:
@@ -375,6 +375,7 @@ bool doesGC(Graph& graph, Node* node)
     case ValueBitAnd:
     case ValueBitOr:
     case ValueBitXor:
     case ValueBitAnd:
     case ValueBitOr:
     case ValueBitXor:
+    case ValueBitLShift:
     case ValueAdd:
     case ValueSub:
     case ValueMul:
     case ValueAdd:
     case ValueSub:
     case ValueMul:
index aa177b9..c58aacf 100644 (file)
@@ -215,12 +215,14 @@ private:
             break;
         }
 
             break;
         }
 
+        case ValueBitLShift:
         case ValueBitXor:
         case ValueBitOr:
         case ValueBitAnd: {
             if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) {
                 fixEdge<BigIntUse>(node->child1());
                 fixEdge<BigIntUse>(node->child2());
         case ValueBitXor:
         case ValueBitOr:
         case ValueBitAnd: {
             if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) {
                 fixEdge<BigIntUse>(node->child1());
                 fixEdge<BigIntUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
                 break;
             }
 
                 break;
             }
 
@@ -229,8 +231,7 @@ private:
                 fixEdge<UntypedUse>(node->child2());
                 break;
             }
                 fixEdge<UntypedUse>(node->child2());
                 break;
             }
-
-            // In such case, we need to fallback to ArithBitOp
+            
             switch (op) {
             case ValueBitXor:
                 node->setOp(ArithBitXor);
             switch (op) {
             case ValueBitXor:
                 node->setOp(ArithBitXor);
@@ -241,6 +242,9 @@ private:
             case ValueBitAnd:
                 node->setOp(ArithBitAnd);
                 break;
             case ValueBitAnd:
                 node->setOp(ArithBitAnd);
                 break;
+            case ValueBitLShift:
+                node->setOp(ArithBitLShift);
+                break;
             default:
                 DFG_CRASH(m_graph, node, "Unexpected node during ValueBit operation fixup");
                 break;
             default:
                 DFG_CRASH(m_graph, node, "Unexpected node during ValueBit operation fixup");
                 break;
@@ -277,6 +281,7 @@ private:
             break;
         }
 
             break;
         }
 
+        case ArithBitLShift: 
         case ArithBitXor:
         case ArithBitOr:
         case ArithBitAnd: {
         case ArithBitXor:
         case ArithBitOr:
         case ArithBitAnd: {
@@ -286,7 +291,6 @@ private:
         }
 
         case BitRShift:
         }
 
         case BitRShift:
-        case BitLShift:
         case BitURShift: {
             if (Node::shouldSpeculateUntypedForBitOps(node->child1().node(), node->child2().node())) {
                 fixEdge<UntypedUse>(node->child1());
         case BitURShift: {
             if (Node::shouldSpeculateUntypedForBitOps(node->child1().node(), node->child2().node())) {
                 fixEdge<UntypedUse>(node->child1());
index 28b1d49..439741d 100644 (file)
@@ -1694,6 +1694,7 @@ public:
         case ValueBitOr:
         case ValueBitXor:
         case ValueBitNot:
         case ValueBitOr:
         case ValueBitXor:
         case ValueBitNot:
+        case ValueBitLShift:
         case CallObjectConstructor:
         case LoadKeyFromMapBucket:
         case LoadValueFromMapBucket:
         case CallObjectConstructor:
         case LoadKeyFromMapBucket:
         case LoadValueFromMapBucket:
index 4194c2a..c09a176 100644 (file)
@@ -121,7 +121,8 @@ namespace JSC { namespace DFG {
     macro(ArithBitOr, NodeResultInt32) \
     macro(ValueBitXor, NodeResultJS | NodeMustGenerate) \
     macro(ArithBitXor, NodeResultInt32) \
     macro(ArithBitOr, NodeResultInt32) \
     macro(ValueBitXor, NodeResultJS | NodeMustGenerate) \
     macro(ArithBitXor, NodeResultInt32) \
-    macro(BitLShift, NodeResultInt32) \
+    macro(ArithBitLShift, NodeResultInt32) \
+    macro(ValueBitLShift, NodeResultJS | NodeMustGenerate) \
     macro(BitRShift, NodeResultInt32) \
     macro(BitURShift, NodeResultInt32) \
     /* Bitwise operators call ToInt32 on their operands. */\
     macro(BitRShift, NodeResultInt32) \
     macro(BitURShift, NodeResultInt32) \
     /* Bitwise operators call ToInt32 on their operands. */\
index 717c7a1..d12e2c9 100644 (file)
@@ -478,18 +478,15 @@ EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState* exec, EncodedJSValu
 
 EncodedJSValue JIT_OPERATION operationValueBitLShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
 {
 
 EncodedJSValue JIT_OPERATION operationValueBitLShift(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::leftShift(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 left shift operation."_s);
 }
 
 EncodedJSValue JIT_OPERATION operationValueBitRShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
 }
 
 EncodedJSValue JIT_OPERATION operationValueBitRShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
@@ -1431,6 +1428,17 @@ JSCell* JIT_OPERATION operationBitAndBigInt(ExecState* exec, JSCell* op1, JSCell
     return JSBigInt::bitwiseAnd(exec, leftOperand, rightOperand);
 }
 
     return JSBigInt::bitwiseAnd(exec, leftOperand, rightOperand);
 }
 
+JSCell* JIT_OPERATION operationBitLShiftBigInt(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::leftShift(exec, leftOperand, rightOperand);
+}
+
 JSCell* JIT_OPERATION operationAddBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
 {
     VM* vm = &exec->vm();
 JSCell* JIT_OPERATION operationAddBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
 {
     VM* vm = &exec->vm();
index 7ee6c35..9166578 100644 (file)
@@ -176,6 +176,7 @@ JSCell* JIT_OPERATION operationPowBigInt(ExecState*, JSCell* op1, JSCell* op2) W
 JSCell* JIT_OPERATION operationBitAndBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationBitNotBigInt(ExecState*, JSCell* op1) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationBitOrBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationBitAndBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationBitNotBigInt(ExecState*, JSCell* op1) WTF_INTERNAL;
 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 operationBitXorBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 size_t JIT_OPERATION operationSameValue(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationAddBigInt(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;
index 9537ce0..e75de62 100644 (file)
@@ -179,6 +179,22 @@ private:
             break;
         }
 
             break;
         }
 
+        case ValueBitLShift: {
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
+
+            if (left && right) {
+                if (isBigIntSpeculation(left) && isBigIntSpeculation(right))
+                    changed |= mergePrediction(SpecBigInt);
+                else if (isFullNumberOrBooleanSpeculationExpectingDefined(left) && isFullNumberOrBooleanSpeculationExpectingDefined(right))
+                    changed |= mergePrediction(SpecInt32Only);
+                else
+                    changed |= mergePrediction(node->getHeapPrediction());
+            }
+
+            break;
+        }
+
         case ValueAdd: {
             SpeculatedType left = node->child1()->prediction();
             SpeculatedType right = node->child2()->prediction();
         case ValueAdd: {
             SpeculatedType left = node->child1()->prediction();
             SpeculatedType right = node->child2()->prediction();
@@ -768,7 +784,7 @@ private:
         case ArithBitOr:
         case ArithBitXor:
         case BitRShift:
         case ArithBitOr:
         case ArithBitXor:
         case BitRShift:
-        case BitLShift:
+        case ArithBitLShift:
         case BitURShift:
         case ArithIMul:
         case ArithClz32: {
         case BitURShift:
         case ArithIMul:
         case ArithClz32: {
@@ -1137,6 +1153,7 @@ private:
         case ValueDiv:
         case ValueMod:
         case ValuePow:
         case ValueDiv:
         case ValueMod:
         case ValuePow:
+        case ValueBitLShift:
         case ArithAdd:
         case ArithSub:
         case ArithNegate:
         case ArithAdd:
         case ArithSub:
         case ArithNegate:
index 72ca69a..38c29ed 100644 (file)
@@ -203,7 +203,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
     case ArithBitAnd:
     case ArithBitOr:
     case ArithBitXor:
-    case BitLShift:
+    case ArithBitLShift:
     case BitRShift:
     case BitURShift:
     case ValueToInt32:
     case BitRShift:
     case BitURShift:
     case ValueToInt32:
@@ -233,6 +233,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ValueBitXor:
     case ValueBitOr:
     case ValueBitNot:
     case ValueBitXor:
     case ValueBitOr:
     case ValueBitNot:
+    case ValueBitLShift:
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
index fcd5cb9..5bf38a8 100644 (file)
@@ -3861,6 +3861,34 @@ void SpeculativeJIT::emitUntypedRightShiftBitOp(Node* node)
     return;
 }
 
     return;
 }
 
+void SpeculativeJIT::compileValueLShiftOp(Node* node)
+{
+    Edge& leftChild = node->child1();
+    Edge& rightChild = node->child2();
+
+    if (node->binaryUseKind() == 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(operationBitLShiftBigInt, resultGPR, leftGPR, rightGPR);
+        m_jit.exceptionCheck();
+        cellResult(resultGPR, node);
+        return;
+    }
+
+    ASSERT(leftChild.useKind() == UntypedUse && rightChild.useKind() == UntypedUse);
+    emitUntypedBitOp<JITLeftShiftGenerator, operationValueBitLShift>(node);
+}
+
 void SpeculativeJIT::compileShiftOp(Node* node)
 {
     NodeType op = node->op();
 void SpeculativeJIT::compileShiftOp(Node* node)
 {
     NodeType op = node->op();
@@ -3869,9 +3897,6 @@ void SpeculativeJIT::compileShiftOp(Node* node)
 
     if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
         switch (op) {
 
     if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
         switch (op) {
-        case BitLShift:
-            emitUntypedBitOp<JITLeftShiftGenerator, operationValueBitLShift>(node);
-            return;
         case BitRShift:
         case BitURShift:
             emitUntypedRightShiftBitOp(node);
         case BitRShift:
         case BitURShift:
             emitUntypedRightShiftBitOp(node);
index 9f1d893..2ac0672 100644 (file)
@@ -663,7 +663,7 @@ public:
         case BitRShift:
             m_jit.rshift32(op1, Imm32(shiftAmount), result);
             break;
         case BitRShift:
             m_jit.rshift32(op1, Imm32(shiftAmount), result);
             break;
-        case BitLShift:
+        case ArithBitLShift:
             m_jit.lshift32(op1, Imm32(shiftAmount), result);
             break;
         case BitURShift:
             m_jit.lshift32(op1, Imm32(shiftAmount), result);
             break;
         case BitURShift:
@@ -679,7 +679,7 @@ public:
         case BitRShift:
             m_jit.rshift32(op1, shiftAmount, result);
             break;
         case BitRShift:
             m_jit.rshift32(op1, shiftAmount, result);
             break;
-        case BitLShift:
+        case ArithBitLShift:
             m_jit.lshift32(op1, shiftAmount, result);
             break;
         case BitURShift:
             m_jit.lshift32(op1, shiftAmount, result);
             break;
         case BitURShift:
@@ -1334,6 +1334,7 @@ public:
     void compileValueBitwiseOp(Node*);
 
     void emitUntypedRightShiftBitOp(Node*);
     void compileValueBitwiseOp(Node*);
 
     void emitUntypedRightShiftBitOp(Node*);
+    void compileValueLShiftOp(Node*);
     void compileShiftOp(Node*);
 
     template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction>
     void compileShiftOp(Node*);
 
     template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction>
index b3d1d1d..dc5a3b4 100644 (file)
@@ -2001,8 +2001,12 @@ void SpeculativeJIT::compile(Node* node)
         compileBitwiseNot(node);
         break;
 
         compileBitwiseNot(node);
         break;
 
+    case ValueBitLShift:
+        compileValueLShiftOp(node);
+        break;
+
     case BitRShift:
     case BitRShift:
-    case BitLShift:
+    case ArithBitLShift:
     case BitURShift:
         compileShiftOp(node);
         break;
     case BitURShift:
         compileShiftOp(node);
         break;
index 9d0ae0a..7306c2a 100644 (file)
@@ -2100,8 +2100,12 @@ void SpeculativeJIT::compile(Node* node)
         compileBitwiseOp(node);
         break;
 
         compileBitwiseOp(node);
         break;
 
+    case ValueBitLShift:
+        compileValueLShiftOp(node);
+        break;
+
     case BitRShift:
     case BitRShift:
-    case BitLShift:
+    case ArithBitLShift:
     case BitURShift:
         compileShiftOp(node);
         break;
     case BitURShift:
         compileShiftOp(node);
         break;
index d1cde13..6c74486 100644 (file)
@@ -92,7 +92,7 @@ private:
             handleCommutativity();
             break;
             
             handleCommutativity();
             break;
             
-        case BitLShift:
+        case ArithBitLShift:
         case BitRShift:
         case BitURShift:
             if (m_node->child1().useKind() != UntypedUse && m_node->child2()->isInt32Constant() && !(m_node->child2()->asInt32() & 0x1f)) {
         case BitRShift:
         case BitURShift:
             if (m_node->child1().useKind() != UntypedUse && m_node->child2()->isInt32Constant() && !(m_node->child2()->asInt32() & 0x1f)) {
index a22c117..e3ab8e2 100644 (file)
@@ -64,7 +64,7 @@ inline CapabilityLevel canCompile(Node* node)
     case ArithBitOr:
     case ArithBitXor:
     case BitRShift:
     case ArithBitOr:
     case ArithBitXor:
     case BitRShift:
-    case BitLShift:
+    case ArithBitLShift:
     case BitURShift:
     case CheckStructure:
     case CheckStructureOrEmpty:
     case BitURShift:
     case CheckStructure:
     case CheckStructureOrEmpty:
@@ -93,6 +93,7 @@ inline CapabilityLevel canCompile(Node* node)
     case ValueBitXor:
     case ValueBitOr:
     case ValueBitNot:
     case ValueBitXor:
     case ValueBitOr:
     case ValueBitNot:
+    case ValueBitLShift:
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
index 1af7414..1c2e940 100644 (file)
@@ -853,8 +853,11 @@ private:
         case BitRShift:
             compileBitRShift();
             break;
         case BitRShift:
             compileBitRShift();
             break;
-        case BitLShift:
-            compileBitLShift();
+        case ArithBitLShift:
+            compileArithBitLShift();
+            break;
+        case ValueBitLShift:
+            compileValueBitLShift();
             break;
         case BitURShift:
             compileBitURShift();
             break;
         case BitURShift:
             compileBitURShift();
@@ -3184,17 +3187,28 @@ private:
             m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
     }
     
             m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
     }
     
-    void compileBitLShift()
+    void compileArithBitLShift()
     {
     {
-        if (m_node->isBinaryUseKind(UntypedUse)) {
-            emitBinaryBitOpSnippet<JITLeftShiftGenerator>(operationValueBitLShift);
-            return;
-        }
         setInt32(m_out.shl(
             lowInt32(m_node->child1()),
             m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
     }
     
         setInt32(m_out.shl(
             lowInt32(m_node->child1()),
             m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
     }
     
+    void compileValueBitLShift()
+    {
+        if (m_node->isBinaryUseKind(BigIntUse)) {
+            LValue left = lowBigInt(m_node->child1());
+            LValue right = lowBigInt(m_node->child2());
+            
+            LValue result = vmCall(pointerType(), m_out.operation(operationBitLShiftBigInt), m_callFrame, left, right);
+            setJSValue(result);
+            return;
+        }
+
+        ASSERT(m_node->isBinaryUseKind(UntypedUse));
+        emitBinaryBitOpSnippet<JITLeftShiftGenerator>(operationValueBitLShift);
+    }
+
     void compileBitURShift()
     {
         if (m_node->isBinaryUseKind(UntypedUse)) {
     void compileBitURShift()
     {
         if (m_node->isBinaryUseKind(UntypedUse)) {
index c350c01..37ef279 100644 (file)
@@ -1170,7 +1170,7 @@ macro bitOpProfiled(opcodeName, opcodeStruct, operation)
 end
 
 
 end
 
 
-bitOp(lshift, OpLshift,
+bitOpProfiled(lshift, OpLshift,
     macro (left, right) lshifti left, right end)
 
 
     macro (left, right) lshifti left, right end)
 
 
index 6ba9720..e1ed72f 100644 (file)
@@ -1146,7 +1146,7 @@ macro bitOpProfiled(opcodeName, opcodeStruct, operation)
     commonBitOp(llintOpWithProfile, opcodeName, opcodeStruct, operation)
 end
 
     commonBitOp(llintOpWithProfile, opcodeName, opcodeStruct, operation)
 end
 
-bitOp(lshift, OpLshift,
+bitOpProfiled(lshift, OpLshift,
     macro (left, right) lshifti left, right end)
 
 
     macro (left, right) lshifti left, right end)
 
 
index 48c7c1a..5df4f58 100644 (file)
@@ -674,13 +674,13 @@ SLOW_PATH_DECL(slow_path_lshift)
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
             JSBigInt* result = JSBigInt::leftShift(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             CHECK_EXCEPTION();
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
             JSBigInt* result = JSBigInt::leftShift(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 left shift operation."));
     }
 
         }
 
         THROW(createTypeError(exec, "Invalid mix of BigInt and other type in left shift operation."));
     }
 
-    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_rshift)
 }
 
 SLOW_PATH_DECL(slow_path_rshift)