Changeset 231131 in webkit


Ignore:
Timestamp:
Apr 27, 2018 11:11:57 PM (6 years ago)
Author:
Caio Lima
Message:

[ESNext][BigInt] Implement support for "*" operation
https://bugs.webkit.org/show_bug.cgi?id=183721

Reviewed by Saam Barati.

JSTests:

  • bigIntTests.yaml:
  • stress/big-int-mul-jit.js: Added.
  • stress/big-int-mul-to-primitive-precedence.js: Added.
  • stress/big-int-mul-to-primitive.js: Added.
  • stress/big-int-mul-type-error.js: Added.
  • stress/big-int-mul-wrapped-value.js: Added.
  • stress/big-int-multiplication.js: Added.
  • stress/big-int-multiply-memory-stress.js: Added.

Source/JavaScriptCore:

Added BigInt support into times binary operator into LLInt and on
JITOperations profiledMul and unprofiledMul. We are also replacing all
uses of int to unsigned when there is no negative values for
variables.

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):

  • jit/JITOperations.cpp:
  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/JSBigInt.cpp:

(JSC::JSBigInt::JSBigInt):
(JSC::JSBigInt::allocationSize):
(JSC::JSBigInt::createWithLength):
(JSC::JSBigInt::toString):
(JSC::JSBigInt::multiply):
(JSC::JSBigInt::digitDiv):
(JSC::JSBigInt::internalMultiplyAdd):
(JSC::JSBigInt::multiplyAccumulate):
(JSC::JSBigInt::equals):
(JSC::JSBigInt::absoluteDivSmall):
(JSC::JSBigInt::calculateMaximumCharactersRequired):
(JSC::JSBigInt::toStringGeneric):
(JSC::JSBigInt::rightTrim):
(JSC::JSBigInt::allocateFor):
(JSC::JSBigInt::parseInt):
(JSC::JSBigInt::digit):
(JSC::JSBigInt::setDigit):

  • runtime/JSBigInt.h:
  • runtime/Operations.h:

(JSC::jsMul):

