Changeset 242715 in webkit


Ignore:
Timestamp:
Mar 11, 2019 10:21:41 AM (5 years ago)
Author:
Caio Lima
Message:

[ESNext][BigInt] Implement "~" unary operation
https://bugs.webkit.org/show_bug.cgi?id=182216

Reviewed by Keith Miller.

JSTests:

  • stress/big-int-bit-not-general.js: Added.
  • stress/big-int-bitwise-not-jit.js: Added.
  • stress/big-int-bitwise-not-wrapped-value.js: Added.
  • stress/bit-op-with-object-returning-int32.js:
  • stress/bitwise-not-fixup-rules.js: Added.
  • stress/value-bit-not-ai-rule.js: Added.

PerformanceTests:

  • BigIntBench/big-int-simple-bit-not.js: Added.

Source/JavaScriptCore:

This patch is adding support of BigInt into op_bitnot operations. In
addition, we are changing ArithBitNot to handle only Number operands,
while introducing a new node named ValueBitNot to handle Untyped and
BigInt. This node follows the same approach we are doing into other
arithimetic operations into DFG.

  • dfg/DFGAbstractInterpreterInlines.h:

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

It is possible that fixup and prediction propagation don't convert a
ValueBitNot(ConstInt32) into ArithBitNot(ConstInt32) because these
analysis are conservative. In such case, we are adding constant
folding rules to ValueBitNot AI.

  • dfg/DFGBackwardsPropagationPhase.cpp:

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

ValueBitNot has same rules as ArithBitNot on backwards propagation.

  • dfg/DFGByteCodeParser.cpp:

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

We can emit ArithBitNot if we know that operand of op_bitnot is a
Number or any int. Otherwise we fallback to ValueBitNot and rely on
fixup to convert the node to ArithBitNot when it is possible.
ValueBitNot uses heap prediction on prediction propagation and we
collect its type from op_bitnot's value profiler.

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

When we have the case with ValueBitNot(BigInt), we don't clobberize
world.

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

ValueBitNot can GC on BigIntUse because, right now, all bitNot
operation allocates temporary BigInts to perform calculations and it
can potentially trigger GC.

  • dfg/DFGFixupPhase.cpp:

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

ValueBitNot is responsible do handle BigIntUse and UntypedUse. To all
other uses, we fallback to ArithBitNot.

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):

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

(JSC::DFG::bitwiseBinaryOp):

This template function is abstracting the new semantics of numeric
values operations on bitwise operations. These operations usually
folow these steps:

  1. rhsNumeric = GetInt32OrBigInt(rhs)
  2. lhsNumeric = GetInt32OrBigInt(lhs)
  3. trhow error if TypeOf(rhsNumeric) != TypeOf(lhsNumeric)
  4. return BigInt::bitwiseOp(bitOp, rhs, lhs) if TypeOf(lhsNumeric) == BigInt
  5. return rhs <int32BitOp> lhs

Since we have almost the same code for every bitwise op,
we use such template to avoid code duplication. The template receives
Int32 and BigInt operations as parameter. Error message is received as
const char* instead of String& to avoid String allocation even when
there is no error to throw.

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

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileValueBitNot):

ValueBitNot generates speculative code for BigIntUse and this code is a
call to operationBitNotBigInt. This operation is faster than
operationValueBitNot because there is no need to check types of
operands and execute properly operation. We still need to check
exceptions after operationBitNotBigInt because it can throw OOM.

(JSC::DFG::SpeculativeJIT::compileBitwiseNot):

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

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitNot):
(JSC::FTL::DFG::LowerDFGToB3::compileArithBitNot):

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/JSBigInt.cpp:

(JSC::JSBigInt::bitwiseNot):

  • runtime/JSBigInt.h:
Location:
trunk
Files:
6 added
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r242699 r242715  
     12019-03-11  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [ESNext][BigInt] Implement "~" unary operation
     4        https://bugs.webkit.org/show_bug.cgi?id=182216
     5
     6        Reviewed by Keith Miller.
     7
     8        * stress/big-int-bit-not-general.js: Added.
     9        * stress/big-int-bitwise-not-jit.js: Added.
     10        * stress/big-int-bitwise-not-wrapped-value.js: Added.
     11        * stress/bit-op-with-object-returning-int32.js:
     12        * stress/bitwise-not-fixup-rules.js: Added.
     13        * stress/value-bit-not-ai-rule.js: Added.
     14
    1152019-03-10  Ross Kirsling  <ross.kirsling@sony.com>
    216
  • trunk/JSTests/stress/bit-op-with-object-returning-int32.js

    r239982 r242715  
    3737assert(numberOfDFGCompiles(bitXor) <= 1, true);
    3838
     39function bitNot(a) {
     40    return ~a;
     41}
     42noInline(bitNot);
     43
     44for (var i = 0; i < 10000; i++)
     45    assert(bitNot(o), -14);
     46
     47assert(numberOfDFGCompiles(bitNot) <= 1, true);
     48
  • trunk/PerformanceTests/ChangeLog

    r242373 r242715  
     12019-03-11  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [ESNext][BigInt] Implement "~" unary operation
     4        https://bugs.webkit.org/show_bug.cgi?id=182216
     5
     6        Reviewed by Keith Miller.
     7
     8        * BigIntBench/big-int-simple-bit-not.js: Added.
     9
    1102019-03-04  Saam Barati  <sbarati@apple.com>
    211
  • trunk/Source/JavaScriptCore/ChangeLog

    r242713 r242715  
     12019-03-11  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [ESNext][BigInt] Implement "~" unary operation
     4        https://bugs.webkit.org/show_bug.cgi?id=182216
     5
     6        Reviewed by Keith Miller.
     7
     8        This patch is adding support of BigInt into op_bitnot operations. In
     9        addition, we are changing ArithBitNot to handle only Number operands,
     10        while introducing a new node named ValueBitNot to handle Untyped and
     11        BigInt. This node follows the same approach we are doing into other
     12        arithimetic operations into DFG.
     13
     14        * dfg/DFGAbstractInterpreterInlines.h:
     15        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     16
     17        It is possible that fixup and prediction propagation don't convert a
     18        ValueBitNot(ConstInt32) into ArithBitNot(ConstInt32) because these
     19        analysis are conservative. In such case, we are adding constant
     20        folding rules to ValueBitNot AI.
     21
     22        * dfg/DFGBackwardsPropagationPhase.cpp:
     23        (JSC::DFG::BackwardsPropagationPhase::propagate):
     24
     25        ValueBitNot has same rules as ArithBitNot on backwards propagation.
     26
     27        * dfg/DFGByteCodeParser.cpp:
     28        (JSC::DFG::ByteCodeParser::parseBlock):
     29
     30        We can emit ArithBitNot if we know that operand of op_bitnot is a
     31        Number or any int. Otherwise we fallback to ValueBitNot and rely on
     32        fixup to convert the node to ArithBitNot when it is possible.
     33        ValueBitNot uses heap prediction on prediction propagation and we
     34        collect its type from op_bitnot's value profiler.
     35
     36        * dfg/DFGClobberize.h:
     37        (JSC::DFG::clobberize):
     38
     39        When we have the case with ValueBitNot(BigInt), we don't clobberize
     40        world.
     41
     42        * dfg/DFGDoesGC.cpp:
     43        (JSC::DFG::doesGC):
     44
     45        ValueBitNot can GC on BigIntUse because, right now, all bitNot
     46        operation allocates temporary BigInts to perform calculations and it
     47        can potentially trigger GC.
     48
     49        * dfg/DFGFixupPhase.cpp:
     50        (JSC::DFG::FixupPhase::fixupNode):
     51
     52        ValueBitNot is responsible do handle BigIntUse and UntypedUse. To all
     53        other uses, we fallback to ArithBitNot.
     54
     55        * dfg/DFGNode.h:
     56        (JSC::DFG::Node::hasHeapPrediction):
     57        * dfg/DFGNodeType.h:
     58        * dfg/DFGOperations.cpp:
     59        (JSC::DFG::bitwiseBinaryOp):
     60
     61        This template function is abstracting the new semantics of numeric
     62        values operations on bitwise operations. These operations usually
     63        folow these steps:
     64
     65            1. rhsNumeric = GetInt32OrBigInt(rhs)
     66            2. lhsNumeric = GetInt32OrBigInt(lhs)
     67            3. trhow error if TypeOf(rhsNumeric) != TypeOf(lhsNumeric)
     68            4. return BigInt::bitwiseOp(bitOp, rhs, lhs) if TypeOf(lhsNumeric) == BigInt
     69            5. return rhs <int32BitOp> lhs
     70
     71        Since we have almost the same code for every bitwise op,
     72        we use such template to avoid code duplication. The template receives
     73        Int32 and BigInt operations as parameter. Error message is received as
     74        `const char*` instead of `String&` to avoid String allocation even when
     75        there is no error to throw.
     76
     77        * dfg/DFGOperations.h:
     78        * dfg/DFGPredictionPropagationPhase.cpp:
     79        * dfg/DFGSafeToExecute.h:
     80        (JSC::DFG::safeToExecute):
     81        * dfg/DFGSpeculativeJIT.cpp:
     82        (JSC::DFG::SpeculativeJIT::compileValueBitNot):
     83
     84        ValueBitNot generates speculative code for BigIntUse and this code is a
     85        call to `operationBitNotBigInt`. This operation is faster than
     86        `operationValueBitNot` because there is no need to check types of
     87        operands and execute properly operation. We still need to check
     88        exceptions after `operationBitNotBigInt` because it can throw OOM.
     89
     90        (JSC::DFG::SpeculativeJIT::compileBitwiseNot):
     91        * dfg/DFGSpeculativeJIT.h:
     92        * dfg/DFGSpeculativeJIT32_64.cpp:
     93        (JSC::DFG::SpeculativeJIT::compile):
     94        * dfg/DFGSpeculativeJIT64.cpp:
     95        (JSC::DFG::SpeculativeJIT::compile):
     96        * ftl/FTLCapabilities.cpp:
     97        (JSC::FTL::canCompile):
     98        * ftl/FTLLowerDFGToB3.cpp:
     99        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     100        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitNot):
     101        (JSC::FTL::DFG::LowerDFGToB3::compileArithBitNot):
     102        * runtime/CommonSlowPaths.cpp:
     103        (JSC::SLOW_PATH_DECL):
     104        * runtime/JSBigInt.cpp:
     105        (JSC::JSBigInt::bitwiseNot):
     106        * runtime/JSBigInt.h:
     107
    11082019-03-11  Darin Adler  <darin@apple.com>
    2109
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r242655 r242715  
    377377    }
    378378
     379    case ValueBitNot: {
     380        JSValue operand = forNode(node->child1()).value();
     381        if (operand && operand.isInt32()) {
     382            didFoldClobberWorld();
     383            int32_t a = operand.asInt32();
     384            setConstant(node, JSValue(~a));
     385            break;
     386        }
     387
     388        if (node->child1().useKind() == BigIntUse)
     389            setTypeForNode(node, SpecBigInt);
     390        else {
     391            clobberWorld();
     392            setTypeForNode(node, SpecBoolInt32 | SpecBigInt);
     393        }
     394
     395        break;
     396    }
     397
    379398    case ArithBitNot: {
    380         if (node->child1().useKind() == UntypedUse) {
    381             clobberWorld();
    382             setNonCellTypeForNode(node, SpecInt32Only);
    383             break;
    384         }
    385 
    386399        JSValue operand = forNode(node->child1()).value();
    387400        if (operand && operand.isInt32()) {
  • trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp

    r240269 r242715  
    211211            break;
    212212           
     213        case ValueBitNot:
    213214        case ArithBitNot: {
    214215            flags |= NodeBytecodeUsesAsInt;
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r242015 r242715  
    49194919        case op_bitnot: {
    49204920            auto bytecode = currentInstruction->as<OpBitnot>();
     4921            SpeculatedType prediction = getPrediction();
    49214922            Node* op1 = get(bytecode.m_operand);
    4922             set(bytecode.m_dst, addToGraph(ArithBitNot, op1));
     4923            if (op1->hasNumberOrAnyIntResult())
     4924                set(bytecode.m_dst, addToGraph(ArithBitNot, op1));
     4925            else
     4926                set(bytecode.m_dst, addToGraph(ValueBitNot, OpInfo(), OpInfo(prediction), op1));
    49234927            NEXT_OPCODE(op_bitnot);
    49244928        }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r241228 r242715  
    260260        return;
    261261
     262    case ValueBitNot:
     263        if (node->child1().useKind() == BigIntUse) {
     264            def(PureValue(node));
     265            return;
     266        }
     267        read(World);
     268        write(Heap);
     269        return;
     270
    262271    case ArithBitNot:
    263272        if (node->child1().useKind() == UntypedUse) {
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r241772 r242715  
    379379    case ValueMul:
    380380    case ValueDiv:
     381    case ValueBitNot:
    381382    case ValueNegate:
    382383#else
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r241228 r242715  
    235235        }
    236236
     237        case ValueBitNot: {
     238            Edge& operandEdge = node->child1();
     239
     240            if (operandEdge.node()->shouldSpeculateBigInt()) {
     241                node->clearFlags(NodeMustGenerate);
     242                fixEdge<BigIntUse>(operandEdge);
     243            } else if (operandEdge.node()->shouldSpeculateUntypedForBitOps())
     244                fixEdge<UntypedUse>(operandEdge);
     245            else {
     246                node->setOp(ArithBitNot);
     247                node->setResult(NodeResultInt32);
     248                node->clearFlags(NodeMustGenerate);
     249                fixIntConvertingEdge(operandEdge);
     250            }
     251            break;
     252        }
     253
    237254        case ArithBitNot: {
    238             if (node->child1().node()->shouldSpeculateUntypedForBitOps()) {
    239                 fixEdge<UntypedUse>(node->child1());
    240                 break;
    241             }
    242 
    243             fixIntConvertingEdge(node->child1());
    244             node->clearFlags(NodeMustGenerate);
     255            Edge& operandEdge = node->child1();
     256
     257            fixIntConvertingEdge(operandEdge);
    245258            break;
    246259        }
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r240938 r242715  
    16941694        case ValueBitOr:
    16951695        case ValueBitXor:
     1696        case ValueBitNot:
    16961697        case CallObjectConstructor:
    16971698        case LoadKeyFromMapBucket:
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r241228 r242715  
    112112    \
    113113    /* Nodes for bitwise operations. */\
    114     macro(ArithBitNot, NodeResultInt32 | NodeMustGenerate) \
     114    macro(ValueBitNot, NodeResultJS | NodeMustGenerate) \
     115    macro(ArithBitNot, NodeResultInt32) \
    115116    macro(ValueBitAnd, NodeResultJS | NodeMustGenerate) \
    116117    macro(ArithBitAnd, NodeResultInt32) \
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r242500 r242715  
    214214}
    215215
     216template<typename BigIntOperation, typename Int32Operation>
     217static ALWAYS_INLINE EncodedJSValue bitwiseBinaryOp(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BigIntOperation&& bigIntOp, Int32Operation&& int32Op, 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.toBigIntOrInt32(exec);
     227    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     228    auto rightNumeric = op2.toBigIntOrInt32(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(int32Op(WTF::get<int32_t>(leftNumeric), WTF::get<int32_t>(rightNumeric))));
     241}
     242
    216243static ALWAYS_INLINE EncodedJSValue parseIntResult(double input)
    217244{
     
    362389    JSValue op1 = JSValue::decode(encodedOp1);
    363390
    364     int32_t operandValue = op1.toInt32(exec);
     391    auto operandNumeric = op1.toBigIntOrInt32(exec);
    365392    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    366393
    367     return JSValue::encode(jsNumber(~operandValue));
     394    if (WTF::holds_alternative<JSBigInt*>(operandNumeric))
     395        RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::bitwiseNot(exec, WTF::get<JSBigInt*>(operandNumeric))));
     396
     397    return JSValue::encode(jsNumber(~WTF::get<int32_t>(operandNumeric)));
    368398}
    369399
    370400EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    371401{
    372     VM* vm = &exec->vm();
    373     NativeCallFrameTracer tracer(vm, exec);
    374     auto scope = DECLARE_THROW_SCOPE(*vm);
    375 
    376     JSValue op1 = JSValue::decode(encodedOp1);
    377     JSValue op2 = JSValue::decode(encodedOp2);
    378 
    379     auto leftNumeric = op1.toBigIntOrInt32(exec);
    380     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    381     auto rightNumeric = op2.toBigIntOrInt32(exec);
    382     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    383 
    384     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
    385         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
    386             JSBigInt* result = JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
    387             RETURN_IF_EXCEPTION(scope, encodedJSValue());
    388             return JSValue::encode(result);
    389         }
    390 
    391         return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'and' operation.");
    392     }
    393 
    394     return JSValue::encode(jsNumber(WTF::get<int32_t>(leftNumeric) & WTF::get<int32_t>(rightNumeric)));
     402    auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
     403        return JSBigInt::bitwiseAnd(exec, left, right);
     404    };
     405
     406    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
     407        return left & right;
     408    };
     409
     410    return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'and' operation."_s);
    395411}
    396412
    397413EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    398414{
    399     VM* vm = &exec->vm();
    400     NativeCallFrameTracer tracer(vm, exec);
    401     auto scope = DECLARE_THROW_SCOPE(*vm);
    402 
    403     JSValue op1 = JSValue::decode(encodedOp1);
    404     JSValue op2 = JSValue::decode(encodedOp2);
    405 
    406     auto leftNumeric = op1.toBigIntOrInt32(exec);
    407     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    408     auto rightNumeric = op2.toBigIntOrInt32(exec);
    409     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    410 
    411     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
    412         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
    413             JSBigInt* result = JSBigInt::bitwiseOr(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
    414             RETURN_IF_EXCEPTION(scope, encodedJSValue());
    415             return JSValue::encode(result);
    416         }
    417 
    418         return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'or' operation.");
    419     }
    420 
    421     return JSValue::encode(jsNumber(WTF::get<int32_t>(leftNumeric) | WTF::get<int32_t>(rightNumeric)));
     415    auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
     416        return JSBigInt::bitwiseOr(exec, left, right);
     417    };
     418
     419    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
     420        return left | right;
     421    };
     422
     423    return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'or' operation."_s);
    422424}
    423425
    424426EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    425427{
    426     VM* vm = &exec->vm();
    427     NativeCallFrameTracer tracer(vm, exec);
    428     auto scope = DECLARE_THROW_SCOPE(*vm);
    429 
    430     JSValue op1 = JSValue::decode(encodedOp1);
    431     JSValue op2 = JSValue::decode(encodedOp2);
    432 
    433     auto leftNumeric = op1.toBigIntOrInt32(exec);
    434     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    435     auto rightNumeric = op2.toBigIntOrInt32(exec);
    436     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    437 
    438     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
    439         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
    440             JSBigInt* result = JSBigInt::bitwiseXor(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
    441             RETURN_IF_EXCEPTION(scope, encodedJSValue());
    442             return JSValue::encode(result);
    443         }
    444 
    445         return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'xor' operation.");
    446     }
    447 
    448     return JSValue::encode(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric)));
     428    auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
     429        return JSBigInt::bitwiseXor(exec, left, right);
     430    };
     431
     432    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
     433        return left ^ right;
     434    };
     435
     436    return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'xor' operation."_s);
    449437}
    450438
     
    13371325   
    13381326    return JSBigInt::sub(exec, leftOperand, rightOperand);
     1327}
     1328
     1329JSCell* JIT_OPERATION operationBitNotBigInt(ExecState* exec, JSCell* op1)
     1330{
     1331    VM* vm = &exec->vm();
     1332    NativeCallFrameTracer tracer(vm, exec);
     1333
     1334    JSBigInt* operand = jsCast<JSBigInt*>(op1);
     1335
     1336    return JSBigInt::bitwiseNot(exec, operand);
    13391337}
    13401338
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r242252 r242715  
    171171JSCell* JIT_OPERATION operationDivBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
    172172JSCell* JIT_OPERATION operationBitAndBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
     173JSCell* JIT_OPERATION operationBitNotBigInt(ExecState*, JSCell* op1) WTF_INTERNAL;
    173174JSCell* JIT_OPERATION operationBitOrBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
    174175JSCell* JIT_OPERATION operationAddBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r240327 r242715  
    803803        case ValueBitXor:
    804804        case ValueBitOr:
     805        case ValueBitNot:
    805806        case CallObjectConstructor:
    806807        case GetArgument:
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r240327 r242715  
    232232    case ValueBitXor:
    233233    case ValueBitOr:
     234    case ValueBitNot:
    234235    case ValueNegate:
    235236    case ValueAdd:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r242626 r242715  
    35233523}
    35243524
     3525void SpeculativeJIT::compileValueBitNot(Node* node)
     3526{
     3527    Edge& child1 = node->child1();
     3528
     3529    if (child1.useKind() == BigIntUse) {
     3530        SpeculateCellOperand operand(this, child1);
     3531        GPRReg operandGPR = operand.gpr();
     3532
     3533        speculateBigInt(child1, operandGPR);
     3534
     3535        flushRegisters();
     3536        GPRFlushedCallResult result(this);
     3537        GPRReg resultGPR = result.gpr();
     3538
     3539        callOperation(operationBitNotBigInt, resultGPR, operandGPR);
     3540        m_jit.exceptionCheck();
     3541        cellResult(resultGPR, node);
     3542
     3543        return;
     3544    }
     3545
     3546    JSValueOperand operand(this, child1);
     3547    JSValueRegs operandRegs = operand.jsValueRegs();
     3548
     3549    flushRegisters();
     3550    JSValueRegsFlushedCallResult result(this);
     3551    JSValueRegs resultRegs = result.regs();
     3552    callOperation(operationValueBitNot, resultRegs, operandRegs);
     3553    m_jit.exceptionCheck();
     3554
     3555    jsValueResult(resultRegs, node);
     3556}
     3557
    35253558void SpeculativeJIT::compileBitwiseNot(Node* node)
    35263559{
    35273560    Edge& child1 = node->child1();
    3528 
    3529     if (child1.useKind() == UntypedUse) {
    3530         JSValueOperand operand(this, child1);
    3531         JSValueRegs operandRegs = operand.jsValueRegs();
    3532 
    3533         flushRegisters();
    3534         JSValueRegsFlushedCallResult result(this);
    3535         JSValueRegs resultRegs = result.regs();
    3536         callOperation(operationValueBitNot, resultRegs, operandRegs);
    3537         m_jit.exceptionCheck();
    3538 
    3539         jsValueResult(resultRegs, node);
    3540         return;
    3541     }
    35423561
    35433562    SpeculateInt32Operand operand(this, child1);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r242397 r242715  
    13261326    void compileDoubleAsInt32(Node*);
    13271327
     1328    void compileValueBitNot(Node*);
    13281329    void compileBitwiseNot(Node*);
    13291330
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r242286 r242715  
    19901990    case ArithBitXor:
    19911991        compileBitwiseOp(node);
     1992        break;
     1993
     1994    case ValueBitNot:
     1995        compileValueBitNot(node);
    19921996        break;
    19931997
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r242286 r242715  
    20792079        // the argument is not used.
    20802080        recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
     2081        break;
     2082
     2083    case ValueBitNot:
     2084        compileValueBitNot(node);
    20812085        break;
    20822086
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r241222 r242715  
    9292    case ValueBitXor:
    9393    case ValueBitOr:
     94    case ValueBitNot:
    9495    case ValueNegate:
    9596    case ValueAdd:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r242626 r242715  
    666666            compileArithUnary();
    667667            break;
     668        case ValueBitNot:
     669            compileValueBitNot();
     670            break;
    668671        case ArithBitNot:
    669672            compileArithBitNot();
     
    28912894    }
    28922895   
     2896    void compileValueBitNot()
     2897    {
     2898        if (m_node->child1().useKind() == BigIntUse) {
     2899            LValue operand = lowBigInt(m_node->child1());
     2900            LValue result = vmCall(pointerType(), m_out.operation(operationBitNotBigInt), m_callFrame, operand);
     2901            setJSValue(result);
     2902            return;
     2903        }
     2904
     2905        LValue operand = lowJSValue(m_node->child1());
     2906        LValue result = vmCall(Int64, m_out.operation(operationValueBitNot), m_callFrame, operand);
     2907        setJSValue(result);
     2908    }
     2909
    28932910    void compileArithBitNot()
    28942911    {
    2895         if (m_node->child1().useKind() == UntypedUse) {
    2896             LValue operand = lowJSValue(m_node->child1());
    2897             LValue result = vmCall(Int64, m_out.operation(operationValueBitNot), m_callFrame, operand);
    2898             setJSValue(result);
    2899             return;
    2900         }
    2901 
    29022912        setInt32(m_out.bitNot(lowInt32(m_node->child1())));
    29032913    }
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r242500 r242715  
    716716    BEGIN();
    717717    auto bytecode = pc->as<OpBitnot>();
    718     int32_t operand = GET_C(bytecode.m_operand).jsValue().toInt32(exec);
    719     CHECK_EXCEPTION();
    720     RETURN_PROFILED(jsNumber(~operand));
     718    auto operandNumeric = GET_C(bytecode.m_operand).jsValue().toBigIntOrInt32(exec);
     719    CHECK_EXCEPTION();
     720
     721    if (WTF::holds_alternative<JSBigInt*>(operandNumeric)) {
     722        JSBigInt* result = JSBigInt::bitwiseNot(exec, WTF::get<JSBigInt*>(operandNumeric));
     723        CHECK_EXCEPTION();
     724        RETURN_PROFILED(result);
     725    }
     726
     727    RETURN_PROFILED(jsNumber(~WTF::get<int32_t>(operandNumeric)));
    721728}
    722729
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp

    r240255 r242715  
    526526}
    527527
     528JSBigInt* JSBigInt::bitwiseNot(ExecState* exec, JSBigInt* x)
     529{
     530    if (x->sign()) {
     531        // ~(-x) == ~(~(x-1)) == x-1
     532        return absoluteSubOne(exec, x, x->length());
     533    }
     534    // ~x == -x-1 == -(x+1)
     535    return absoluteAddOne(exec, x, SignOption::Signed);
     536}
     537
    528538#if USE(JSVALUE32_64)
    529539#define HAVE_TWO_DIGIT 1
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.h

    r242109 r242715  
    125125    static JSBigInt* bitwiseOr(ExecState*, JSBigInt* x, JSBigInt* y);
    126126    static JSBigInt* bitwiseXor(ExecState*, JSBigInt* x, JSBigInt* y);
     127    static JSBigInt* bitwiseNot(ExecState*, JSBigInt* x);
    127128
    128129    static JSBigInt* leftShift(ExecState*, JSBigInt* x, JSBigInt* y);
Note: See TracChangeset for help on using the changeset viewer.