[BigInt] Add ValueMul into DFG
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Dec 2018 21:11:43 +0000 (21:11 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Dec 2018 21:11:43 +0000 (21:11 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186175

Reviewed by Yusuke Suzuki.

JSTests:

* stress/big-int-mul-jit-osr.js: Added.
* stress/big-int-mul-jit-untyped.js: Added.
* stress/value-mul-fixup-int32-big-int.js: Added.

PerformanceTests:

* BigIntBench/big-int-simple-mul.js: Added.
* BigIntBench/value-mul-type-propagation.js: Added.

Source/JavaScriptCore:

This patch is adding a new DFG node called ValueMul. This node is
responsible to handle multiplication operations that can result into
non-number values. We emit such node during DFGByteCodeParser when the
operands are not numbers. During FixupPhase, we change this
operation to ArithMul if we can speculate Number/Boolean operands.

The BigInt specialization shows a small progression:

                        noSpec                changes

big-int-simple-mul  18.8090+-1.0435  ^  17.4305+-0.2673  ^ definitely 1.0791x faster

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::makeSafe):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupMultiplication):
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::arithNodeFlags):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileValueMul):
(JSC::DFG::SpeculativeJIT::compileArithMul):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileValueMul):
(JSC::FTL::DFG::LowerDFGToB3::compileArithMul):

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

27 files changed:
JSTests/ChangeLog
JSTests/stress/big-int-mul-jit-osr.js [new file with mode: 0644]
JSTests/stress/big-int-mul-jit-untyped.js [new file with mode: 0644]
JSTests/stress/value-mul-fixup-int32-big-int.js [new file with mode: 0644]
PerformanceTests/BigIntBench/big-int-simple-mul.js [new file with mode: 0644]
PerformanceTests/BigIntBench/value-mul-type-propagation.js [new file with mode: 0644]
PerformanceTests/ChangeLog
Source/JavaScriptCore/ChangeLog
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/DFGValidate.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

index fcf0b8e..caa0a56 100644 (file)
@@ -1,3 +1,14 @@
+2018-12-10  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueMul into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=186175
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/big-int-mul-jit-osr.js: Added.
+        * stress/big-int-mul-jit-untyped.js: Added.
+        * stress/value-mul-fixup-int32-big-int.js: Added.
+
 2018-12-06  Keith Miller  <keith_miller@apple.com>
 
         stress/big-wasm-memory tests failing on 32-bit JSC bot