Location:
trunk
Files:
7 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r231104 r231131  
     12018-04-27  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [ESNext][BigInt] Implement support for "*" operation
     4        https://bugs.webkit.org/show_bug.cgi?id=183721
     5
     6        Reviewed by Saam Barati.
     7
     8        * bigIntTests.yaml:
     9        * stress/big-int-mul-jit.js: Added.
     10        * stress/big-int-mul-to-primitive-precedence.js: Added.
     11        * stress/big-int-mul-to-primitive.js: Added.
     12        * stress/big-int-mul-type-error.js: Added.
     13        * stress/big-int-mul-wrapped-value.js: Added.
     14        * stress/big-int-multiplication.js: Added.
     15        * stress/big-int-multiply-memory-stress.js: Added.
     16
    1172018-04-27  Ryan Haddad  <ryanhaddad@apple.com>
    218
  • trunk/JSTests/bigIntTests.yaml

    r231104 r231131  
    9898  cmd: runBigIntEnabled
    9999
     100- path: stress/big-int-mul-jit.js
     101  cmd: runBigIntEnabled
     102
     103- path: stress/big-int-mul-to-primitive-precedence.js
     104  cmd: runBigIntEnabled
     105
     106- path: stress/big-int-mul-to-primitive.js
     107  cmd: runBigIntEnabled
     108
     109- path: stress/big-int-mul-type-error.js
     110  cmd: runBigIntEnabled
     111
     112- path: stress/big-int-mul-wrapped-value.js
     113  cmd: runBigIntEnabled
     114
     115- path: stress/big-int-multiplication.js
     116  cmd: runBigIntEnabled
     117
     118- path: stress/big-int-multiply-memory-stress.js
     119  cmd: runBigIntEnabled
     120
  • trunk/Source/JavaScriptCore/ChangeLog

    r231129 r231131  
     12018-04-27  Caio Lima  <ticaiolima@gmail.com>
     2
     3        [ESNext][BigInt] Implement support for "*" operation
     4        https://bugs.webkit.org/show_bug.cgi?id=183721
     5
     6        Reviewed by Saam Barati.
     7
     8        Added BigInt support into times binary operator into LLInt and on
     9        JITOperations profiledMul and unprofiledMul. We are also replacing all
     10        uses of int to unsigned when there is no negative values for
     11        variables.
     12
     13        * dfg/DFGConstantFoldingPhase.cpp:
     14        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     15        * jit/JITOperations.cpp:
     16        * runtime/CommonSlowPaths.cpp:
     17        (JSC::SLOW_PATH_DECL):
     18        * runtime/JSBigInt.cpp:
     19        (JSC::JSBigInt::JSBigInt):
     20        (JSC::JSBigInt::allocationSize):
     21        (JSC::JSBigInt::createWithLength):
     22        (JSC::JSBigInt::toString):
     23        (JSC::JSBigInt::multiply):
     24        (JSC::JSBigInt::digitDiv):
     25        (JSC::JSBigInt::internalMultiplyAdd):
     26        (JSC::JSBigInt::multiplyAccumulate):
     27        (JSC::JSBigInt::equals):
     28        (JSC::JSBigInt::absoluteDivSmall):
     29        (JSC::JSBigInt::calculateMaximumCharactersRequired):
     30        (JSC::JSBigInt::toStringGeneric):
     31        (JSC::JSBigInt::rightTrim):
     32        (JSC::JSBigInt::allocateFor):
     33        (JSC::JSBigInt::parseInt):
     34        (JSC::JSBigInt::digit):
     35        (JSC::JSBigInt::setDigit):
     36        * runtime/JSBigInt.h:
     37        * runtime/Operations.h:
     38        (JSC::jsMul):
     39
    1402018-04-27  JF Bastien  <jfbastien@apple.com>
    241
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r231104 r231131  
    147147
    148148                    // FIXME: Revisit this condition when introducing BigInt to JSC.
    149                     auto isNonStringCellConstant = [] (JSValue value) {
    150                         return value && value.isCell() && !value.isString();
     149                    auto isNonStringOrBigIntCellConstant = [] (JSValue value) {
     150                        return value && value.isCell() && !value.isString() && !value.isBigInt();
    151151                    };
    152152
    153                     if (isNonStringCellConstant(child1Constant)) {
     153                    if (isNonStringOrBigIntCellConstant(child1Constant)) {
    154154                        node->convertToCompareEqPtr(m_graph.freezeStrong(child1Constant.asCell()), node->child2());
    155155                        changed = true;
    156                     } else if (isNonStringCellConstant(child2Constant)) {
     156                    } else if (isNonStringOrBigIntCellConstant(child2Constant)) {
    157157                        node->convertToCompareEqPtr(m_graph.freezeStrong(child2Constant.asCell()), node->child1());
    158158                        changed = true;
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r231104 r231131  
    25552555}
    25562556
    2557 ALWAYS_INLINE static EncodedJSValue unprofiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    2558 {
    2559     auto scope = DECLARE_THROW_SCOPE(vm);
     2557ALWAYS_INLINE static EncodedJSValue unprofiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
     2558{
    25602559    JSValue op1 = JSValue::decode(encodedOp1);
    25612560    JSValue op2 = JSValue::decode(encodedOp2);
    25622561
    2563     double a = op1.toNumber(exec);
    2564     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    2565     scope.release();
    2566     double b = op2.toNumber(exec);
    2567     return JSValue::encode(jsNumber(a * b));
    2568 }
    2569 
    2570 ALWAYS_INLINE static EncodedJSValue profiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
    2571 {
    2572     auto scope = DECLARE_THROW_SCOPE(vm);
     2562    return JSValue::encode(jsMul(exec, op1, op2));
     2563}
     2564
     2565ALWAYS_INLINE static EncodedJSValue profiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
     2566{
    25732567    JSValue op1 = JSValue::decode(encodedOp1);
    25742568    JSValue op2 = JSValue::decode(encodedOp2);
     
    25772571        arithProfile.observeLHSAndRHS(op1, op2);
    25782572
    2579     double a = op1.toNumber(exec);
    2580     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    2581     double b = op2.toNumber(exec);
    2582     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    2583    
    2584     JSValue result = jsNumber(a * b);
     2573    JSValue result = jsMul(exec, op1, op2);
    25852574    arithProfile.observeResult(result);
    25862575    return JSValue::encode(result);
     
    25922581    NativeCallFrameTracer tracer(vm, exec);
    25932582
    2594     return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
     2583    return unprofiledMul(exec, encodedOp1, encodedOp2);
    25952584}
    25962585
     
    26002589    NativeCallFrameTracer tracer(vm, exec);
    26012590
    2602     return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
     2591    return unprofiledMul(exec, encodedOp1, encodedOp2);
    26032592}
    26042593
     
    26172606#endif
    26182607
    2619     return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
     2608    return unprofiledMul(exec, encodedOp1, encodedOp2);
    26202609}
    26212610
     
    26262615
    26272616    ASSERT(arithProfile);
    2628     return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile);
     2617    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile);
    26292618}
    26302619
     
    26442633#endif
    26452634
    2646     return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile, false);
     2635    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile, false);
    26472636}
    26482637
     
    26542643    ArithProfile* arithProfile = mulIC->arithProfile();
    26552644    ASSERT(arithProfile);
    2656     return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile);
     2645    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile);
    26572646}
    26582647
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r231104 r231131  
    487487    JSValue left = OP_C(2).jsValue();
    488488    JSValue right = OP_C(3).jsValue();
    489     double a = left.toNumber(exec);
    490     if (UNLIKELY(throwScope.exception()))
    491         RETURN(JSValue());
    492     double b = right.toNumber(exec);
     489    JSValue leftPrimitive = left.toPrimitive(exec, PreferNumber);
     490    CHECK_EXCEPTION();
     491    JSValue rightPrimitive = right.toPrimitive(exec, PreferNumber);
     492    CHECK_EXCEPTION();
     493   
     494    if (leftPrimitive.isBigInt() || rightPrimitive.isBigInt()) {
     495        if (leftPrimitive.isBigInt() && rightPrimitive.isBigInt()) {
     496            JSValue result(JSBigInt::multiply(exec, asBigInt(leftPrimitive), asBigInt(rightPrimitive)));
     497            RETURN_WITH_PROFILING(result, {
     498                updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
     499            });
     500        }
     501
     502        THROW(createTypeError(exec, "Invalid mix of BigInt and other type in multiplication."));
     503    }
     504
     505    double a = leftPrimitive.toNumber(exec);
     506    double b = rightPrimitive.toNumber(exec);
    493507    JSValue result = jsNumber(a * b);
    494508    RETURN_WITH_PROFILING(result, {
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp

    r231104 r231131  
    7070}
    7171
    72 JSBigInt::JSBigInt(VM& vm, Structure* structure, int length)
     72JSBigInt::JSBigInt(VM& vm, Structure* structure, unsigned length)
    7373    : Base(vm, structure)
    7474    , m_length(length)
     
    9494}
    9595
    96 size_t JSBigInt::allocationSize(int length)
     96size_t JSBigInt::allocationSize(unsigned length)
    9797{
    9898    size_t sizeWithPadding = WTF::roundUpToMultipleOf<sizeof(size_t)>(sizeof(JSBigInt));
     
    100100}
    101101
    102 JSBigInt* JSBigInt::createWithLength(VM& vm, int length)
     102JSBigInt* JSBigInt::createWithLength(VM& vm, unsigned length)
    103103{
    104104    JSBigInt* bigInt = new (NotNull, allocateCell<JSBigInt>(vm.heap, allocationSize(length))) JSBigInt(vm, vm.bigIntStructure.get(), length);
     
    224224}
    225225
    226 String JSBigInt::toString(ExecState& state, int radix)
     226String JSBigInt::toString(ExecState& state, unsigned radix)
    227227{
    228228    if (this->isZero())
     
    245245
    246246    internalMultiplyAdd(this, factor, summand, length(), this);
     247}
     248
     249JSBigInt* JSBigInt::multiply(ExecState* state, JSBigInt* x, JSBigInt* y)
     250{
     251    VM& vm = state->vm();
     252
     253    if (x->isZero())
     254        return x;
     255    if (y->isZero())
     256        return y;
     257
     258    unsigned resultLength = x->length() + y->length();
     259    JSBigInt* result = JSBigInt::createWithLength(vm, resultLength);
     260    result->initialize(InitializationType::WithZero);
     261
     262    for (unsigned i = 0; i < x->length(); i++)
     263        multiplyAccumulate(y, x->digit(i), result, i);
     264
     265    result->setSign(x->sign() != y->sign());
     266    return result->rightTrim(vm);
    247267}
    248268
     
    379399    // Adapted from Warren, Hacker's Delight, p. 152.
    380400#if USE(JSVALUE64)
    381     int s = clz64(divisor);
     401    unsigned s = clz64(divisor);
    382402#else
    383     int s = clz32(divisor);
     403    unsigned s = clz32(divisor);
    384404#endif
    385405    divisor <<= s;
     
    424444// Multiplies {source} with {factor} and adds {summand} to the result.
    425445// {result} and {source} may be the same BigInt for inplace modification.
    426 void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int n, JSBigInt* result)
     446void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned n, JSBigInt* result)
    427447{
    428448    ASSERT(source->length() >= n);
     
    431451    Digit carry = summand;
    432452    Digit high = 0;
    433     for (int i = 0; i < n; i++) {
     453    for (unsigned i = 0; i < n; i++) {
    434454        Digit current = source->digit(i);
    435455        Digit newCarry = 0;
     
    459479}
    460480
     481// Multiplies {multiplicand} with {multiplier} and adds the result to
     482// {accumulator}, starting at {accumulatorIndex} for the least-significant
     483// digit.
     484// Callers must ensure that {accumulator} is big enough to hold the result.
     485void JSBigInt::multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex)
     486{
     487    ASSERT(accumulator->length() > multiplicand->length() + accumulatorIndex);
     488    if (!multiplier)
     489        return;
     490   
     491    Digit carry = 0;
     492    Digit high = 0;
     493    for (unsigned i = 0; i < multiplicand->length(); i++, accumulatorIndex++) {
     494        Digit acc = accumulator->digit(accumulatorIndex);
     495        Digit newCarry = 0;
     496       
     497        // Add last round's carryovers.
     498        acc = digitAdd(acc, high, newCarry);
     499        acc = digitAdd(acc, carry, newCarry);
     500       
     501        // Compute this round's multiplication.
     502        Digit multiplicandDigit = multiplicand->digit(i);
     503        Digit low = digitMul(multiplier, multiplicandDigit, high);
     504        acc = digitAdd(acc, low, newCarry);
     505       
     506        // Store result and prepare for next round.
     507        accumulator->setDigit(accumulatorIndex, acc);
     508        carry = newCarry;
     509    }
     510   
     511    while (carry || high) {
     512        ASSERT(accumulatorIndex < accumulator->length());
     513        Digit acc = accumulator->digit(accumulatorIndex);
     514        Digit newCarry = 0;
     515        acc = digitAdd(acc, high, newCarry);
     516        high = 0;
     517        acc = digitAdd(acc, carry, newCarry);
     518        accumulator->setDigit(accumulatorIndex, acc);
     519        carry = newCarry;
     520        accumulatorIndex++;
     521    }
     522}
     523
    461524bool JSBigInt::equals(JSBigInt* x, JSBigInt* y)
    462525{
     
    467530        return false;
    468531
    469     for (int i = 0; i < x->length(); i++) {
     532    for (unsigned i = 0; i < x->length(); i++) {
    470533        if (x->digit(i) != y->digit(i))
    471534            return false;
     
    495558    }
    496559
    497     int length = x->length();
     560    unsigned length = x->length();
    498561    if (quotient != nullptr) {
    499562        if (*quotient == nullptr)
     
    522585};
    523586
    524 static const int bitsPerCharTableShift = 5;
     587static const unsigned bitsPerCharTableShift = 5;
    525588static const size_t bitsPerCharTableMultiplier = 1u << bitsPerCharTableShift;
    526589
    527590// Compute (an overapproximation of) the length of the resulting string:
    528591// Divide bit length of the BigInt by bits representable per character.
    529 uint64_t JSBigInt::calculateMaximumCharactersRequired(int length, int radix, Digit lastDigit, bool sign)
    530 {
    531     int leadingZeros;
     592uint64_t JSBigInt::calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign)
     593{
     594    unsigned leadingZeros;
    532595    if (sizeof(lastDigit) == 8)
    533596        leadingZeros = clz64(lastDigit);
     
    557620}
    558621
    559 String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, int radix)
     622String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, unsigned radix)
    560623{
    561624    // FIXME: [JSC] Revisit usage of StringVector into JSBigInt::toString
     
    566629    ASSERT(!x->isZero());
    567630
    568     int length = x->length();
     631    unsigned length = x->length();
    569632    bool sign = x->sign();
    570633
     
    582645        lastDigit = x->digit(0);
    583646    else {
    584         int chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar;
     647        unsigned chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar;
    585648        Digit chunkDivisor = digitPow(radix, chunkChars);
    586649
    587650        // By construction of chunkChars, there can't have been overflow.
    588651        ASSERT(chunkDivisor);
    589         int nonZeroDigit = length - 1;
     652        unsigned nonZeroDigit = length - 1;
    590653        ASSERT(x->digit(nonZeroDigit));
    591654
     
    603666
    604667            dividend = &rest;
    605             for (int i = 0; i < chunkChars; i++) {
     668            for (unsigned i = 0; i < chunkChars; i++) {
    606669                resultString.append(radixDigits[chunk % radix]);
    607670                chunk /= radix;
     
    628691
    629692    // Remove leading zeroes.
    630     int newSizeNoLeadingZeroes = resultString.size();
     693    unsigned newSizeNoLeadingZeroes = resultString.size();
    631694    while (newSizeNoLeadingZeroes  > 1 && resultString[newSizeNoLeadingZeroes - 1] == '0')
    632695        newSizeNoLeadingZeroes--;
     
    646709    if (isZero())
    647710        return this;
     711
     712    ASSERT(m_length);
    648713
    649714    int nonZeroIndex = m_length - 1;
     
    651716        nonZeroIndex--;
    652717
    653     if (nonZeroIndex == m_length - 1)
     718    if (nonZeroIndex == static_cast<int>(m_length - 1))
    654719        return this;
    655720
    656     int newLength = nonZeroIndex + 1;
     721    unsigned newLength = nonZeroIndex + 1;
    657722    JSBigInt* trimmedBigInt = createWithLength(vm, newLength);
    658723    RELEASE_ASSERT(trimmedBigInt);
     
    664729}
    665730
    666 JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, int radix, int charcount)
     731JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, unsigned radix, unsigned charcount)
    667732{
    668733    ASSERT(2 <= radix && radix <= 36);
     
    671736    size_t bitsPerChar = maxBitsPerCharTable[radix];
    672737    size_t chars = charcount;
    673     const int roundup = bitsPerCharTableMultiplier - 1;
     738    const unsigned roundup = bitsPerCharTableMultiplier - 1;
    674739    if (chars <= (std::numeric_limits<size_t>::max() - roundup) / bitsPerChar) {
    675740        size_t bitsMin = bitsPerChar * chars;
     
    679744        if (bitsMin <= static_cast<size_t>(maxInt)) {
    680745            // Divide by kDigitsBits, rounding up.
    681             int length = (static_cast<int>(bitsMin) + digitBits - 1) / digitBits;
     746            unsigned length = (bitsMin + digitBits - 1) / digitBits;
    682747            if (length <= maxLength) {
    683748                JSBigInt* result = JSBigInt::createWithLength(vm, length);
     
    720785
    721786template <typename CharType>
    722 JSBigInt* JSBigInt::parseInt(ExecState* state, CharType*  data, int length)
     787JSBigInt* JSBigInt::parseInt(ExecState* state, CharType*  data, unsigned length)
    723788{
    724789    VM& vm = state->vm();
    725790
    726     int p = 0;
     791    unsigned p = 0;
    727792    while (p < length && isStrWhiteSpace(data[p]))
    728793        ++p;
     
    759824
    760825template <typename CharType>
    761 JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int length, int startIndex, int radix, bool allowEmptyString)
     826JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, bool allowEmptyString)
    762827{
    763828    ASSERT(length >= 0);
    764     int p = startIndex;
     829    unsigned p = startIndex;
    765830
    766831    auto scope = DECLARE_THROW_SCOPE(vm);
     
    778843    int endIndex = length - 1;
    779844    // Removing trailing spaces
    780     while (endIndex >= p && isStrWhiteSpace(data[endIndex]))
     845    while (endIndex >= static_cast<int>(p) && isStrWhiteSpace(data[endIndex]))
    781846        --endIndex;
    782847
     
    786851        return createZero(vm);
    787852
    788     int limit0 = '0' + (radix < 10 ? radix : 10);
    789     int limita = 'a' + (radix - 10);
    790     int limitA = 'A' + (radix - 10);
     853    unsigned limit0 = '0' + (radix < 10 ? radix : 10);
     854    unsigned limita = 'a' + (radix - 10);
     855    unsigned limitA = 'A' + (radix - 10);
    791856
    792857    JSBigInt* result = allocateFor(state, vm, radix, length - p);
     
    795860    result->initialize(InitializationType::WithZero);
    796861
    797     for (int i = p; i < length; i++, p++) {
     862    for (unsigned i = p; i < length; i++, p++) {
    798863        uint32_t digit;
    799864        if (data[i] >= '0' && data[i] < limit0)
     
    823888}
    824889
    825 JSBigInt::Digit JSBigInt::digit(int n)
     890JSBigInt::Digit JSBigInt::digit(unsigned n)
    826891{
    827892    ASSERT(n >= 0 && n < length());
     
    829894}
    830895
    831 void JSBigInt::setDigit(int n, Digit value)
     896void JSBigInt::setDigit(unsigned n, Digit value)
    832897{
    833898    ASSERT(n >= 0 && n < length());
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.h

    r231104 r231131  
    4242public:
    4343
    44     JSBigInt(VM&, Structure*, int length);
     44    JSBigInt(VM&, Structure*, unsigned length);
    4545
    4646    enum class InitializationType { None, WithZero };
     
    5050
    5151    static size_t estimatedSize(JSCell*);
    52     static size_t allocationSize(int length);
     52    static size_t allocationSize(unsigned length);
    5353
    5454    static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
    55 
    5655    static JSBigInt* createZero(VM&);
    57     static JSBigInt* createWithLength(VM&, int length);
     56    static JSBigInt* createWithLength(VM&, unsigned length);
    5857
    5958    static JSBigInt* createFrom(VM&, int32_t value);
     
    7170    bool sign() const { return m_sign; }
    7271
    73     void setLength(int length) { m_length = length; }
    74     int length() const { return m_length; }
     72    void setLength(unsigned length) { m_length = length; }
     73    unsigned length() const { return m_length; }
    7574
    7675    static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix);
     
    7877
    7978    std::optional<uint8_t> singleDigitValueForString();
    80     String toString(ExecState&, int radix);
     79    String toString(ExecState&, unsigned radix);
    8180   
    8281    JS_EXPORT_PRIVATE static bool equals(JSBigInt*, JSBigInt*);
     
    8685
    8786    JSObject* toObject(ExecState*, JSGlobalObject*) const;
     87
     88    static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y);
    8889   
    8990private:
    9091    using Digit = uintptr_t;
    91     static constexpr const int bitsPerByte = 8;
    92     static constexpr const int digitBits = sizeof(Digit) * bitsPerByte;
    93     static constexpr const int halfDigitBits = digitBits / 2;
     92    static constexpr const unsigned bitsPerByte = 8;
     93    static constexpr const unsigned digitBits = sizeof(Digit) * bitsPerByte;
     94    static constexpr const unsigned halfDigitBits = digitBits / 2;
    9495    static constexpr const Digit halfDigitMask = (1ull << halfDigitBits) - 1;
    9596    static constexpr const int maxInt = 0x7FFFFFFF;
     
    99100    // raising it later is easier than lowering it.
    100101    // Support up to 1 million bits.
    101     static const int maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
     102    static const unsigned maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
    102103   
    103     static uint64_t calculateMaximumCharactersRequired(int length, int radix, Digit lastDigit, bool sign);
     104    static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign);
    104105   
    105106    static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder);
    106     static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int, JSBigInt* result);
     107    static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result);
     108    static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex);
    107109
    108110    // Digit arithmetic helpers.
     
    113115    static Digit digitPow(Digit base, Digit exponent);
    114116
    115     static String toStringGeneric(ExecState&, JSBigInt*, int radix);
     117    static String toStringGeneric(ExecState&, JSBigInt*, unsigned radix);
    116118
    117119    bool isZero();
    118120
    119121    template <typename CharType>
    120     static JSBigInt* parseInt(ExecState*, CharType*  data, int length);
     122    static JSBigInt* parseInt(ExecState*, CharType*  data, unsigned length);
    121123
    122124    template <typename CharType>
    123     static JSBigInt* parseInt(ExecState*, VM&, CharType* data, int length, int startIndex, int radix, bool allowEmptyString = true);
     125    static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, bool allowEmptyString = true);
    124126
    125     static JSBigInt* allocateFor(ExecState*, VM&, int radix, int charcount);
     127    static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount);
    126128
    127129    JSBigInt* rightTrim(VM&);
     
    132134    Digit* dataStorage();
    133135
    134     Digit digit(int);
    135     void setDigit(int, Digit);
     136    Digit digit(unsigned);
     137    void setDigit(unsigned, Digit);
    136138       
    137     int m_length;
     139    unsigned m_length;
    138140    bool m_sign;
    139141};
  • trunk/Source/JavaScriptCore/runtime/Operations.h

    r231104 r231131  
    2424#include "CallFrame.h"
    2525#include "ExceptionHelpers.h"
     26#include "JSBigInt.h"
    2627#include "JSCJSValue.h"
    2728
     
    257258}
    258259
     260ALWAYS_INLINE JSValue jsMul(ExecState* state, JSValue v1, JSValue v2)
     261{
     262    VM& vm = state->vm();
     263    auto scope = DECLARE_THROW_SCOPE(vm);
     264
     265    JSValue leftNumber = v1.toPrimitive(state, PreferNumber);
     266    RETURN_IF_EXCEPTION(scope, { });
     267    JSValue rightNumber = v2.toPrimitive(state, PreferNumber);
     268    RETURN_IF_EXCEPTION(scope, { });
     269
     270    if (leftNumber.isBigInt() || rightNumber.isBigInt()) {
     271        if (leftNumber.isBigInt() && rightNumber.isBigInt())
     272            return JSBigInt::multiply(state, asBigInt(leftNumber), asBigInt(rightNumber));
     273
     274        throwTypeError(state, scope, ASCIILiteral("Invalid mix of BigInt and other type in multiplication."));
     275        return { };
     276    }
     277
     278    scope.release();
     279    double leftValue =  leftNumber.toNumber(state);
     280    double rightValue =  rightNumber.toNumber(state);
     281    return jsNumber(leftValue * rightValue);
     282}
     283
    259284inline bool scribbleFreeCells()
    260285{
Note: See TracChangeset for help on using the changeset viewer.