Polymorphic operand types for DFG and FTL mul.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Dec 2015 05:42:56 +0000 (05:42 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Dec 2015 05:42:56 +0000 (05:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=151746

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Perf on benchmarks is neutral except for the newly added JSRegress ftl-object-mul
test which shows a 2.16x speed up on x86_64 FTL, 1.27x speed up on x86_64 DFG,
and 1.56x on x86 DFG.

The speed up comes not from the mul operator itself, but from the fact that the
polymorphic operand types support now allow the test function to run without OSR
exiting, thereby realizing the DFG and FTL's speed up on other work that the test
function does.

This patch has passed the layout tests on x86_64 with a debug build.
It passed the JSC tests with x86 and x86_64 debug builds.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithMul):
* ftl/FTLCompile.cpp:
- Changed to call generateBinaryOpFastPath() instead now, and let it dispatch to
  the appropriate snippet generator.

* ftl/FTLCompileBinaryOp.cpp:
(JSC::FTL::generateBinaryArithOpFastPath):
(JSC::FTL::generateBinaryOpFastPath):
(JSC::FTL::generateArithSubFastPath): Deleted.
(JSC::FTL::generateValueAddFastPath): Deleted.
- Refactored these functions to eliminate the need for copy-pasting every time
  we add support for another binary arithmetic snippet.

* ftl/FTLCompileBinaryOp.h:
* ftl/FTLInlineCacheDescriptor.h:
* ftl/FTLInlineCacheDescriptorInlines.h:
(JSC::FTL::ArithMulDescriptor::ArithMulDescriptor):
(JSC::FTL::ArithMulDescriptor::icSize):
* ftl/FTLInlineCacheSize.cpp:
(JSC::FTL::sizeOfArithMul):
* ftl/FTLInlineCacheSize.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::lower):
(JSC::FTL::DFG::LowerDFGToLLVM::compileArithMul):
* jit/JITMulGenerator.h:
(JSC::JITMulGenerator::JITMulGenerator):

* tests/stress/op_mul.js:
- Updated a test value: the interesting value for imminent overflow from an
  int32 is 0x7fffffff, not 0x7ffffff.

LayoutTests:

* js/regress/ftl-object-mul-expected.txt: Added.
* js/regress/ftl-object-mul.html: Added.
* js/regress/script-tests/ftl-object-mul.js: Added.
(o1.valueOf):
(foo):

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

22 files changed:
LayoutTests/ChangeLog
LayoutTests/js/regress/ftl-object-mul-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/ftl-object-mul.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/ftl-object-mul.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/ftl/FTLCompile.cpp
Source/JavaScriptCore/ftl/FTLCompileBinaryOp.cpp
Source/JavaScriptCore/ftl/FTLCompileBinaryOp.h
Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h
Source/JavaScriptCore/ftl/FTLInlineCacheDescriptorInlines.h
Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp
Source/JavaScriptCore/ftl/FTLInlineCacheSize.h
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/jit/JITMulGenerator.h
Source/JavaScriptCore/tests/stress/op_mul.js

index 3609c18..455b8ea 100644 (file)
@@ -1,3 +1,16 @@
+2015-12-02  Mark Lam  <mark.lam@apple.com>
+
+        Polymorphic operand types for DFG and FTL mul.
+        https://bugs.webkit.org/show_bug.cgi?id=151746
+
+        Reviewed by Filip Pizlo.
+
+        * js/regress/ftl-object-mul-expected.txt: Added.
+        * js/regress/ftl-object-mul.html: Added.
+        * js/regress/script-tests/ftl-object-mul.js: Added.
+        (o1.valueOf):
+        (foo):
+
 2015-12-02  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Unify font-variant-* with font-variant shorthand