diff --git a/JSTests/stress/big-int-mul-jit-osr.js b/JSTests/stress/big-int-mul-jit-osr.js
new file mode 100644 (file)
index 0000000..e7631e5
--- /dev/null
@@ -0,0 +1,25 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntMul(x, y) {
+    return x * y;
+}
+noInline(bigIntMul);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntMul(3n, 10n);
+    assert.sameValue(r, 30n, 3n + " * " + 10n + " = " + r);
+}
+
+let r = bigIntMul(3, 10);
+assert.sameValue(r, 30, 3 + " * " + 10 + " = " + r);
+
+r = bigIntMul("3", "10");
+assert.sameValue(r, 30, 3 + " * " + 10 + " = " + r);
+
diff --git a/JSTests/stress/big-int-mul-jit-untyped.js b/JSTests/stress/big-int-mul-jit-untyped.js
new file mode 100644 (file)
index 0000000..5ed64bc
--- /dev/null
@@ -0,0 +1,36 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntMul(x, y) {
+    return x * y;
+}
+noInline(bigIntMul);
+
+let o =  {valueOf: () => 10n};
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntMul(3n, o);
+    assert.sameValue(r, 30n, 3n + " * {valueOf: () => 10n} = " + r);
+}
+
+o2 =  {valueOf: () => 10000n};
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntMul(o2, o);
+    assert.sameValue(r, 100000n, "{valueOf: () => 10000n} * {valueOf: () => 10n}  = " + r);
+}
+
+o = Object(10n);
+let r = bigIntMul(3n, o);
+assert.sameValue(r, 30n, 3n + " * Object(10n) = " + r);
+
+o2 = Object(3241n);
+r = bigIntMul(o2, o);
+assert.sameValue(r, 32410n, "Object(32410n) * Object(10n) = " + r);
+
diff --git a/JSTests/stress/value-mul-fixup-int32-big-int.js b/JSTests/stress/value-mul-fixup-int32-big-int.js
new file mode 100644 (file)
index 0000000..a598833
--- /dev/null
@@ -0,0 +1,29 @@
+//@ runBigIntEnabled
+
+function assert(a, e) {
+    if (a !== e)
+        throw new Error("Bad!");
+}
+
+function foo() {
+    let c;
+    do {
+    
+        let a = 2;
+        let b = 3n;
+        for (let i = 0; i < 10000; i++) {
+            c = i;
+        }
+
+        c = a * b; 
+    } while(true);
+
+    return c;
+}
+
+try {
+    foo();
+} catch(e) {
+    assert(e instanceof TypeError, true);
+}
+
diff --git a/PerformanceTests/BigIntBench/big-int-simple-mul.js b/PerformanceTests/BigIntBench/big-int-simple-mul.js
new file mode 100644 (file)
index 0000000..1380f88
--- /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, 0b1010n);
+}
+
+let out;
+for (let i = 0; i < 100000; i++) {
+    out = bigInt(0xffffffffffffffffffn, 0xaaffffffffffffffffffn);
+}
+
diff --git a/PerformanceTests/BigIntBench/value-mul-type-propagation.js b/PerformanceTests/BigIntBench/value-mul-type-propagation.js
new file mode 100644 (file)
index 0000000..9864044
--- /dev/null
@@ -0,0 +1,39 @@
+//@ runBigIntEnabled
+
+function assert(a, e) {
+    if (a !== e)
+        throw new Error("Bad!");
+}
+
+function foo(o) {
+    let c;
+    do {
+    
+        let a = 2 * o;
+        o.bigInt = true;
+        let b = 1n * o;
+        for (let i = 0; i < 10000; i++) {
+            c = i;
+        }
+
+        let d = b * o;
+        c = a * d;
+    } while(false);
+}
+noInline(foo);
+
+let o = {
+    valueOf: function () {
+        return this.bigInt ? 2n : 2;
+    }
+}
+
+for (let i = 0; i < 1000; i++) {
+    try {
+        o.bigInt = false;
+        foo(o);
+    } catch(e) {
+        assert(e instanceof TypeError, true);
+    }
+}
+
index 5d89525..3b3186b 100644 (file)
@@ -1,3 +1,13 @@
+2018-12-10  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueMul into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=186175
+
+        Reviewed by Yusuke Suzuki.
+
+        * BigIntBench/big-int-simple-mul.js: Added.
+        * BigIntBench/value-mul-type-propagation.js: Added.
+
 2018-11-07  Caio Lima  <ticaiolima@gmail.com>
 
         [BigInt] Add support to BigInt into ValueAdd
index 8fef43a..1c79958 100644 (file)
@@ -1,3 +1,58 @@
+2018-12-10  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] Add ValueMul into DFG
+        https://bugs.webkit.org/show_bug.cgi?id=186175
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch is adding a new DFG node called ValueMul. This node is
+        responsible to handle multiplication operations that can result into
+        non-number values. We emit such node during DFGByteCodeParser when the
+        operands are not numbers. During FixupPhase, we change this
+        operation to ArithMul if we can speculate Number/Boolean operands.
+
+        The BigInt specialization shows a small progression:
+
+                                noSpec                changes
+
+        big-int-simple-mul  18.8090+-1.0435  ^  17.4305+-0.2673  ^ definitely 1.0791x faster
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::makeSafe):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupMultiplication):
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::arithNodeFlags):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileValueMul):
+        (JSC::DFG::SpeculativeJIT::compileArithMul):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueMul):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithMul):
+
 2018-12-08  Mark Lam  <mark.lam@apple.com>
 
         Reduce size of PropertySlot and PutPropertySlot.
