[BigInt] Implement ValueBitXor into DFG
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Nov 2018 13:24:53 +0000 (13:24 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Nov 2018 13:24:53 +0000 (13:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190264

Reviewed by Yusuke Suzuki.

JSTests:

* stress/big-int-bitwise-xor-jit.js: Added.
* stress/big-int-bitwise-xor-memory-stress.js: Added.
* stress/big-int-bitwise-xor-untyped.js: Added.

Source/JavaScriptCore:

This patch is splitting the BitXor node into ArithBitXor and
ValueBitXor. This is necessary due the introduction of
BigInt, since BitXor operations now can result into Int32 or BigInt.
In such case, we use ArithBitXor when operands are Int and fallback to
ValueBitXor when operands are anything else. In the case of
ValueBitXor, we speculate BigInt when op1 and op2 are predicted as
BigInt as well. BigInt specialization consist into call
`operationBigIntBitXor` function, that calls JSBigInt::bitXor.

* bytecode/BytecodeList.rb:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::arithProfileForPC):
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* 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):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileValueBitwiseOp):
(JSC::DFG::SpeculativeJIT::compileBitwiseOp):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::bitOp):
* 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::compileValueBitXor):
(JSC::FTL::DFG::LowerDFGToB3::compileArithBitXor):
(JSC::FTL::DFG::LowerDFGToB3::compileBitXor): Deleted.
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_bitxor):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):

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

31 files changed:
JSTests/ChangeLog
JSTests/stress/big-int-bitwise-xor-jit.js [new file with mode: 0644]
JSTests/stress/big-int-bitwise-xor-memory-stress.js [new file with mode: 0644]
JSTests/stress/big-int-bitwise-xor-untyped.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/BytecodeList.rb
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/Opcode.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.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/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/jit/JITArithmetic.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

index c053fe3..d009ba8 100644 (file)
@@ -1,3 +1,14 @@
+2018-11-30  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Implement ValueBitXor into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=190264
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/big-int-bitwise-xor-jit.js: Added.
+        * stress/big-int-bitwise-xor-memory-stress.js: Added.
+        * stress/big-int-bitwise-xor-untyped.js: Added.
+
 2018-11-27  Saam barati  <sbarati@apple.com>
 
         r238510 broke scopes of size zero
diff --git a/JSTests/stress/big-int-bitwise-xor-jit.js b/JSTests/stress/big-int-bitwise-xor-jit.js
new file mode 100644 (file)
index 0000000..3c3934b
--- /dev/null
@@ -0,0 +1,25 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntBitXor(a, b) {
+    return (a ^ b) ^ (a ^ 0b11n);
+
+}
+noInline(bigIntBitXor);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntBitXor(0b11n, 0b1010n);
+    assert.sameValue(r, 0b1001n);
+}
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntBitXor(0xfffafafaf19281fefafeafebcn, 0b1010n);
+    assert.sameValue(r, 0b1001n);
+}
+
diff --git a/JSTests/stress/big-int-bitwise-xor-memory-stress.js b/JSTests/stress/big-int-bitwise-xor-memory-stress.js
new file mode 100644 (file)
index 0000000..636ad27
--- /dev/null
@@ -0,0 +1,14 @@
+//@ runBigIntEnabled
+
+function assert(a) {
+    if (!a)
+        throw new Error("Bad assertion");
+}
+
+let a = 0b11n;
+for (let i = 0; i < 1000000; i++) {
+    a ^= 0b01n;
+}
+
+assert(a === 0b11n);
+
diff --git a/JSTests/stress/big-int-bitwise-xor-untyped.js b/JSTests/stress/big-int-bitwise-xor-untyped.js
new file mode 100644 (file)
index 0000000..934e099
--- /dev/null
@@ -0,0 +1,26 @@
+//@ runBigIntEnabled
+
+function assert(v, e) {
+    if (v !== e)
+        throw new Error("Expected value: " + e + " but got: " + v)
+}
+
+function bigIntOperations(a, b) {
+    let c = a ^ b;
+    return a ^ c;
+}
+noInline(bigIntOperations);
+
+c = 0;
+let o = { valueOf: function () {
+    c++;
+    return 0b1111n;
+}};
+
+for (let i = 0; i < 100000; i++) {
+    let out = bigIntOperations(o, 0b1010n);
+    assert(out, 0b1010n);
+}
+
+assert(c, 200000);
+
index 676d21b..5bbc272 100644 (file)
@@ -1,3 +1,70 @@
+2018-11-30  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Implement ValueBitXor into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=190264
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch is splitting the BitXor node into ArithBitXor and
+        ValueBitXor. This is necessary due the introduction of
+        BigInt, since BitXor operations now can result into Int32 or BigInt.
+        In such case, we use ArithBitXor when operands are Int and fallback to
+        ValueBitXor when operands are anything else. In the case of
+        ValueBitXor, we speculate BigInt when op1 and op2 are predicted as
+        BigInt as well. BigInt specialization consist into call
+        `operationBigIntBitXor` function, that calls JSBigInt::bitXor.
+
+        * bytecode/BytecodeList.rb:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        (JSC::CodeBlock::arithProfileForPC):
+        * bytecode/Opcode.h:
+        (JSC::padOpcodeName):
+        * bytecompiler/BytecodeGenerator.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * 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):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileValueBitwiseOp):
+        (JSC::DFG::SpeculativeJIT::compileBitwiseOp):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::bitOp):
+        * 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::compileValueBitXor):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithBitXor):
+        (JSC::FTL::DFG::LowerDFGToB3::compileBitXor): Deleted.
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::emit_op_bitxor):
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+
 2018-11-29  Justin Michaud  <justin_michaud@apple.com>
 
         CSS Painting API should pass 'this' correctly to paint callback, and repaint when properties change.