diff --git a/LayoutTests/js/regress/ftl-object-mul-expected.txt b/LayoutTests/js/regress/ftl-object-mul-expected.txt
new file mode 100644 (file)
index 0000000..f5eebb3
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/ftl-object-mul
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/ftl-object-mul.html b/LayoutTests/js/regress/ftl-object-mul.html
new file mode 100644 (file)
index 0000000..df24dee
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/ftl-object-mul.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/ftl-object-mul.js b/LayoutTests/js/regress/script-tests/ftl-object-mul.js
new file mode 100644 (file)
index 0000000..4304a7a
--- /dev/null
@@ -0,0 +1,40 @@
+//@ runFTLNoCJIT
+var o1 = {
+    i: 0,
+    valueOf: function() { return this.i; }
+};
+
+result = 0;
+function foo(a, b) {
+    var result = 0;
+    for (var j = 0; j < 10; j++) {
+        if (a > b)
+            result += a * b;
+        else
+            result += b * 1;
+    }
+    for (var i = 0; i < 1000; i++)
+        result += i;
+    return result;
+}
+noInline(foo);
+
+var iterations;
+var expectedResult;
+if (this.window) {
+    // The layout test doesn't like too many iterations and may time out.
+    iterations = 10000;
+    expectedResult = 9997995200;
+} else {
+    iterations = 100000;
+    expectedResult = 549975495200;
+}
+
+
+for (var i = 0; i <= iterations; i++) {
+    o1.i = i + 2;
+    result += foo(o1, 10);
+}
+
+if (result != expectedResult)
+    throw "Bad result: " + result;
index 881650c..92ae297 100644 (file)
@@ -1,3 +1,64 @@
+2015-12-02  Mark Lam  <mark.lam@apple.com>
+
+        Polymorphic operand types for DFG and FTL mul.
+        https://bugs.webkit.org/show_bug.cgi?id=151746
+
+        Reviewed by Filip Pizlo.
+
+        Perf on benchmarks is neutral except for the newly added JSRegress ftl-object-mul
+        test which shows a 2.16x speed up on x86_64 FTL, 1.27x speed up on x86_64 DFG,
+        and 1.56x on x86 DFG. 
+
+        The speed up comes not from the mul operator itself, but from the fact that the
+        polymorphic operand types support now allow the test function to run without OSR
+        exiting, thereby realizing the DFG and FTL's speed up on other work that the test
+        function does.
+
+        This patch has passed the layout tests on x86_64 with a debug build.
+        It passed the JSC tests with x86 and x86_64 debug builds.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithMul):
+        * ftl/FTLCompile.cpp:
+        - Changed to call generateBinaryOpFastPath() instead now, and let it dispatch to
+          the appropriate snippet generator.
+
+        * ftl/FTLCompileBinaryOp.cpp:
+        (JSC::FTL::generateBinaryArithOpFastPath):
+        (JSC::FTL::generateBinaryOpFastPath):
+        (JSC::FTL::generateArithSubFastPath): Deleted.
+        (JSC::FTL::generateValueAddFastPath): Deleted.
+        - Refactored these functions to eliminate the need for copy-pasting every time
+          we add support for another binary arithmetic snippet.
+
+        * ftl/FTLCompileBinaryOp.h:
+        * ftl/FTLInlineCacheDescriptor.h:
+        * ftl/FTLInlineCacheDescriptorInlines.h:
+        (JSC::FTL::ArithMulDescriptor::ArithMulDescriptor):
+        (JSC::FTL::ArithMulDescriptor::icSize):
+        * ftl/FTLInlineCacheSize.cpp:
+        (JSC::FTL::sizeOfArithMul):
+        * ftl/FTLInlineCacheSize.h:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::lower):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileArithMul):
+        * jit/JITMulGenerator.h:
+        (JSC::JITMulGenerator::JITMulGenerator):
+
+        * tests/stress/op_mul.js:
+        - Updated a test value: the interesting value for imminent overflow from an
+          int32 is 0x7fffffff, not 0x7ffffff.
+
 2015-12-02  Joseph Pecoraro  <pecoraro@apple.com>
 
         REGRESSION(r192753): Remote Web Inspector: Applications and Debuggables not showing up in debuggers
index 12e286f..3613178 100644 (file)
@@ -634,6 +634,10 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
                 typeOfDoubleProduct(
                     forNode(node->child1()).m_type, forNode(node->child2()).m_type));
             break;
+        case UntypedUse:
+            clobberWorld(node->origin.semantic, clobberLimit);
+            forNode(node).setType(m_graph, SpecBytecodeNumber);
+            break;
         default:
             RELEASE_ASSERT_NOT_REACHED();
             break;
