Changeset 245063 in webkit


Ignore:
Timestamp:
May 8, 2019 12:38:17 PM (5 years ago)
Author:
Caio Lima
Message:

[BigInt] Add ValueMod into DFG
https://bugs.webkit.org/show_bug.cgi?id=186174

Reviewed by Saam Barati.

JSTests:

  • microbenchmarks/mod-untyped.js: Added.
  • stress/big-int-mod-osr.js: Added.
  • stress/value-div-ai-rule.js: Added.
  • stress/value-mod-ai-rule.js: Added.

PerformanceTests:

  • BigIntBench/big-int-simple-mod.js: Added.

Source/JavaScriptCore:

This patch is introducing a new DFG node called ValueMod, that is
responsible to handle BigInt and Untyped specialization of op_mod.
With the introduction of BigInt, we think that cases with
ValueMod(Untyped, Untyped) can be more common and we introduced
support for such kind of node.

  • dfg/DFGAbstractInterpreter.h:
  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::handleConstantDivOp):

We are abstracting the constant rules of division operations. It
includes ArithDiv, ValueDiv, ArithMod and ValueMod, since they perform
the same analysis.

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGBackwardsPropagationPhase.cpp:

(JSC::DFG::BackwardsPropagationPhase::propagate):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::makeSafe):
(JSC::DFG::ByteCodeParser::parseBlock):

Here we check if lhs and rhs have number result to emit ArithMod.
Otherwise, we need to fallback to ValueMod and let fixup replace this
operation when possible.

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

ValueMod(BigIntUse) doesn't clobberize world because it only calls
operationModBigInt.

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

ValueMod(BigIntUse) can trigger GC since it allocates intermediate
JSBigInt to perform calculation. ValueMod(UntypedUse) can trigger GC
because it can execute arbritary code from user.

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupArithDivInt32):

Function created to simplify readability of ArithDiv/AirthMod fixup
operation.

(JSC::DFG::FixupPhase::fixupArithDiv):
(JSC::DFG::FixupPhase::fixupNode):

Following the same fixup rules of ArithDiv.

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:

(JSC::DFG::binaryOp):

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

ValueMod follows the same prediction propagation rules of ArithMod and
the same rules for doDoubleVoting.

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileValueMod):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • 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::compileValueMod):