index 25144b5..c8f66dd 100644 (file)
@@ -854,6 +854,15 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
         
+    case ValueMul: {
+        clobberWorld();
+        if (node->binaryUseKind() == BigIntUse)
+            setTypeForNode(node, SpecBigInt);
+        else
+            setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
+        break;
+    }
+
     case ArithMul: {
         JSValue left = forNode(node->child1()).value();
         JSValue right = forNode(node->child2()).value();
@@ -897,10 +906,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
                 typeOfDoubleProduct(
                     forNode(node->child1()).m_type, forNode(node->child2()).m_type));
             break;
-        case UntypedUse:
-            clobberWorld();
-            setNonCellTypeForNode(node, SpecBytecodeNumber);
-            break;
         default:
             RELEASE_ASSERT_NOT_REACHED();
             break;
index d06906a..2d8c514 100644 (file)
@@ -269,7 +269,7 @@ private:
         case ValueAdd: {
             if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node()))
                 flags &= ~NodeBytecodeNeedsNegZero;
-            if (node->child1()->hasNumberResult() || node->child2()->hasNumberResult())
+            if (node->child1()->hasNumericResult() || node->child2()->hasNumericResult() || node->child1()->hasNumberResult() || node->child2()->hasNumberResult())
                 flags &= ~NodeBytecodeUsesAsOther;
             if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2()))
                 flags |= NodeBytecodeUsesAsNumber;
@@ -323,6 +323,7 @@ private:
             break;
         }
             
+        case ValueMul:
         case ArithMul: {
             // As soon as a multiply happens, we can easily end up in the part
             // of the double domain where the point at which you do truncation
index 71fc92b..aa23167 100644 (file)
@@ -947,6 +947,7 @@ private:
                         node->mergeFlags(NodeMayHaveBigIntResult);
                     break;
                 
+                case ValueMul:
                 case ArithMul: {
                     if (arithProfile->didObserveInt52Overflow())
                         node->mergeFlags(NodeMayOverflowInt52);
@@ -958,6 +959,8 @@ private:
                         node->mergeFlags(NodeMayHaveDoubleResult);
                     if (arithProfile->didObserveNonNumeric())
                         node->mergeFlags(NodeMayHaveNonNumericResult);
+                    if (arithProfile->didObserveBigInt())
+                        node->mergeFlags(NodeMayHaveBigIntResult);
                     break;
                 }
                 case ValueNegate:
@@ -5017,7 +5020,10 @@ void ByteCodeParser::parseBlock(unsigned limit)
             auto bytecode = currentInstruction->as<OpMul>();
             Node* op1 = get(bytecode.lhs);
             Node* op2 = get(bytecode.rhs);
-            set(bytecode.dst, makeSafe(addToGraph(ArithMul, op1, op2)));
+            if (op1->hasNumberResult() && op2->hasNumberResult())
+                set(bytecode.dst, makeSafe(addToGraph(ArithMul, op1, op2)));
+            else
+                set(bytecode.dst, makeSafe(addToGraph(ValueMul, op1, op2)));
             NEXT_OPCODE(op_mul);
         }
 
index 788eecc..95404f3 100644 (file)
@@ -650,6 +650,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
+    case ValueMul:
     case SetFunctionName:
     case GetDynamicVar:
     case PutDynamicVar:
index 6aa263c..64e2f5e 100644 (file)
@@ -102,6 +102,7 @@ bool doesGC(Graph& graph, Node* node)
     case ValueBitXor:
     case ValueAdd:
     case ValueSub:
+    case ValueMul:
     case ValueNegate:
     case TryGetById:
     case GetById:
index 964e5bc..5b0de12 100644 (file)
@@ -76,6 +76,35 @@ public:
     }
 
 private:
+    void fixupArithMul(Node* node, Edge& leftChild, Edge& rightChild)
+    {
+        if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) {
+            fixIntOrBooleanEdge(leftChild);
+            fixIntOrBooleanEdge(rightChild);
+            if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
+                node->setArithMode(Arith::Unchecked);
+            else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()) || leftChild.node() == rightChild.node())
+                node->setArithMode(Arith::CheckOverflow);
+            else
+                node->setArithMode(Arith::CheckOverflowAndNegativeZero);
+            return;
+        }
+        if (m_graph.binaryArithShouldSpeculateAnyInt(node, FixupPass)) {
+            fixEdge<Int52RepUse>(leftChild);
+            fixEdge<Int52RepUse>(rightChild);
+            if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()) || leftChild.node() == rightChild.node())
+                node->setArithMode(Arith::CheckOverflow);
+            else
+                node->setArithMode(Arith::CheckOverflowAndNegativeZero);
+            node->setResult(NodeResultInt52);
+            return;
+        }
+
+        fixDoubleOrBooleanEdge(leftChild);
+        fixDoubleOrBooleanEdge(rightChild);
+        node->setResult(NodeResultDouble);
+    }
+
     void fixupBlock(BasicBlock* block)
     {
         if (!block)
@@ -383,42 +412,45 @@ private:
             node->clearFlags(NodeMustGenerate);
             break;
         }
-            
-        case ArithMul: {
+
+        case ValueMul: {
             Edge& leftChild = node->child1();
             Edge& rightChild = node->child2();
+
+            if (Node::shouldSpeculateBigInt(leftChild.node(), rightChild.node())) {
+                fixEdge<BigIntUse>(node->child1());
+                fixEdge<BigIntUse>(node->child2());
+                break;
+            }
+
+            // There are cases where we can have BigInt + Int32 operands reaching ValueMul.
+            // Imagine the scenario where ValueMul was never executed, but we can predict types
+            // reaching the node:
+            //
+            // 63: GetLocal(Check:Untyped:@72, JS|MustGen, NonBoolInt32, ...)  predicting NonBoolInt32
+            // 64: GetLocal(Check:Untyped:@71, JS|MustGen, BigInt, ...)  predicting BigInt
+            // 65: ValueMul(Check:Untyped:@63, Check:Untyped:@64, BigInt|BoolInt32|NonBoolInt32, ...)
+            // 
+            // In such scenario, we need to emit ValueMul(Untyped, Untyped), so the runtime can throw 
+            // an exception whenever it gets excuted.
             if (Node::shouldSpeculateUntypedForArithmetic(leftChild.node(), rightChild.node())) {
                 fixEdge<UntypedUse>(leftChild);
                 fixEdge<UntypedUse>(rightChild);
-                node->setResult(NodeResultJS);
                 break;
             }
-            if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) {
-                fixIntOrBooleanEdge(leftChild);
-                fixIntOrBooleanEdge(rightChild);
-                if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
-                    node->setArithMode(Arith::Unchecked);
-                else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())
-                    || leftChild.node() == rightChild.node())
-                    node->setArithMode(Arith::CheckOverflow);
-                else
-                    node->setArithMode(Arith::CheckOverflowAndNegativeZero);
-                break;
-            }
-            if (m_graph.binaryArithShouldSpeculateAnyInt(node, FixupPass)) {
-                fixEdge<Int52RepUse>(leftChild);
-                fixEdge<Int52RepUse>(rightChild);
-                if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())
-                    || leftChild.node() == rightChild.node())
-                    node->setArithMode(Arith::CheckOverflow);
-                else
-                    node->setArithMode(Arith::CheckOverflowAndNegativeZero);
-                node->setResult(NodeResultInt52);
-                break;
-            }
-            fixDoubleOrBooleanEdge(leftChild);
-            fixDoubleOrBooleanEdge(rightChild);
-            node->setResult(NodeResultDouble);
+
+            // At this point, all other possible specializations are only handled by ArithMul.
+            node->setOp(ArithMul);
+            node->setResult(NodeResultNumber);
+            fixupArithMul(node, leftChild, rightChild);
+            break;
+        }
+
+        case ArithMul: {
+            Edge& leftChild = node->child1();
+            Edge& rightChild = node->child2();
+
+            fixupArithMul(node, leftChild, rightChild);
             break;
         }
 