index 0f09c8d..417d06f 100644 (file)
@@ -248,7 +248,6 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
 
     case ArithAdd:
     case ArithNegate:
-    case ArithMul:
     case ArithDiv:
     case ArithMod:
     case DoubleAsInt32:
@@ -257,6 +256,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         return;
 
     case ArithSub:
+    case ArithMul:
         switch (node->binaryUseKind()) {
         case Int32Use:
         case Int52RepUse:
index a957d2b..65e4927 100644 (file)
@@ -227,9 +227,18 @@ private:
         }
             
         case ArithMul: {
+            Edge& leftChild = node->child1();
+            Edge& rightChild = node->child2();
+            if (Node::shouldSpeculateUntypedForArithmetic(leftChild.node(), rightChild.node())
+                || m_graph.hasExitSite(node->origin.semantic, BadType)) {
+                fixEdge<UntypedUse>(leftChild);
+                fixEdge<UntypedUse>(rightChild);
+                node->setResult(NodeResultJS);
+                break;
+            }
             if (m_graph.mulShouldSpeculateInt32(node, FixupPass)) {
-                fixIntOrBooleanEdge(node->child1());
-                fixIntOrBooleanEdge(node->child2());
+                fixIntOrBooleanEdge(leftChild);
+                fixIntOrBooleanEdge(rightChild);
                 if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
                     node->setArithMode(Arith::Unchecked);
                 else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -239,8 +248,8 @@ private:
                 break;
             }
             if (m_graph.mulShouldSpeculateMachineInt(node, FixupPass)) {
-                fixEdge<Int52RepUse>(node->child1());
-                fixEdge<Int52RepUse>(node->child2());
+                fixEdge<Int52RepUse>(leftChild);
+                fixEdge<Int52RepUse>(rightChild);
                 if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
                     node->setArithMode(Arith::CheckOverflow);
                 else
@@ -248,8 +257,8 @@ private:
                 node->setResult(NodeResultInt52);
                 break;
             }
-            fixDoubleOrBooleanEdge(node->child1());
-            fixDoubleOrBooleanEdge(node->child2());
+            fixDoubleOrBooleanEdge(leftChild);
+            fixDoubleOrBooleanEdge(rightChild);
             node->setResult(NodeResultDouble);
             break;
         }
index 8fa219c..c7a0eaa 100644 (file)
@@ -200,6 +200,19 @@ EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState* exec, Encoded
     return JSValue::encode(jsAddSlowCase(exec, op1, op2));
 }
 