index 773ddab..a0672d5 100644 (file)
@@ -240,7 +240,6 @@ op_group :ProfiledBinaryOp,
         :mul,
         :div,
         :sub,
-        :bitxor,
     ],
     args: {
         dst: VirtualRegister,
@@ -259,6 +258,7 @@ op_group :ValueProfiledBinaryOp,
     [
         :bitand,
         :bitor,
+        :bitxor,
     ],
     args: {
         dst: VirtualRegister,
index d34652b..0e80517 100644 (file)
@@ -567,6 +567,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
         LINK(OpBitand, profile)
         LINK(OpBitor, profile)
         LINK(OpBitnot, profile)
+        LINK(OpBitxor, profile)
 
         LINK(OpGetById, profile, hitCountForLLIntCaching)
 
@@ -592,7 +593,6 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
         LINK(OpMul)
         LINK(OpDiv)
         LINK(OpSub)
-        LINK(OpBitxor)
 
         LINK(OpNegate)
 
@@ -2953,8 +2953,6 @@ ArithProfile* CodeBlock::arithProfileForPC(const Instruction* pc)
     switch (pc->opcodeID()) {
     case op_negate:
         return &pc->as<OpNegate>().metadata(this).arithProfile;
-    case op_bitxor:
-        return &pc->as<OpBitxor>().metadata(this).arithProfile;
     case op_add:
         return &pc->as<OpAdd>().metadata(this).arithProfile;
     case op_mul:
index 298f28f..38bdfe2 100644 (file)
@@ -110,6 +110,7 @@ IGNORE_WARNINGS_END
     macro(OpBitand) \
     macro(OpBitor) \
     macro(OpBitnot) \
+    macro(OpBitxor) \
 
 #define FOR_EACH_OPCODE_WITH_ARRAY_PROFILE(macro) \
     macro(OpHasIndexedProperty) \
index 40da5bf..b39c14e 100644 (file)
@@ -684,8 +684,9 @@ namespace JSC {
 
         template<typename BinaryOp>
         std::enable_if_t<
-            BinaryOp::opcodeID != op_bitxor && BinaryOp::opcodeID != op_add
-            && BinaryOp::opcodeID != op_mul && BinaryOp::opcodeID != op_sub
+            BinaryOp::opcodeID != op_add
+            && BinaryOp::opcodeID != op_mul
+            && BinaryOp::opcodeID != op_sub
             && BinaryOp::opcodeID != op_div,
             RegisterID*>
         emitBinaryOp(RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes)
@@ -696,8 +697,9 @@ namespace JSC {
 
         template<typename BinaryOp>
         std::enable_if_t<
-            BinaryOp::opcodeID == op_bitxor || BinaryOp::opcodeID == op_add
-            || BinaryOp::opcodeID == op_mul || BinaryOp::opcodeID == op_sub
+            BinaryOp::opcodeID == op_add
+            || BinaryOp::opcodeID == op_mul
+            || BinaryOp::opcodeID == op_sub
             || BinaryOp::opcodeID == op_div,
             RegisterID*>
         emitBinaryOp(RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types)
index 703d939..25144b5 100644 (file)
@@ -374,7 +374,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             m_state.operand(data->start.offset() + i).makeHeapTop();
         break;
     }
-            
+
     case ArithBitNot: {
         if (node->child1().useKind() == UntypedUse) {
             clobberWorld();
@@ -393,8 +393,9 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
 
-    case ValueBitOr:
+    case ValueBitXor:
     case ValueBitAnd:
+    case ValueBitOr:
         clobberWorld();
         if (node->binaryUseKind() == BigIntUse)
             setTypeForNode(node, SpecBigInt);
@@ -404,7 +405,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             
     case ArithBitAnd:
     case ArithBitOr:
-    case BitXor:
+    case ArithBitXor:
     case BitRShift:
     case BitLShift:
     case BitURShift: {
@@ -426,7 +427,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             case ArithBitOr:
                 setConstant(node, JSValue(a | b));
                 break;
-            case BitXor:
+            case ArithBitXor:
                 setConstant(node, JSValue(a ^ b));
                 break;
             case BitRShift:
index abaa763..d06906a 100644 (file)
@@ -119,7 +119,7 @@ private:
         }
             
         case ArithBitOr:
-        case BitXor:
+        case ArithBitXor:
         case BitLShift: {
             return power > 31;
         }
@@ -217,7 +217,7 @@ private:
 
         case ArithBitAnd:
         case ArithBitOr:
-        case BitXor:
+        case ArithBitXor:
         case BitRShift:
         case BitLShift:
         case BitURShift:
index 00deb58..71fc92b 100644 (file)
@@ -4925,8 +4925,11 @@ void ByteCodeParser::parseBlock(unsigned limit)
             auto bytecode = currentInstruction->as<OpBitxor>();
             Node* op1 = get(bytecode.lhs);
             Node* op2 = get(bytecode.rhs);
-            set(bytecode.dst, addToGraph(BitXor, op1, op2));
-            NEXT_OPCODE(op_bitxor);
+            if (isInt32Speculation(getPrediction()))
+                set(bytecode.dst, addToGraph(ArithBitXor, op1, op2));
+            else
+                set(bytecode.dst, addToGraph(ValueBitXor, op1, op2));
+            NEXT_OPCODE(op_bitor);
         }
 
         case op_rshift: {
index 1177513..788eecc 100644 (file)
@@ -273,7 +273,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
 
     case ArithBitAnd:
     case ArithBitOr:
-    case BitXor:
+    case ArithBitXor:
     case BitLShift:
     case BitRShift:
     case BitURShift:
@@ -645,6 +645,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case InById:
     case HasOwnProperty:
     case ValueBitAnd:
+    case ValueBitXor:
     case ValueBitOr:
     case ValueNegate:
     case ValueAdd:
index 1addd5d..6aa263c 100644 (file)
@@ -70,7 +70,7 @@ bool doesGC(Graph& graph, Node* node)
     case ArithBitNot:
     case ArithBitAnd:
     case ArithBitOr:
-    case BitXor:
+    case ArithBitXor:
     case BitLShift:
     case BitRShift:
     case BitURShift:
@@ -99,6 +99,7 @@ bool doesGC(Graph& graph, Node* node)
     case ArithUnary:
     case ValueBitAnd:
     case ValueBitOr:
+    case ValueBitXor:
     case ValueAdd:
     case ValueSub:
     case ValueNegate:
index aec4a21..964e5bc 100644 (file)
@@ -130,6 +130,7 @@ private:
             break;
         }
 
+        case ValueBitXor:
         case ValueBitOr:
         case ValueBitAnd: {
             if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) {
@@ -142,7 +143,7 @@ private:
             fixEdge<UntypedUse>(node->child2());
             break;
         }
-    
+
         case ArithBitNot: {
             if (node->child1().node()->shouldSpeculateUntypedForBitOps()) {
                 fixEdge<UntypedUse>(node->child1());
@@ -154,13 +155,16 @@ private:
             break;
         }
 
+        case ArithBitXor:
         case ArithBitOr:
         case ArithBitAnd: {
             if (Node::shouldSpeculateUntypedForBitOps(node->child1().node(), node->child2().node())) {
                 fixEdge<UntypedUse>(node->child1());
                 fixEdge<UntypedUse>(node->child2());
-
                 switch (op) {
+                case ArithBitXor:
+                    node->setOpAndDefaultFlags(ValueBitXor);
+                    break;
                 case ArithBitOr:
                     node->setOpAndDefaultFlags(ValueBitOr);
                     break;
@@ -171,15 +175,14 @@ private:
                     DFG_CRASH(m_graph, node, "Unexpected node during ArithBit operation fixup");
                     break;
                 }
-
                 break;
             }
+
             fixIntConvertingEdge(node->child1());
             fixIntConvertingEdge(node->child2());
             break;
         }
 
-        case BitXor:
         case BitRShift:
         case BitLShift:
         case BitURShift: {
index 793489d..509fcc9 100644 (file)
@@ -116,7 +116,8 @@ namespace JSC { namespace DFG {
     macro(ArithBitAnd, NodeResultInt32) \
     macro(ValueBitOr, NodeResultJS | NodeMustGenerate) \
     macro(ArithBitOr, NodeResultInt32) \
-    macro(BitXor, NodeResultInt32) \
+    macro(ValueBitXor, NodeResultJS | NodeMustGenerate) \
+    macro(ArithBitXor, NodeResultInt32) \
     macro(BitLShift, NodeResultInt32) \
     macro(BitRShift, NodeResultInt32) \
     macro(BitURShift, NodeResultInt32) \
index c09c160..3f1f494 100644 (file)
@@ -410,11 +410,22 @@ EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState* exec, EncodedJSValu
     JSValue op1 = JSValue::decode(encodedOp1);
     JSValue op2 = JSValue::decode(encodedOp2);
 
-    int32_t a = op1.toInt32(exec);
+    auto leftNumeric = op1.toBigIntOrInt32(exec);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    scope.release();
-    int32_t b = op2.toInt32(exec);
-    return JSValue::encode(jsNumber(a ^ b));
+    auto rightNumeric = op2.toBigIntOrInt32(exec);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+            JSBigInt* result = JSBigInt::bitwiseXor(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            RETURN_IF_EXCEPTION(scope, encodedJSValue());
+            return JSValue::encode(result);
+        }
+
+        return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'xor' operation.");
+    }
+
+    return JSValue::encode(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric)));
 }
 
 EncodedJSValue JIT_OPERATION operationValueBitLShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
@@ -1344,6 +1355,17 @@ JSCell* JIT_OPERATION operationBitOrBigInt(ExecState* exec, JSCell* op1, JSCell*
     return JSBigInt::bitwiseOr(exec, leftOperand, rightOperand);
 }
 
+JSCell* JIT_OPERATION operationBitXorBigInt(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::bitwiseXor(exec, leftOperand, rightOperand);
+}
+
 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, JSCell* op1, JSCell* op2)
 {
     VM* vm = &exec->vm();
index ca83a70..512ac11 100644 (file)
@@ -168,6 +168,7 @@ JSCell* JIT_OPERATION operationSubBigInt(ExecState*, JSCell* op1, JSCell* op2) W
 JSCell* JIT_OPERATION operationBitAndBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationBitOrBigInt(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 operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*, EncodedJSValue);
 JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState*, Structure*, uint32_t length, uint32_t minCapacity);
index 25867f8..f8209fb 100644 (file)
@@ -277,6 +277,7 @@ private:
             break;
         }
 
+        case ValueBitXor:
         case ValueBitOr:
         case ValueBitAnd: {
             if (node->child1()->shouldSpeculateBigInt() && node->child2()->shouldSpeculateBigInt())
@@ -740,7 +741,7 @@ private:
         case ArithBitNot:
         case ArithBitAnd:
         case ArithBitOr:
-        case BitXor:
+        case ArithBitXor:
         case BitRShift:
         case BitLShift:
         case BitURShift:
@@ -1096,6 +1097,7 @@ private:
         case UInt32ToNumber:
         case ValueBitOr:
         case ValueBitAnd:
+        case ValueBitXor:
         case ValueNegate:
         case ValueAdd:
         case ValueSub:
index 6c6eada..b43b7df 100644 (file)
@@ -200,7 +200,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ArithBitNot:
     case ArithBitAnd:
     case ArithBitOr:
-    case BitXor:
+    case ArithBitXor:
     case BitLShift:
     case BitRShift:
     case BitURShift:
@@ -228,6 +228,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ArithTrunc:
     case ArithUnary:
     case ValueBitAnd:
+    case ValueBitXor:
     case ValueBitOr:
     case ValueNegate:
     case ValueAdd:
index ddc99c3..2cda06d 100644 (file)
@@ -3637,6 +3637,9 @@ void SpeculativeJIT::compileValueBitwiseOp(Node* node)
         case ValueBitAnd:
             emitUntypedBitOp<JITBitAndGenerator, operationValueBitAnd>(node);
             return;
+        case ValueBitXor:
+            emitUntypedBitOp<JITBitXorGenerator, operationValueBitXor>(node);
+            return;
         case ValueBitOr:
             emitUntypedBitOp<JITBitOrGenerator, operationValueBitOr>(node);
             return;
@@ -3663,6 +3666,9 @@ void SpeculativeJIT::compileValueBitwiseOp(Node* node)
     case ValueBitAnd:
         callOperation(operationBitAndBigInt, resultGPR, leftGPR, rightGPR);
         break;
+    case ValueBitXor:
+        callOperation(operationBitXorBigInt, resultGPR, leftGPR, rightGPR);
+        break;
     case ValueBitOr:
         callOperation(operationBitOrBigInt, resultGPR, leftGPR, rightGPR);
         break;
@@ -3680,16 +3686,6 @@ void SpeculativeJIT::compileBitwiseOp(Node* node)
     Edge& leftChild = node->child1();
     Edge& rightChild = node->child2();
 
-    if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
-        switch (op) {
-        case BitXor:
-            emitUntypedBitOp<JITBitXorGenerator, operationValueBitXor>(node);
-            return;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-        }
-    }
-
     if (leftChild->isInt32Constant()) {
         SpeculateInt32Operand op2(this, rightChild);
         GPRTemporary result(this, Reuse, op2);
@@ -3697,26 +3693,28 @@ void SpeculativeJIT::compileBitwiseOp(Node* node)
         bitOp(op, leftChild->asInt32(), op2.gpr(), result.gpr());
 
         int32Result(result.gpr(), node);
+        return;
+    }
 
-    } else if (rightChild->isInt32Constant()) {
+    if (rightChild->isInt32Constant()) {
         SpeculateInt32Operand op1(this, leftChild);
         GPRTemporary result(this, Reuse, op1);
 
         bitOp(op, rightChild->asInt32(), op1.gpr(), result.gpr());
 
         int32Result(result.gpr(), node);
-
-    } else {
-        SpeculateInt32Operand op1(this, leftChild);
-        SpeculateInt32Operand op2(this, rightChild);
-        GPRTemporary result(this, Reuse, op1, op2);
-        
-        GPRReg reg1 = op1.gpr();
-        GPRReg reg2 = op2.gpr();
-        bitOp(op, reg1, reg2, result.gpr());
-        
-        int32Result(result.gpr(), node);
+        return;
     }
+
+    SpeculateInt32Operand op1(this, leftChild);
+    SpeculateInt32Operand op2(this, rightChild);
+    GPRTemporary result(this, Reuse, op1, op2);
+
+    GPRReg reg1 = op1.gpr();
+    GPRReg reg2 = op2.gpr();
+    bitOp(op, reg1, reg2, result.gpr());
+
+    int32Result(result.gpr(), node);
 }
 
 void SpeculativeJIT::emitUntypedRightShiftBitOp(Node* node)
index de0b4f3..adb3ba1 100644 (file)
@@ -639,7 +639,7 @@ public:
         case ArithBitOr:
             m_jit.or32(Imm32(imm), op1, result);
             break;
-        case BitXor:
+        case ArithBitXor:
             m_jit.xor32(Imm32(imm), op1, result);
             break;
         default:
@@ -655,7 +655,7 @@ public:
         case ArithBitOr:
             m_jit.or32(op1, op2, result);
             break;
-        case BitXor:
+        case ArithBitXor:
             m_jit.xor32(op1, op2, result);
             break;
         default:
index fb302f2..ce3e266 100644 (file)
@@ -1981,12 +1981,13 @@ void SpeculativeJIT::compile(Node* node)
 
     case ValueBitOr:
     case ValueBitAnd:
+    case ValueBitXor:
         compileValueBitwiseOp(node);
         break;
 
     case ArithBitAnd:
     case ArithBitOr:
-    case BitXor:
+    case ArithBitXor:
         compileBitwiseOp(node);
         break;
 
index 1bf72ef..fb161a7 100644 (file)
@@ -2079,13 +2079,14 @@ void SpeculativeJIT::compile(Node* node)
         break;
 
     case ValueBitAnd:
+    case ValueBitXor:
     case ValueBitOr:
         compileValueBitwiseOp(node);
         break;
 
     case ArithBitAnd:
     case ArithBitOr:
-    case BitXor:
+    case ArithBitXor:
         compileBitwiseOp(node);
         break;
 
index 12d5b6f..2370c79 100644 (file)
@@ -87,7 +87,7 @@ private:
             }
             break;
             
-        case BitXor:
+        case ArithBitXor:
         case ArithBitAnd:
             handleCommutativity();
             break;
index 804a3b3..da11381 100644 (file)
@@ -61,7 +61,7 @@ inline CapabilityLevel canCompile(Node* node)
     case ArithBitNot:
     case ArithBitAnd:
     case ArithBitOr:
-    case BitXor:
+    case ArithBitXor:
     case BitRShift:
     case BitLShift:
     case BitURShift:
@@ -88,6 +88,7 @@ inline CapabilityLevel canCompile(Node* node)
     case GetGlobalLexicalVariable:
     case PutGlobalVariable:
     case ValueBitAnd:
+    case ValueBitXor:
     case ValueBitOr:
     case ValueNegate:
     case ValueAdd:
index a234b32..c254892 100644 (file)
@@ -668,8 +668,11 @@ private:
         case ArithBitOr:
             compileArithBitOr();
             break;
-        case DFG::BitXor:
-            compileBitXor();
+        case ArithBitXor:
+            compileArithBitXor();
+            break;
+        case ValueBitXor:
+            compileValueBitXor();
             break;
         case BitRShift:
             compileBitRShift();
@@ -2898,12 +2901,22 @@ private:
         setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
     }
     