Location:
trunk
Files:
5 added
22 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r245051 r245063  
     12019-05-08  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [BigInt] Add ValueMod into DFG
     4        https://bugs.webkit.org/show_bug.cgi?id=186174
     5
     6        Reviewed by Saam Barati.
     7
     8        * microbenchmarks/mod-untyped.js: Added.
     9        * stress/big-int-mod-osr.js: Added.
     10        * stress/value-div-ai-rule.js: Added.
     11        * stress/value-mod-ai-rule.js: Added.
     12
    1132019-05-07  Yusuke Suzuki  <ysuzuki@apple.com>
    214
  • trunk/PerformanceTests/ChangeLog

    r244973 r245063  
     12019-05-08  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [BigInt] Add ValueMod into DFG
     4        https://bugs.webkit.org/show_bug.cgi?id=186174
     5
     6        Reviewed by Saam Barati.
     7
     8        * BigIntBench/big-int-simple-mod.js: Added.
     9
    1102019-05-06  Saam Barati  <sbarati@apple.com>
    211
  • trunk/Source/JavaScriptCore/ChangeLog

    r245051 r245063  
     12019-05-08  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [BigInt] Add ValueMod into DFG
     4        https://bugs.webkit.org/show_bug.cgi?id=186174
     5
     6        Reviewed by Saam Barati.
     7
     8        This patch is introducing a new DFG node called ValueMod, that is
     9        responsible to handle BigInt and Untyped specialization of op_mod.
     10        With the introduction of BigInt, we think that cases with
     11        ValueMod(Untyped, Untyped) can be more common and we introduced
     12        support for such kind of node.
     13
     14        * dfg/DFGAbstractInterpreter.h:
     15        * dfg/DFGAbstractInterpreterInlines.h:
     16        (JSC::DFG::AbstractInterpreter<AbstractStateType>::handleConstantDivOp):
     17
     18        We are abstracting the constant rules of division operations. It
     19        includes ArithDiv, ValueDiv, ArithMod and ValueMod, since they perform
     20        the same analysis.
     21
     22        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     23        * dfg/DFGBackwardsPropagationPhase.cpp:
     24        (JSC::DFG::BackwardsPropagationPhase::propagate):
     25        * dfg/DFGByteCodeParser.cpp:
     26        (JSC::DFG::ByteCodeParser::makeSafe):
     27        (JSC::DFG::ByteCodeParser::parseBlock):
     28
     29        Here we check if lhs and rhs have number result to emit ArithMod.
     30        Otherwise, we need to fallback to ValueMod and let fixup replace this
     31        operation when possible.
     32
     33        * dfg/DFGClobberize.h:
     34        (JSC::DFG::clobberize):
     35
     36        ValueMod(BigIntUse) doesn't clobberize world because it only calls
     37        `operationModBigInt`.
     38
     39        * dfg/DFGDoesGC.cpp:
     40        (JSC::DFG::doesGC):
     41
     42        ValueMod(BigIntUse) can trigger GC since it allocates intermediate
     43        JSBigInt to perform calculation. ValueMod(UntypedUse) can trigger GC
     44        because it can execute arbritary code from user.
     45
     46        * dfg/DFGFixupPhase.cpp:
     47        (JSC::DFG::FixupPhase::fixupArithDivInt32):
     48
     49        Function created to simplify readability of ArithDiv/AirthMod fixup
     50        operation.
     51
     52        (JSC::DFG::FixupPhase::fixupArithDiv):
     53        (JSC::DFG::FixupPhase::fixupNode):
     54
     55        Following the same fixup rules of ArithDiv.
     56
     57        * dfg/DFGNodeType.h:
     58        * dfg/DFGOperations.cpp:
     59        (JSC::DFG::binaryOp):
     60        * dfg/DFGOperations.h:
     61        * dfg/DFGPredictionPropagationPhase.cpp:
     62
     63        ValueMod follows the same prediction propagation rules of ArithMod and
     64        the same rules for `doDoubleVoting`.
     65
     66        * dfg/DFGSafeToExecute.h:
     67        (JSC::DFG::safeToExecute):
     68        * dfg/DFGSpeculativeJIT.cpp:
     69        (JSC::DFG::SpeculativeJIT::compileValueMod):
     70        * dfg/DFGSpeculativeJIT.h:
     71        * dfg/DFGSpeculativeJIT32_64.cpp:
     72        (JSC::DFG::SpeculativeJIT::compile):
     73        * dfg/DFGSpeculativeJIT64.cpp:
     74        (JSC::DFG::SpeculativeJIT::compile):
     75        * dfg/DFGValidate.cpp:
     76        * ftl/FTLCapabilities.cpp:
     77        (JSC::FTL::canCompile):
     78        * ftl/FTLLowerDFGToB3.cpp:
     79        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     80        (JSC::FTL::DFG::LowerDFGToB3::compileValueMod):
     81
    1822019-05-07  Yusuke Suzuki  <ysuzuki@apple.com>
    283
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h

    r234086 r245063  
    254254    void executeDoubleUnaryOpEffects(Node*, double(*equivalentFunction)(double));
    255255   
     256    bool handleConstantDivOp(Node*);
     257
    256258    CodeBlock* m_codeBlock;
    257259    Graph& m_graph;
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r244324 r245063  
    235235
    236236template<typename AbstractStateType>
     237bool AbstractInterpreter<AbstractStateType>::handleConstantDivOp(Node* node)
     238{
     239    JSValue left = forNode(node->child1()).value();
     240    JSValue right = forNode(node->child2()).value();
     241
     242    if (left && right) {
     243        NodeType op = node->op();
     244        bool isDivOperation = op == ValueDiv || op == ArithDiv;
     245
     246        // Only possible case of ValueOp below is UntypedUse,
     247        // so we need to reflect clobberize rules.
     248        bool isClobbering = op == ValueDiv || op == ValueMod;
     249
     250        if (left.isInt32() && right.isInt32()) {
     251            double doubleResult;
     252            if (isDivOperation)
     253                doubleResult = left.asNumber() / right.asNumber();
     254            else
     255                doubleResult = fmod(left.asNumber(), right.asNumber());
     256
     257            if (node->hasArithMode()) {
     258                if (!shouldCheckOverflow(node->arithMode()))
     259                    doubleResult = toInt32(doubleResult);
     260                else if (!shouldCheckNegativeZero(node->arithMode()))
     261                    doubleResult += 0; // Sanitizes zero.
     262            }
     263
     264            JSValue valueResult = jsNumber(doubleResult);
     265            if (valueResult.isInt32()) {
     266                if (isClobbering)
     267                    didFoldClobberWorld();
     268                setConstant(node, valueResult);
     269                return true;
     270            }
     271        } else if (left.isNumber() && right.isNumber()) {
     272            if (isClobbering)
     273                didFoldClobberWorld();
     274
     275            if (isDivOperation)
     276                setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber()));
     277            else
     278                setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber())));
     279
     280            return true;
     281        }
     282    }
     283
     284    return false;
     285}
     286
     287template<typename AbstractStateType>
    237288bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimit, Node* node)
    238289{
     
    912963    }
    913964       
     965    case ValueMod:
    914966    case ValueDiv: {
     967        if (handleConstantDivOp(node))
     968            break;
     969
    915970        if (node->binaryUseKind() == BigIntUse)
    916971            setTypeForNode(node, SpecBigInt);
     
    922977    }
    923978
     979    case ArithMod:
    924980    case ArithDiv: {
    925         JSValue left = forNode(node->child1()).value();
    926         JSValue right = forNode(node->child2()).value();
     981        if (handleConstantDivOp(node))
     982            break;
     983
    927984        switch (node->binaryUseKind()) {
    928985        case Int32Use:
    929             if (left && right && left.isInt32() && right.isInt32()) {
    930                 double doubleResult = left.asNumber() / right.asNumber();
    931                 if (!shouldCheckOverflow(node->arithMode()))
    932                     doubleResult = toInt32(doubleResult);
    933                 else if (!shouldCheckNegativeZero(node->arithMode()))
    934                     doubleResult += 0; // Sanitizes zero.
    935                 JSValue valueResult = jsNumber(doubleResult);
    936                 if (valueResult.isInt32()) {
    937                     setConstant(node, valueResult);
    938                     break;
    939                 }
    940             }
    941986            setNonCellTypeForNode(node, SpecInt32Only);
    942987            break;
    943988        case DoubleRepUse:
    944             if (left && right && left.isNumber() && right.isNumber()) {
    945                 setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber()));
    946                 break;
    947             }
    948             setNonCellTypeForNode(node,
    949                 typeOfDoubleQuotient(
    950                     forNode(node->child1()).m_type, forNode(node->child2()).m_type));
    951             break;
    952         default:
    953             RELEASE_ASSERT_NOT_REACHED();
    954             break;
    955         }
    956         break;
    957     }
    958 
    959     case ArithMod: {
    960         JSValue left = forNode(node->child1()).value();
    961         JSValue right = forNode(node->child2()).value();
    962         switch (node->binaryUseKind()) {
    963         case Int32Use:
    964             if (left && right && left.isInt32() && right.isInt32()) {
    965                 double doubleResult = fmod(left.asNumber(), right.asNumber());
    966                 if (!shouldCheckOverflow(node->arithMode()))
    967                     doubleResult = toInt32(doubleResult);
    968                 else if (!shouldCheckNegativeZero(node->arithMode()))
    969                     doubleResult += 0; // Sanitizes zero.
    970                 JSValue valueResult = jsNumber(doubleResult);
    971                 if (valueResult.isInt32()) {
    972                     setConstant(node, valueResult);
    973                     break;
    974                 }
    975             }
    976             setNonCellTypeForNode(node, SpecInt32Only);
    977             break;
    978         case DoubleRepUse:
    979             if (left && right && left.isNumber() && right.isNumber()) {
    980                 setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber())));
    981                 break;
    982             }
    983             setNonCellTypeForNode(node,
    984                 typeOfDoubleBinaryOp(
    985                     forNode(node->child1()).m_type, forNode(node->child2()).m_type));
     989            if (node->op() == ArithDiv) {
     990                setNonCellTypeForNode(node,
     991                    typeOfDoubleQuotient(
     992                        forNode(node->child1()).m_type, forNode(node->child2()).m_type));
     993            } else {
     994                setNonCellTypeForNode(node,
     995                    typeOfDoubleBinaryOp(
     996                        forNode(node->child1()).m_type, forNode(node->child2()).m_type));
     997            }
     998           
    986999            break;
    9871000        default:
  • trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp

    r242715 r245063  
    364364        }
    365365           
     366        case ValueMod:
    366367        case ArithMod: {
    367368            flags |= NodeBytecodeUsesAsNumber;
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r244939 r245063  
    936936            node->mergeFlags(NodeMayNegZeroInDFG);
    937937       
    938         if (!isX86() && node->op() == ArithMod)
     938        if (!isX86() && (node->op() == ArithMod || node->op() == ValueMod))
    939939            return node;
    940940
     
    997997            case ArithSub:
    998998            case ValueAdd:
     999            case ValueMod:
    9991000            case ArithMod: // for ArithMod "MayOverflow" means we tried to divide by zero, or we saw double.
    10001001                node->mergeFlags(NodeMayOverflowInt32InBaseline);
     
    51075108            Node* op1 = get(bytecode.m_lhs);
    51085109            Node* op2 = get(bytecode.m_rhs);
    5109             set(bytecode.m_dst, makeSafe(addToGraph(ArithMod, op1, op2)));
     5110            if (op1->hasNumberResult() && op2->hasNumberResult())
     5111                set(bytecode.m_dst, makeSafe(addToGraph(ArithMod, op1, op2)));
     5112            else
     5113                set(bytecode.m_dst, makeSafe(addToGraph(ValueMod, op1, op2)));
    51105114            NEXT_OPCODE(op_mod);
    51115115        }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r244324 r245063  
    681681    case ValueMul:
    682682    case ValueDiv:
     683    case ValueMod:
    683684        if (node->isBinaryUseKind(BigIntUse)) {
    684685            def(PureValue(node));
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r244324 r245063  
    380380    case ValueMul:
    381381    case ValueDiv:
     382    case ValueMod:
    382383    case ValueBitNot:
    383384    case ValueNegate:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r244324 r245063  
    7676
    7777private:
    78     void fixupArithDiv(Node* node, Edge& leftChild, Edge& rightChild)
    79     {
    80         if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) {
    81             if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) {
    82                 fixIntOrBooleanEdge(leftChild);
    83                 fixIntOrBooleanEdge(rightChild);
    84                 if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
    85                     node->setArithMode(Arith::Unchecked);
    86                 else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
    87                     node->setArithMode(Arith::CheckOverflow);
    88                 else
    89                     node->setArithMode(Arith::CheckOverflowAndNegativeZero);
    90                 return;
    91             }
    92            
    93             // This will cause conversion nodes to be inserted later.
    94             fixDoubleOrBooleanEdge(leftChild);
    95             fixDoubleOrBooleanEdge(rightChild);
    96            
    97             // We don't need to do ref'ing on the children because we're stealing them from
    98             // the original division.
    99             Node* newDivision = m_insertionSet.insertNode(m_indexInBlock, SpecBytecodeDouble, *node);
    100             newDivision->setResult(NodeResultDouble);
    101            
    102             node->setOp(DoubleAsInt32);
    103             node->children.initialize(Edge(newDivision, DoubleRepUse), Edge(), Edge());
    104             if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
     78
     79    void fixupArithDivInt32(Node* node, Edge& leftChild, Edge& rightChild)
     80    {
     81        if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) {
     82            fixIntOrBooleanEdge(leftChild);
     83            fixIntOrBooleanEdge(rightChild);
     84            if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
     85                node->setArithMode(Arith::Unchecked);
     86            else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
    10587                node->setArithMode(Arith::CheckOverflow);
    10688            else
    10789                node->setArithMode(Arith::CheckOverflowAndNegativeZero);
     90            return;
     91        }
     92
     93        // This will cause conversion nodes to be inserted later.
     94        fixDoubleOrBooleanEdge(leftChild);
     95        fixDoubleOrBooleanEdge(rightChild);
     96
     97        // We don't need to do ref'ing on the children because we're stealing them from
     98        // the original division.
     99        Node* newDivision = m_insertionSet.insertNode(m_indexInBlock, SpecBytecodeDouble, *node);
     100        newDivision->setResult(NodeResultDouble);
     101
     102        node->setOp(DoubleAsInt32);
     103        node->children.initialize(Edge(newDivision, DoubleRepUse), Edge(), Edge());
     104        if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
     105            node->setArithMode(Arith::CheckOverflow);
     106        else
     107            node->setArithMode(Arith::CheckOverflowAndNegativeZero);
     108
     109    }
     110
     111    void fixupArithDiv(Node* node, Edge& leftChild, Edge& rightChild)
     112    {
     113        if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) {
     114            fixupArithDivInt32(node, leftChild, rightChild);
    108115            return;
    109116        }
     
    475482                fixEdge<BigIntUse>(node->child1());
    476483                fixEdge<BigIntUse>(node->child2());
     484                node->clearFlags(NodeMustGenerate);
    477485                break;
    478486            }
     
    509517        }
    510518
     519        case ValueMod:
    511520        case ValueDiv: {
    512521            Edge& leftChild = node->child1();
     
    516525                fixEdge<BigIntUse>(leftChild);
    517526                fixEdge<BigIntUse>(rightChild);
     527                node->clearFlags(NodeMustGenerate);
    518528                break;
    519529            }
     
    524534                break;
    525535            }
    526             node->setOp(ArithDiv);
     536
     537            if (op == ValueDiv)
     538                node->setOp(ArithDiv);
     539            else
     540                node->setOp(ArithMod);
     541
    527542            node->setResult(NodeResultNumber);
    528543            fixupArithDiv(node, leftChild, rightChild);
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r244324 r245063  
    180180    macro(ValueMul, NodeResultJS | NodeMustGenerate) \
    181181    macro(ValueDiv, NodeResultJS | NodeMustGenerate) \
     182    macro(ValueMod, NodeResultJS | NodeMustGenerate) \
    182183    \
    183184    /* Add of values that always convers its inputs to strings. May have two or three kids. */\
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r245017 r245063  
    214214}
    215215
     216template<typename BigIntOperation, typename NumberOperation>
     217static ALWAYS_INLINE EncodedJSValue binaryOp(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BigIntOperation&& bigIntOp, NumberOperation&& numberOp, const char* errorMessage)
     218{
     219    VM* vm = &exec->vm();
     220    NativeCallFrameTracer tracer(vm, exec);
     221    auto scope = DECLARE_THROW_SCOPE(*vm);
     222
     223    JSValue op1 = JSValue::decode(encodedOp1);
     224    JSValue op2 = JSValue::decode(encodedOp2);
     225
     226    auto leftNumeric = op1.toNumeric(exec);
     227    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     228    auto rightNumeric = op2.toNumeric(exec);
     229    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     230
     231    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
     232        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
     233            RELEASE_AND_RETURN(scope, JSValue::encode(bigIntOp(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric))));
     234
     235        return throwVMTypeError(exec, scope, errorMessage);
     236    }
     237
     238    scope.release();
     239
     240    return JSValue::encode(jsNumber(numberOp(WTF::get<double>(leftNumeric), WTF::get<double>(rightNumeric))));
     241}
     242
    216243template<typename BigIntOperation, typename Int32Operation>
    217244static ALWAYS_INLINE EncodedJSValue bitwiseBinaryOp(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BigIntOperation&& bigIntOp, Int32Operation&& int32Op, const char* errorMessage)
     
    381408}
    382409
     410EncodedJSValue JIT_OPERATION operationValueMod(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
     411{
     412    auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
     413        return JSBigInt::remainder(exec, left, right);
     414    };
     415
     416    auto numberOp = [] (double left, double right) -> double {
     417        return jsMod(left, right);
     418    };
     419
     420    return binaryOp(exec, encodedOp1, encodedOp2, bigIntOp, numberOp, "Invalid mix of BigInt and other type in remainder operation.");
     421}
     422
    383423EncodedJSValue JIT_OPERATION operationValueBitNot(ExecState* exec, EncodedJSValue encodedOp1)
    384424{
     
    498538EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    499539{
    500     VM* vm = &exec->vm();
    501     NativeCallFrameTracer tracer(vm, exec);
    502     auto scope = DECLARE_THROW_SCOPE(*vm);
    503 
    504     JSValue op1 = JSValue::decode(encodedOp1);
    505     JSValue op2 = JSValue::decode(encodedOp2);
    506 
    507     auto leftNumeric = op1.toNumeric(exec);
    508     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    509     auto rightNumeric = op2.toNumeric(exec);
    510     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    511 
    512     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
    513         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
    514             JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
    515             RETURN_IF_EXCEPTION(scope, encodedJSValue());
    516             return JSValue::encode(result);
    517         }
    518 
    519         return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in division operation.");
    520     }
    521 
    522     scope.release();
    523 
    524     double a = WTF::get<double>(leftNumeric);
    525     double b = WTF::get<double>(rightNumeric);
    526     return JSValue::encode(jsNumber(a / b));
     540    auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
     541        return JSBigInt::divide(exec, left, right);
     542    };
     543
     544    auto numberOp = [] (double left, double right) -> double {
     545        return left / right;
     546    };
     547
     548    return binaryOp(exec, encodedOp1, encodedOp2, bigIntOp, numberOp, "Invalid mix of BigInt and other type in division operation.");
    527549}
    528550
     
    13531375}
    13541376   
     1377JSCell* JIT_OPERATION operationModBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
     1378{
     1379    VM* vm = &exec->vm();
     1380    NativeCallFrameTracer tracer(vm, exec);
     1381   
     1382    JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     1383    JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
     1384   
     1385    return JSBigInt::remainder(exec, leftOperand, rightOperand);
     1386}
     1387
    13551388JSCell* JIT_OPERATION operationDivBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
    13561389{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r244067 r245063  
    5151EncodedJSValue JIT_OPERATION operationToThis(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
    5252EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
     53EncodedJSValue JIT_OPERATION operationValueMod(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
    5354EncodedJSValue JIT_OPERATION operationValueBitNot(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
    5455EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
     
    169170JSCell* JIT_OPERATION operationSubBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
    170171JSCell* JIT_OPERATION operationMulBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
     172JSCell* JIT_OPERATION operationModBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
    171173JSCell* JIT_OPERATION operationDivBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
    172174JSCell* JIT_OPERATION operationBitAndBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r244324 r245063  
    349349
    350350        case ValueDiv:
     351        case ValueMod:
    351352        case ArithDiv:
    352353        case ArithMod: {
     
    361362                    else
    362363                        changed |= mergePrediction(SpecBytecodeDouble);
    363                 } else if (op == ValueDiv && isBigIntSpeculation(left) && isBigIntSpeculation(right))
     364                } else if ((op == ValueDiv || op == ValueMod) && isBigIntSpeculation(left) && isBigIntSpeculation(right))
    364365                    changed |= mergePrediction(SpecBigInt);
    365366                else {
    366367                    changed |= mergePrediction(SpecInt32Only | SpecBytecodeDouble);
    367                     if (op == ValueDiv && (node->mayHaveBigIntResult()
     368                    if ((op == ValueDiv || op == ValueMod) && (node->mayHaveBigIntResult()
    368369                        || (left & SpecBigInt)
    369370                        || (right & SpecBigInt)))
     
    602603        case ArithMod:
    603604        case ValueDiv:
     605        case ValueMod:
    604606        case ArithDiv: {
    605607            SpeculatedType left = node->child1()->prediction();
     
    11181120        case ValueMul:
    11191121        case ValueDiv:
     1122        case ValueMod:
    11201123        case ArithAdd:
    11211124        case ArithSub:
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r244324 r245063  
    239239    case ValueMul:
    240240    case ValueDiv:
     241    case ValueMod:
    241242    case TryGetById:
    242243    case DeleteById:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r244760 r245063  
    52205220    m_jit.exceptionCheck();
    52215221    doubleResult(result.fpr(), node);
     5222}
     5223
     5224void SpeculativeJIT::compileValueMod(Node* node)
     5225{
     5226    Edge& leftChild = node->child1();
     5227    Edge& rightChild = node->child2();
     5228
     5229    if (node->binaryUseKind() == BigIntUse) {
     5230        SpeculateCellOperand left(this, leftChild);
     5231        SpeculateCellOperand right(this, rightChild);
     5232        GPRReg leftGPR = left.gpr();
     5233        GPRReg rightGPR = right.gpr();
     5234
     5235        speculateBigInt(leftChild, leftGPR);
     5236        speculateBigInt(rightChild, rightGPR);
     5237
     5238        flushRegisters();
     5239        GPRFlushedCallResult result(this);
     5240        GPRReg resultGPR = result.gpr();
     5241
     5242        callOperation(operationModBigInt, resultGPR, leftGPR, rightGPR);
     5243
     5244        m_jit.exceptionCheck();
     5245        cellResult(resultGPR, node);
     5246        return;
     5247    }
     5248
     5249    DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse, node->binaryUseKind());
     5250    JSValueOperand op1(this, leftChild);
     5251    JSValueOperand op2(this, rightChild);
     5252    JSValueRegs op1Regs = op1.jsValueRegs();
     5253    JSValueRegs op2Regs = op2.jsValueRegs();
     5254    flushRegisters();
     5255    JSValueRegsFlushedCallResult result(this);
     5256    JSValueRegs resultRegs = result.regs();
     5257    callOperation(operationValueMod, resultRegs, op1Regs, op2Regs);
     5258    m_jit.exceptionCheck();
     5259    jsValueResult(resultRegs, node);
    52225260}
    52235261
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r242812 r245063  
    13571357    void compileArithDiv(Node*);
    13581358    void compileArithFRound(Node*);
     1359    void compileValueMod(Node*);
    13591360    void compileArithMod(Node*);
    13601361    void compileArithPow(Node*);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r244324 r245063  
    20852085    case ArithDiv: {
    20862086        compileArithDiv(node);
     2087        break;
     2088    }
     2089
     2090    case ValueMod: {
     2091        compileValueMod(node);
    20872092        break;
    20882093    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r244324 r245063  
    22312231    case ArithDiv: {
    22322232        compileArithDiv(node);
     2233        break;
     2234    }
     2235
     2236    case ValueMod: {
     2237        compileValueMod(node);
    22332238        break;
    22342239    }
  • trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp

    r244324 r245063  
    258258                case ValueMul:
    259259                case ValueDiv:
     260                case ValueMod:
    260261                case ArithAdd:
    261262                case ArithSub:
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r244811 r245063  
    9999    case ValueMul:
    100100    case ValueDiv:
     101    case ValueMod:
    101102    case StrCat:
    102103    case ArithAdd:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r245051 r245063  
    781781            compileArithDiv();
    782782            break;
     783        case ValueMod:
     784            compileValueMod();
     785            break;
    783786        case ArithMod:
    784787            compileArithMod();
     
    25472550    }
    25482551   
     2552    void compileValueMod()
     2553    {
     2554        if (m_node->binaryUseKind() == BigIntUse) {
     2555            LValue left = lowBigInt(m_node->child1());
     2556            LValue right = lowBigInt(m_node->child2());
     2557
     2558            LValue result = vmCall(pointerType(), m_out.operation(operationModBigInt), m_callFrame, left, right);
     2559            setJSValue(result);
     2560            return;
     2561        }
     2562
     2563        DFG_ASSERT(m_graph, m_node, m_node->binaryUseKind() == UntypedUse, m_node->binaryUseKind());
     2564        LValue left = lowJSValue(m_node->child1());
     2565        LValue right = lowJSValue(m_node->child2());
     2566        LValue result = vmCall(Int64, m_out.operation(operationValueMod), m_callFrame, left, right);
     2567        setJSValue(result);
     2568    }
     2569
    25492570    void compileArithMod()
    25502571    {
Note: See TracChangeset for help on using the changeset viewer.