+EncodedJSValue JIT_OPERATION operationValueMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+
+    JSValue op1 = JSValue::decode(encodedOp1);
+    JSValue op2 = JSValue::decode(encodedOp2);
+
+    double a = op1.toNumber(exec);
+    double b = op2.toNumber(exec);
+    return JSValue::encode(jsNumber(a * b));
+}
+
 EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
 {
     VM* vm = &exec->vm();
index 8d1fc2b..3c2c94f 100644 (file)
@@ -45,6 +45,7 @@ EncodedJSValue JIT_OPERATION operationToThis(ExecState*, EncodedJSValue encodedO
 EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationValueMul(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueSub(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL;
index 437ebbb..40cec76 100644 (file)
@@ -334,12 +334,16 @@ private:
             SpeculatedType right = node->child2()->prediction();
             
             if (left && right) {
-                if (m_graph.mulShouldSpeculateInt32(node, m_pass))
-                    changed |= mergePrediction(SpecInt32);
-                else if (m_graph.mulShouldSpeculateMachineInt(node, m_pass))
-                    changed |= mergePrediction(SpecInt52);
-                else
-                    changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+                if (isFullNumberOrBooleanSpeculationExpectingDefined(left)
+                    && isFullNumberOrBooleanSpeculationExpectingDefined(right)) {
+                    if (m_graph.mulShouldSpeculateInt32(node, m_pass))
+                        changed |= mergePrediction(SpecInt32);
+                    else if (m_graph.mulShouldSpeculateMachineInt(node, m_pass))
+                        changed |= mergePrediction(SpecInt52);
+                    else
+                        changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+                } else
+                    changed |= mergePrediction(SpecInt32 | SpecBytecodeDouble);
             }
             break;
         }
index 800613c..19909e6 100755 (executable)
@@ -39,6 +39,7 @@
 #include "DFGSlowPathGenerator.h"
 #include "DirectArguments.h"
 #include "JITAddGenerator.h"
+#include "JITMulGenerator.h"
 #include "JITSubGenerator.h"
 #include "JSArrowFunction.h"
 #include "JSCInlines.h"
@@ -3443,7 +3444,108 @@ void SpeculativeJIT::compileArithMul(Node* node)
         doubleResult(result.fpr(), 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();
+#if USE(JSVALUE64)
+            GPRTemporary result(this);
+            JSValueRegs resultRegs = JSValueRegs(result.gpr());
+#else
+            GPRTemporary resultTag(this);
+            GPRTemporary resultPayload(this);
+            JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+#endif
+            flushRegisters();
+            callOperation(operationValueMul, resultRegs, leftRegs, rightRegs);
+            m_jit.exceptionCheck();
+
+            jsValueResult(resultRegs, node);
+            return;
+        }
+
+        Optional<JSValueOperand> left;
+        Optional<JSValueOperand> right;
+
+        JSValueRegs leftRegs;
+        JSValueRegs rightRegs;
+
+        FPRTemporary leftNumber(this);
+        FPRTemporary rightNumber(this);
+        FPRReg leftFPR = leftNumber.fpr();
+        FPRReg rightFPR = rightNumber.fpr();
+
+#if USE(JSVALUE64)
+        GPRTemporary result(this);
+        JSValueRegs resultRegs = JSValueRegs(result.gpr());
+        GPRTemporary scratch(this);
+        GPRReg scratchGPR = scratch.gpr();
+        FPRReg scratchFPR = InvalidFPRReg;
+#else
+        GPRTemporary resultTag(this);
+        GPRTemporary resultPayload(this);
+        JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+        GPRReg scratchGPR = resultTag.gpr();
+        FPRTemporary fprScratch(this);
+        FPRReg scratchFPR = fprScratch.fpr();
+#endif
+
+        SnippetOperand leftOperand(m_state.forNode(leftChild).resultType());
+        SnippetOperand rightOperand(m_state.forNode(rightChild).resultType());
+
+        if (leftChild->isInt32Constant())
+            leftOperand.setConstInt32(leftChild->asInt32());
+        if (rightChild->isInt32Constant())
+            rightOperand.setConstInt32(rightChild->asInt32());
+
+        RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
+
+        if (!leftOperand.isPositiveConstInt32()) {
+            left = JSValueOperand(this, leftChild);
+            leftRegs = left->jsValueRegs();
+        }
+        if (!rightOperand.isPositiveConstInt32()) {
+            right = JSValueOperand(this, rightChild);
+            rightRegs = right->jsValueRegs();
+        }
+
+        JITMulGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
+            leftFPR, rightFPR, scratchGPR, scratchFPR);
+        gen.generateFastPath(m_jit);
+
+        ASSERT(gen.didEmitFastPath());
+        gen.endJumpList().append(m_jit.jump());
+
+        gen.slowPathJumpList().link(&m_jit);
+        silentSpillAllRegisters(resultRegs);
+
+        if (leftOperand.isPositiveConstInt32()) {
+            leftRegs = resultRegs;
+            int64_t leftConst = leftOperand.asConstInt32();
+            m_jit.moveValue(JSValue(leftConst), leftRegs);
+        }
+        if (rightOperand.isPositiveConstInt32()) {
+            rightRegs = resultRegs;
+            int64_t rightConst = rightOperand.asConstInt32();
+            m_jit.moveValue(JSValue(rightConst), rightRegs);
+        }
+
+        callOperation(operationValueMul, resultRegs, leftRegs, rightRegs);
+
+        silentFillAllRegisters(resultRegs);
+        m_jit.exceptionCheck();
+
+        gen.endJumpList().link(&m_jit);
+        jsValueResult(resultRegs, node);
+        return;
+    }
+
     default:
         RELEASE_ASSERT_NOT_REACHED();
         return;
index 5001145..2331163 100644 (file)
@@ -336,16 +336,7 @@ static void generateBinaryOpICFastPath(
         CCallHelpers::Jump done;
         CCallHelpers::Jump slowPathStart;
 
-        switch (ic.nodeType()) {
-        case ArithSub:
-            generateArithSubFastPath(ic, fastPathJIT, result, left, right, usedRegisters, done, slowPathStart);
-            break;
-        case ValueAdd:
-            generateValueAddFastPath(ic, fastPathJIT, result, left, right, usedRegisters, done, slowPathStart);
-            break;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-        }
+        generateBinaryOpFastPath(ic, fastPathJIT, result, left, right, usedRegisters, done, slowPathStart);
 
         char* startOfIC = bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
         const char* fastPathICName = ic.fastPathICName();
index f2929de..67a3ece 100644 (file)
@@ -32,6 +32,7 @@
 #include "FTLInlineCacheDescriptor.h"
 #include "GPRInfo.h"
 #include "JITAddGenerator.h"
+#include "JITMulGenerator.h"
 #include "JITSubGenerator.h"
 #include "ScratchRegisterAllocator.h"
 
@@ -152,11 +153,11 @@ private:
     GPRReg m_savedTagTypeNumberRegister { InvalidGPRReg };
 };
 
-void generateArithSubFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
+template<typename BinaryArithOpGenerator>
+void generateBinaryArithOpFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
     GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
     CCallHelpers::Jump& done, CCallHelpers::Jump& slowPathStart)
 {
-    ASSERT(ic.nodeType() == ArithSub);
     ScratchRegisterAllocator allocator(usedRegisters);
 
     BinarySnippetRegisterContext context(allocator, result, left, right);
@@ -166,7 +167,7 @@ void generateArithSubFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
     FPRReg rightFPR = allocator.allocateScratchFPR();
     FPRReg scratchFPR = InvalidFPRReg;
 
-    JITSubGenerator gen(ic.leftOperand(), ic.rightOperand(), JSValueRegs(result),
+    BinaryArithOpGenerator gen(ic.leftOperand(), ic.rightOperand(), JSValueRegs(result),
         JSValueRegs(left), JSValueRegs(right), leftFPR, rightFPR, scratchGPR, scratchFPR);
 
     auto numberOfBytesUsedToPreserveReusedRegisters =
@@ -189,41 +190,23 @@ void generateArithSubFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
     slowPathStart = jit.jump();
 }
 
-void generateValueAddFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
+void generateBinaryOpFastPath(BinaryOpDescriptor& ic, CCallHelpers& jit,
     GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
     CCallHelpers::Jump& done, CCallHelpers::Jump& slowPathStart)
 {
-    ASSERT(ic.nodeType() == ValueAdd);
-    ScratchRegisterAllocator allocator(usedRegisters);
-
-    BinarySnippetRegisterContext context(allocator, result, left, right);
-
-    GPRReg scratchGPR = allocator.allocateScratchGPR();
-    FPRReg leftFPR = allocator.allocateScratchFPR();
-    FPRReg rightFPR = allocator.allocateScratchFPR();
-    FPRReg scratchFPR = InvalidFPRReg;
-
-    JITAddGenerator gen(ic.leftOperand(), ic.rightOperand(), JSValueRegs(result),
-        JSValueRegs(left), JSValueRegs(right), leftFPR, rightFPR, scratchGPR, scratchFPR);
-
-    auto numberOfBytesUsedToPreserveReusedRegisters =
-    allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace);
-
-    context.initializeRegisters(jit);
-    gen.generateFastPath(jit);
-
-    ASSERT(gen.didEmitFastPath());
-    gen.endJumpList().link(&jit);
-    context.restoreRegisters(jit);
-    allocator.restoreReusedRegistersByPopping(jit, numberOfBytesUsedToPreserveReusedRegisters,
-        ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
-    done = jit.jump();
-
-    gen.slowPathJumpList().link(&jit);
-    context.restoreRegisters(jit);
-    allocator.restoreReusedRegistersByPopping(jit, numberOfBytesUsedToPreserveReusedRegisters,
-        ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
-    slowPathStart = jit.jump();
+    switch (ic.nodeType()) {
+    case ArithMul:
+        generateBinaryArithOpFastPath<JITMulGenerator>(ic, jit, result, left, right, usedRegisters, done, slowPathStart);
+        break;
+    case ArithSub:
+        generateBinaryArithOpFastPath<JITSubGenerator>(ic, jit, result, left, right, usedRegisters, done, slowPathStart);
+        break;
+    case ValueAdd:
+        generateBinaryArithOpFastPath<JITAddGenerator>(ic, jit, result, left, right, usedRegisters, done, slowPathStart);
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
 }
 
 } } // namespace JSC::FTL
index f89fb96..ead6325 100644 (file)
@@ -35,11 +35,7 @@ namespace FTL {
 
 class BinaryOpDescriptor;
 
-void generateArithSubFastPath(BinaryOpDescriptor&, CCallHelpers&,
-    GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
-    CCallHelpers::Jump& done, CCallHelpers::Jump& slowPathStart);
-
-void generateValueAddFastPath(BinaryOpDescriptor&, CCallHelpers&,
+void generateBinaryOpFastPath(BinaryOpDescriptor&, CCallHelpers&,
     GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
     CCallHelpers::Jump& done, CCallHelpers::Jump& slowPathStart);
 
index 3368a8f..ec77c4a 100644 (file)
@@ -165,6 +165,12 @@ protected:
     SnippetOperand m_rightOperand;
 };
 
+class ArithMulDescriptor : public BinaryOpDescriptor {
+public:
+    ArithMulDescriptor(unsigned stackmapID, CodeOrigin, const SnippetOperand& leftOperand, const SnippetOperand& rightOperand);
+    static size_t icSize();
+};
+
 class ArithSubDescriptor : public BinaryOpDescriptor {
 public:
     ArithSubDescriptor(unsigned stackmapID, CodeOrigin, const SnippetOperand& leftOperand, const SnippetOperand& rightOperand);
index 088b493..6c21945 100644 (file)
 
 namespace JSC { namespace FTL {
 
+ArithMulDescriptor::ArithMulDescriptor(unsigned stackmapID, CodeOrigin codeOrigin,
+    const SnippetOperand& leftOperand, const SnippetOperand& rightOperand)
+    : BinaryOpDescriptor(DFG::ArithMul, stackmapID, codeOrigin, icSize(),
+        "ArithMul", "ArithMul IC fast path", DFG::operationValueMul, leftOperand, rightOperand)
+{
+}
+
+size_t ArithMulDescriptor::icSize()
+{
+    return sizeOfArithMul();
+}
+
 ArithSubDescriptor::ArithSubDescriptor(unsigned stackmapID, CodeOrigin codeOrigin,
     const SnippetOperand& leftOperand, const SnippetOperand& rightOperand)
     : BinaryOpDescriptor(DFG::ArithSub, stackmapID, codeOrigin, icSize(),
index a5ad2b0..ea94e50 100644 (file)
@@ -128,6 +128,23 @@ size_t sizeOfIn()
 #endif
 }
 
+size_t sizeOfArithMul()
+{
+#if CPU(ARM64)
+#ifdef NDEBUG
+    return 180; // ARM64 release.
+#else
+    return 276; // ARM64 debug.
+#endif
+#else // CPU(X86_64)
+#ifdef NDEBUG
+    return 199; // X86_64 release.
+#else
+    return 286; // X86_64 debug.
+#endif
+#endif
+}
+
 size_t sizeOfArithSub()
 {
 #if CPU(ARM64)
index c360608..cbab2b8 100644 (file)
@@ -46,6 +46,7 @@ size_t sizeOfTailCallForwardVarargs();
 size_t sizeOfConstructVarargs();
 size_t sizeOfConstructForwardVarargs();
 size_t sizeOfIn();
+size_t sizeOfArithMul();
 size_t sizeOfArithSub();
 size_t sizeOfValueAdd();
 #if ENABLE(MASM_PROBE)
index 6539e08..1821d68 100644 (file)
@@ -232,6 +232,7 @@ public:
                             maxNumberOfCatchSpills = std::max(maxNumberOfCatchSpills, m_graph.localsLiveInBytecode(opCatchOrigin).bitCount());
                         break;
                     }
+                    case ArithMul:
                     case ArithSub:
                     case GetById:
                     case GetByIdFlush:
@@ -1485,8 +1486,8 @@ private:
     
     void compileValueAdd()
     {
-        auto leftChild = m_node->child1();
-        auto rightChild = m_node->child2();
+        Edge& leftChild = m_node->child1();
+        Edge& rightChild = m_node->child2();
 
         if (!(provenType(leftChild) & SpecFullNumber) || !(provenType(rightChild) & SpecFullNumber)) {
             setJSValue(vmCall(m_out.int64, m_out.operation(operationValueAddNotNumber), m_callFrame,
@@ -1809,7 +1810,60 @@ private:
                 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
             break;
         }
-            
+
+        case UntypedUse: {
+            Edge& leftChild = m_node->child1();
+            Edge& rightChild = m_node->child2();
+
+            if (!(provenType(leftChild) & SpecFullNumber) || !(provenType(rightChild) & SpecFullNumber)) {
+                setJSValue(vmCall(m_out.int64, m_out.operation(operationValueMul), m_callFrame,
+                    lowJSValue(leftChild), lowJSValue(rightChild)));
+                return;
+            }
+
+            unsigned stackmapID = m_stackmapIDs++;
+
+            if (Options::verboseCompilation())
+                dataLog("    Emitting ArithMul patchpoint with stackmap #", stackmapID, "\n");
+
+#if FTL_USES_B3
+            CRASH();
+#else
+            LValue left = lowJSValue(leftChild);
+            LValue right = lowJSValue(rightChild);
+
+            SnippetOperand leftOperand(abstractValue(leftChild).resultType());
+            SnippetOperand rightOperand(abstractValue(rightChild).resultType());
+
+            if (leftChild->isInt32Constant())
+                leftOperand.setConstInt32(leftChild->asInt32());
+            if (rightChild->isInt32Constant())
+                rightOperand.setConstInt32(rightChild->asInt32());
+
+            RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
+
+            // Arguments: id, bytes, target, numArgs, args...
+            StackmapArgumentList arguments;
+            arguments.append(m_out.constInt64(stackmapID));
+            arguments.append(m_out.constInt32(ArithSubDescriptor::icSize()));
+            arguments.append(constNull(m_out.ref8));
+            arguments.append(m_out.constInt32(2));
+            arguments.append(left);
+            arguments.append(right);
+
+            appendOSRExitArgumentsForPatchpointIfWillCatchException(arguments,
+                ExceptionType::BinaryOpGenerator, 3); // left, right, and result show up in the stackmap locations.
+
+            LValue call = m_out.call(m_out.int64, m_out.patchpointInt64Intrinsic(), arguments);
+            setInstructionCallingConvention(call, LLVMAnyRegCallConv);
+
+            m_ftlState.binaryOps.append(ArithMulDescriptor(stackmapID, m_node->origin.semantic, leftOperand, rightOperand));
+
+            setJSValue(call);
+#endif
+            break;
+        }
+
         default:
             DFG_CRASH(m_graph, m_node, "Bad use kind");
             break;
index a6993b0..3c96158 100644 (file)
@@ -37,7 +37,7 @@ class JITMulGenerator {
 public:
     JITMulGenerator(SnippetOperand leftOperand, SnippetOperand rightOperand,
         JSValueRegs result, JSValueRegs left, JSValueRegs right,
-        FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR, uint32_t* profilingCounter)
+        FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR, uint32_t* profilingCounter = nullptr)
         : m_leftOperand(leftOperand)
         , m_rightOperand(rightOperand)
         , m_result(result)
index 562a74a..a7babad 100644 (file)
@@ -43,8 +43,8 @@ var values = [
     '-0x7fff',
     '0x10000',
     '-0x10000',
-    '0x7ffffff',
-    '-0x7ffffff',
+    '0x7fffffff',
+    '-0x7fffffff',
     '0x100000000',
     '-0x100000000',
 
@@ -59,8 +59,8 @@ var values = [
     '"-0x7fff"',
     '"0x10000"',
     '"-0x10000"',
-    '"0x7ffffff"',
-    '"-0x7ffffff"',
+    '"0x7fffffff"',
+    '"-0x7fffffff"',
     '"0x100000000"',
     '"-0x100000000"',
 ];