index 9952806..5aa83a9 100644 (file)
@@ -1124,12 +1124,13 @@ public:
     PromotedLocationDescriptor promotedLocationDescriptor();
     
     // This corrects the arithmetic node flags, so that irrelevant bits are
-    // ignored. In particular, anything other than ArithMul does not need
+    // ignored. In particular, anything other than ArithMul or ValueMul does not need
     // to know if it can speculate on negative zero.
     NodeFlags arithNodeFlags()
     {
         NodeFlags result = m_flags & NodeArithFlagsMask;
-        if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32 || op() == ValueNegate)
+        if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32 || op() == ValueNegate
+            || op() == ValueMul)
             return result;
         return result & ~NodeBytecodeNeedsNegZero;
     }
@@ -1371,6 +1372,21 @@ public:
         return result() == NodeResultNumber;
     }
     
+    bool hasNumericResult()
+    {
+        switch (op()) {
+        case ValueSub:
+        case ValueMul:
+        case ValueBitAnd:
+        case ValueBitOr:
+        case ValueBitXor:
+        case ValueNegate:
+            return true;
+        default:
+            return false;
+        }
+    }
+
     bool hasDoubleResult()
     {
         return result() == NodeResultDouble;
index 509fcc9..40f6264 100644 (file)
@@ -174,6 +174,7 @@ namespace JSC { namespace DFG {
     macro(ValueAdd, NodeResultJS | NodeMustGenerate) \
     \
     macro(ValueSub, NodeResultJS | NodeMustGenerate) \
+    macro(ValueMul, NodeResultJS | NodeMustGenerate) \
     \
     /* Add of values that always convers its inputs to strings. May have two or three kids. */\
     macro(StrCat, NodeResultJS | NodeMustGenerate) \
index 3f1f494..be992af 100644 (file)
@@ -1322,6 +1322,17 @@ JSCell* JIT_OPERATION operationSubBigInt(ExecState* exec, JSCell* op1, JSCell* o
     return JSBigInt::sub(exec, leftOperand, rightOperand);
 }
 
+JSCell* JIT_OPERATION operationMulBigInt(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::multiply(exec, leftOperand, rightOperand);
+}
+
 JSCell* JIT_OPERATION operationBitAndBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
 {
     VM* vm = &exec->vm();
index 512ac11..e455609 100644 (file)
@@ -165,6 +165,7 @@ size_t JIT_OPERATION operationRegExpTest(ExecState*, JSGlobalObject*, RegExpObje
 size_t JIT_OPERATION operationRegExpTestGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationSubBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationMulBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
 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;
index f8209fb..e8299eb 100644 (file)
@@ -320,6 +320,7 @@ private:
             break;
         }
 
+        case ValueMul:
         case ArithMul: {
             SpeculatedType left = node->child1()->prediction();
             SpeculatedType right = node->child2()->prediction();
@@ -337,13 +338,18 @@ private:
                         changed |= mergePrediction(SpecInt52Only);
                     else
                         changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
-                } else {
-                    if (node->mayHaveNonIntResult()
+                } else if (op == ValueMul && isBigIntSpeculation(left) && isBigIntSpeculation(right))
+                    changed |= mergePrediction(SpecBigInt);
+                else {
+                    changed |= mergePrediction(SpecInt32Only);
+                    if (node->mayHaveDoubleResult()
                         || (left & SpecBytecodeDouble)
                         || (right & SpecBytecodeDouble))
-                        changed |= mergePrediction(SpecInt32Only | SpecBytecodeDouble);
-                    else
-                        changed |= mergePrediction(SpecInt32Only);
+                        changed |= mergePrediction(SpecBytecodeDouble);
+                    if ((op == ValueMul && node->mayHaveBigIntResult())
+                        || (left & SpecBigInt)
+                        || (right & SpecBigInt))
+                        changed |= mergePrediction(SpecBigInt);
                 }
             }
             break;
@@ -571,6 +577,7 @@ private:
             break;
         }
 
+        case ValueMul:
         case ArithMul: {
             SpeculatedType left = node->child1()->prediction();
             SpeculatedType right = node->child2()->prediction();
@@ -1101,6 +1108,7 @@ private:
         case ValueNegate:
         case ValueAdd:
         case ValueSub:
+        case ValueMul:
         case ArithAdd:
         case ArithSub:
         case ArithNegate:
index b43b7df..07cf01f 100644 (file)
@@ -233,6 +233,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
+    case ValueMul:
     case TryGetById:
     case DeleteById:
     case DeleteByVal:
index 2cda06d..465bf3f 100644 (file)
@@ -4778,6 +4778,63 @@ void SpeculativeJIT::compileMathIC(Node* node, JITUnaryMathIC<Generator>* mathIC
     return;
 }
 
+void SpeculativeJIT::compileValueMul(Node* node)
+{
+    Edge& leftChild = node->child1();
+    Edge& rightChild = node->child2();
+
+    if (leftChild.useKind() == BigIntUse && rightChild.useKind() == 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(operationMulBigInt, resultGPR, leftGPR, rightGPR);
+
+        m_jit.exceptionCheck();
+        cellResult(resultGPR, node);
+        return;
+    }
+
+    if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
+        JSValueOperand left(this, leftChild);
+        JSValueOperand right(this, rightChild);
+        JSValueRegs leftRegs = left.jsValueRegs();
+        JSValueRegs rightRegs = right.jsValueRegs();
+
+        flushRegisters();
+        JSValueRegsFlushedCallResult result(this);
+        JSValueRegs resultRegs = result.regs();
+        callOperation(operationValueMul, resultRegs, leftRegs, rightRegs);
+        m_jit.exceptionCheck();
+
+        jsValueResult(resultRegs, node);
+        return;
+    }
+
+    bool needsScratchGPRReg = true;
+#if USE(JSVALUE64)
+    bool needsScratchFPRReg = false;
+#else
+    bool needsScratchFPRReg = true;
+#endif
+
+    CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
+    ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex);
+    const Instruction* instruction = baselineCodeBlock->instructions().at(node->origin.semantic.bytecodeIndex).ptr();
+    JITMulIC* mulIC = m_jit.codeBlock()->addJITMulIC(arithProfile, instruction);
+    auto repatchingFunction = operationValueMulOptimize;
+    auto nonRepatchingFunction = operationValueMul;
+
+    compileMathIC(node, mulIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
+}
 
 void SpeculativeJIT::compileArithMul(Node* node)
 {
@@ -4917,45 +4974,6 @@ void SpeculativeJIT::compileArithMul(Node* node)
         return;
     }
 
-    case UntypedUse: {
-        Edge& leftChild = node->child1();
-        Edge& rightChild = node->child2();
-
-        if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
-            JSValueOperand left(this, leftChild);
-            JSValueOperand right(this, rightChild);
-            JSValueRegs leftRegs = left.jsValueRegs();
-            JSValueRegs rightRegs = right.jsValueRegs();
-
-            flushRegisters();
-            JSValueRegsFlushedCallResult result(this);
-            JSValueRegs resultRegs = result.regs();
-            callOperation(operationValueMul, resultRegs, leftRegs, rightRegs);
-            m_jit.exceptionCheck();
-
-            jsValueResult(resultRegs, node);
-            return;
-        }
-
-#if USE(JSVALUE64)
-        bool needsScratchGPRReg = true;
-        bool needsScratchFPRReg = false;
-#else
-        bool needsScratchGPRReg = true;
-        bool needsScratchFPRReg = true;
-#endif
-
-        CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
-        ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex);
-        const Instruction* instruction = baselineCodeBlock->instructions().at(node->origin.semantic.bytecodeIndex).ptr();
-        JITMulIC* mulIC = m_jit.codeBlock()->addJITMulIC(arithProfile, instruction);
-        auto repatchingFunction = operationValueMulOptimize;
-        auto nonRepatchingFunction = operationValueMul;
-        
-        compileMathIC(node, mulIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
-        return;
-    }
-
     default:
         RELEASE_ASSERT_NOT_REACHED();
         return;
index adb3ba1..a20e39a 100644 (file)
@@ -1354,6 +1354,7 @@ public:
     void compileArithSub(Node*);
     void compileValueNegate(Node*);
     void compileArithNegate(Node*);
+    void compileValueMul(Node*);
     void compileArithMul(Node*);
     void compileArithDiv(Node*);
     void compileArithFRound(Node*);
index ce3e266..bcf7c72 100644 (file)
@@ -2067,6 +2067,10 @@ void SpeculativeJIT::compile(Node* node)
         compileArithMul(node);
         break;
 
+    case ValueMul:
+        compileValueMul(node);
+        break;
+
     case ArithDiv: {
         compileArithDiv(node);
         break;
index fb161a7..0662744 100644 (file)
@@ -2209,6 +2209,10 @@ void SpeculativeJIT::compile(Node* node)
         compileArithMul(node);
         break;
 
+    case ValueMul:
+        compileValueMul(node);
+        break;
+
     case ArithDiv: {
         compileArithDiv(node);
         break;
index 5382f8a..6677ee5 100644 (file)
@@ -255,6 +255,7 @@ public:
                 case MakeRope:
                 case ValueAdd:
                 case ValueSub:
+                case ValueMul:
                 case ArithAdd:
                 case ArithSub:
                 case ArithMul:
index da11381..0a3569f 100644 (file)
@@ -93,6 +93,7 @@ inline CapabilityLevel canCompile(Node* node)
     case ValueNegate:
     case ValueAdd:
     case ValueSub:
+    case ValueMul:
     case StrCat:
     case ArithAdd:
     case ArithClz32:
index fb04397..0823fc8 100644 (file)
@@ -597,6 +597,9 @@ private:
         case ValueSub:
             compileValueSub();
             break;
+        case ValueMul:
+            compileValueMul();
+            break;
         case StrCat:
             compileStrCat();
             break;
@@ -1904,6 +1907,25 @@ private:
         compileBinaryMathIC<JITSubGenerator>(arithProfile, instruction, repatchingFunction, nonRepatchingFunction);
     }
 
+    void compileValueMul()
+    {
+        if (m_node->isBinaryUseKind(BigIntUse)) {
+            LValue left = lowBigInt(m_node->child1());
+            LValue right = lowBigInt(m_node->child2());
+            
+            LValue result = vmCall(Int64, m_out.operation(operationMulBigInt), m_callFrame, left, right);
+            setJSValue(result);
+            return;
+        }
+
+        CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic);
+        ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex);
+        const Instruction* instruction = baselineCodeBlock->instructions().at(m_node->origin.semantic.bytecodeIndex).ptr();
+        auto repatchingFunction = operationValueMulOptimize;
+        auto nonRepatchingFunction = operationValueMul;
+        compileBinaryMathIC<JITMulGenerator>(arithProfile, instruction, repatchingFunction, nonRepatchingFunction);
+    }
+
     template <typename Generator, typename Func1, typename Func2,
         typename = std::enable_if_t<std::is_function<typename std::remove_pointer<Func1>::type>::value && std::is_function<typename std::remove_pointer<Func2>::type>::value>>
     void compileUnaryMathIC(ArithProfile* arithProfile, const Instruction* instruction, Func1 repatchingFunction, Func2 nonRepatchingFunction)
@@ -2252,16 +2274,6 @@ private:
             break;
         }
 
-        case UntypedUse: {
-            CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic);
-            ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex);
-            const Instruction* instruction = baselineCodeBlock->instructions().at(m_node->origin.semantic.bytecodeIndex).ptr();
-            auto repatchingFunction = operationValueMulOptimize;
-            auto nonRepatchingFunction = operationValueMul;
-            compileBinaryMathIC<JITMulGenerator>(arithProfile, instruction, repatchingFunction, nonRepatchingFunction);
-            break;
-        }
-
         default:
             DFG_CRASH(m_graph, m_node, "Bad use kind");
             break;