-    void compileBitXor()
+    void compileValueBitXor()
     {
-        if (m_node->isBinaryUseKind(UntypedUse)) {
-            emitBinaryBitOpSnippet<JITBitXorGenerator>(operationValueBitXor);
+        if (m_node->isBinaryUseKind(BigIntUse)) {
+            LValue left = lowBigInt(m_node->child1());
+            LValue right = lowBigInt(m_node->child2());
+
+            LValue result = vmCall(pointerType(), m_out.operation(operationBitXorBigInt), m_callFrame, left, right);
+            setJSValue(result);
             return;
         }
+
+        emitBinaryBitOpSnippet<JITBitXorGenerator>(operationValueBitXor);
+    }
+
+    void compileArithBitXor()
+    {
         setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
     }
     
index 0bdc153..e81459c 100644 (file)
@@ -550,7 +550,7 @@ void JIT::emit_op_bitor(const Instruction* currentInstruction)
 
 void JIT::emit_op_bitxor(const Instruction* currentInstruction)
 {
-    emitBitBinaryOpFastPath<OpBitxor, JITBitXorGenerator>(currentInstruction);
+    emitBitBinaryOpFastPath<OpBitxor, JITBitXorGenerator>(currentInstruction, ProfilingPolicy::ShouldEmitProfiling);
 }
 
 void JIT::emit_op_lshift(const Instruction* currentInstruction)
index 6b29219..bb22057 100644 (file)
@@ -1157,7 +1157,7 @@ bitOp(rshift, OpRshift,
 bitOp(urshift, OpUrshift,
     macro (left, right) urshifti left, right end)
 
-bitOp(bitxor, OpBitxor,
+bitOpProfiled(bitxor, OpBitxor,
     macro (left, right) xori left, right end)
 
 bitOpProfiled(bitand, OpBitand,
index 721a778..2e7ed9e 100644 (file)
@@ -1117,7 +1117,7 @@ bitOpProfiled(bitand, OpBitand,
 bitOpProfiled(bitor, OpBitor,
     macro (left, right) ori left, right end)
 
-bitOp(bitxor, OpBitxor,
+bitOpProfiled(bitxor, OpBitxor,
     macro (left, right) xori left, right end)
 
 llintOpWithProfile(op_bitnot, OpBitnot, macro (size, get, dispatch, return)
index 2bbba02..d8edf86 100644 (file)
@@ -753,13 +753,13 @@ SLOW_PATH_DECL(slow_path_bitxor)
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
             JSBigInt* result = JSBigInt::bitwiseXor(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 bitwise 'xor' operation."));
     }
 
-    RETURN(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric)));
+    RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric)));
 }
 
 SLOW_PATH_DECL(slow_path_typeof)