Changeset 231733 in webkit


Ignore:
Timestamp:
May 11, 2018 9:32:12 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 Yusuke Suzuki.

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/JSCJSValue.h:
  • runtime/JSCJSValueInlines.h:

(JSC::JSValue::toNumeric const):

  • runtime/Operations.h:

(JSC::jsMul):

Location:
trunk
Files:
7 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r231710 r231733  
     12018-05-11  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 Yusuke Suzuki.
     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-05-11  Michael Saboff  <msaboff@apple.com>
    218
  • trunk/JSTests/bigIntTests.yaml

    r231147 r231733  
    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

    r231719 r231733  
     12018-05-11  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 Yusuke Suzuki.
     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/JSCJSValue.h:
     38        * runtime/JSCJSValueInlines.h:
     39        (JSC::JSValue::toNumeric const):
     40        * runtime/Operations.h:
     41        (JSC::jsMul):
     42
    1432018-05-11  Commit Queue  <commit-queue@webkit.org>
    244
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r231514 r231733  
    149149
    150150                    // FIXME: Revisit this condition when introducing BigInt to JSC.
    151                     auto isNonStringCellConstant = [] (JSValue value) {
    152                         return value && value.isCell() && !value.isString();
     151                    auto isNonStringOrBigIntCellConstant = [] (JSValue value) {
     152                        return value && value.isCell() && !value.isString() && !value.isBigInt();
    153153                    };
    154154
    155                     if (isNonStringCellConstant(child1Constant)) {
     155                    if (isNonStringOrBigIntCellConstant(child1Constant)) {
    156156                        node->convertToCompareEqPtr(m_graph.freezeStrong(child1Constant.asCell()), node->child2());
    157157                        changed = true;
    158                     } else if (isNonStringCellConstant(child2Constant)) {
     158                    } else if (isNonStringOrBigIntCellConstant(child2Constant)) {
    159159                        node->convertToCompareEqPtr(m_graph.freezeStrong(child2Constant.asCell()), node->child1());
    160160                        changed = true;
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r231147 r231733  
    25552555}
    25562556
    2557 ALWAYS_INLINE static EncodedJSValue unprofiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
    2558 {
     2557ALWAYS_INLINE static EncodedJSValue unprofiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
     2558{
     2559    JSValue op1 = JSValue::decode(encodedOp1);
     2560    JSValue op2 = JSValue::decode(encodedOp2);
     2561
     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{
     2567    VM& vm = exec->vm();
    25592568    auto scope = DECLARE_THROW_SCOPE(vm);
    25602569    JSValue op1 = JSValue::decode(encodedOp1);
    25612570    JSValue op2 = JSValue::decode(encodedOp2);
    25622571
    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);
    2573     JSValue op1 = JSValue::decode(encodedOp1);
    2574     JSValue op2 = JSValue::decode(encodedOp2);
    2575 
    25762572    if (shouldObserveLHSAndRHSTypes)
    25772573        arithProfile.observeLHSAndRHS(op1, op2);
    25782574
    2579     double a = op1.toNumber(exec);
     2575    JSValue result = jsMul(exec, op1, op2);
    25802576    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    2581     double b = op2.toNumber(exec);
    2582     RETURN_IF_EXCEPTION(scope, encodedJSValue());
    2583    
    2584     JSValue result = jsNumber(a * b);
    25852577    arithProfile.observeResult(result);
    25862578    return JSValue::encode(result);
     
    25922584    NativeCallFrameTracer tracer(vm, exec);
    25932585
    2594     return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
     2586    return unprofiledMul(exec, encodedOp1, encodedOp2);
    25952587}
    25962588
     
    26002592    NativeCallFrameTracer tracer(vm, exec);
    26012593
    2602     return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
     2594    return unprofiledMul(exec, encodedOp1, encodedOp2);
    26032595}
    26042596
     
    26172609#endif
    26182610
    2619     return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
     2611    return unprofiledMul(exec, encodedOp1, encodedOp2);
    26202612}
    26212613
     
    26262618
    26272619    ASSERT(arithProfile);
    2628     return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile);
     2620    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile);
    26292621}
    26302622
     
    26442636#endif
    26452637
    2646     return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile, false);
     2638    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile, false);
    26472639}
    26482640
     
    26542646    ArithProfile* arithProfile = mulIC->arithProfile();
    26552647    ASSERT(arithProfile);
    2656     return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile);
     2648    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile);
    26572649}
    26582650
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r231345 r231733  
    6666#include "TypeProfilerLog.h"
    6767#include <wtf/StringPrintStream.h>
     68#include <wtf/Variant.h>
    6869
    6970namespace JSC {
     
    489490    JSValue left = OP_C(2).jsValue();
    490491    JSValue right = OP_C(3).jsValue();
    491     double a = left.toNumber(exec);
    492     if (UNLIKELY(throwScope.exception()))
    493         RETURN(JSValue());
    494     double b = right.toNumber(exec);
    495     JSValue result = jsNumber(a * b);
     492    JSValue result = jsMul(exec, left, right);
     493    CHECK_EXCEPTION();
    496494    RETURN_WITH_PROFILING(result, {
    497495        updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp

    r231629 r231733  
    6969}
    7070
    71 JSBigInt::JSBigInt(VM& vm, Structure* structure, int length)
     71JSBigInt::JSBigInt(VM& vm, Structure* structure, unsigned length)
    7272    : Base(vm, structure)
    7373    , m_length(length)
     
    9393}
    9494
    95 size_t JSBigInt::allocationSize(int length)
     95size_t JSBigInt::allocationSize(unsigned length)
    9696{
    9797    size_t sizeWithPadding = WTF::roundUpToMultipleOf<sizeof(size_t)>(sizeof(JSBigInt));
     
    9999}
    100100
    101 JSBigInt* JSBigInt::createWithLength(VM& vm, int length)
     101JSBigInt* JSBigInt::createWithLength(VM& vm, unsigned length)
    102102{
    103103    JSBigInt* bigInt = new (NotNull, allocateCell<JSBigInt>(vm.heap, allocationSize(length))) JSBigInt(vm, vm.bigIntStructure.get(), length);
     
    249249
    250250    internalMultiplyAdd(this, factor, summand, length(), this);
     251}
     252
     253JSBigInt* JSBigInt::multiply(ExecState* state, JSBigInt* x, JSBigInt* y)
     254{
     255    VM& vm = state->vm();
     256
     257    if (x->isZero())
     258        return x;
     259    if (y->isZero())
     260        return y;
     261
     262    unsigned resultLength = x->length() + y->length();
     263    JSBigInt* result = JSBigInt::createWithLength(vm, resultLength);
     264    result->initialize(InitializationType::WithZero);
     265
     266    for (unsigned i = 0; i < x->length(); i++)
     267        multiplyAccumulate(y, x->digit(i), result, i);
     268
     269    result->setSign(x->sign() != y->sign());
     270    return result->rightTrim(vm);
    251271}
    252272
     
    364384    // Adapted from Warren, Hacker's Delight, p. 152.
    365385#if USE(JSVALUE64)
    366     int s = clz64(divisor);
     386    unsigned s = clz64(divisor);
    367387#else
    368     int s = clz32(divisor);
     388    unsigned s = clz32(divisor);
    369389#endif
    370390    divisor <<= s;
     
    409429// Multiplies {source} with {factor} and adds {summand} to the result.
    410430// {result} and {source} may be the same BigInt for inplace modification.
    411 void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int n, JSBigInt* result)
     431void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned n, JSBigInt* result)
    412432{
    413433    ASSERT(source->length() >= n);
     
    416436    Digit carry = summand;
    417437    Digit high = 0;
    418     for (int i = 0; i < n; i++) {
     438    for (unsigned i = 0; i < n; i++) {
    419439        Digit current = source->digit(i);
    420440        Digit newCarry = 0;
     
    444464}
    445465
     466// Multiplies {multiplicand} with {multiplier} and adds the result to
     467// {accumulator}, starting at {accumulatorIndex} for the least-significant
     468// digit.
     469// Callers must ensure that {accumulator} is big enough to hold the result.
     470void JSBigInt::multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex)
     471{
     472    ASSERT(accumulator->length() > multiplicand->length() + accumulatorIndex);
     473    if (!multiplier)
     474        return;
     475   
     476    Digit carry = 0;
     477    Digit high = 0;
     478    for (unsigned i = 0; i < multiplicand->length(); i++, accumulatorIndex++) {
     479        Digit acc = accumulator->digit(accumulatorIndex);
     480        Digit newCarry = 0;
     481       
     482        // Add last round's carryovers.
     483        acc = digitAdd(acc, high, newCarry);
     484        acc = digitAdd(acc, carry, newCarry);
     485       
     486        // Compute this round's multiplication.
     487        Digit multiplicandDigit = multiplicand->digit(i);
     488        Digit low = digitMul(multiplier, multiplicandDigit, high);
     489        acc = digitAdd(acc, low, newCarry);
     490       
     491        // Store result and prepare for next round.
     492        accumulator->setDigit(accumulatorIndex, acc);
     493        carry = newCarry;
     494    }
     495   
     496    while (carry || high) {
     497        ASSERT(accumulatorIndex < accumulator->length());
     498        Digit acc = accumulator->digit(accumulatorIndex);
     499        Digit newCarry = 0;
     500        acc = digitAdd(acc, high, newCarry);
     501        high = 0;
     502        acc = digitAdd(acc, carry, newCarry);
     503        accumulator->setDigit(accumulatorIndex, acc);
     504        carry = newCarry;
     505        accumulatorIndex++;
     506    }
     507}
     508
    446509bool JSBigInt::equals(JSBigInt* x, JSBigInt* y)
    447510{
     
    452515        return false;
    453516
    454     for (int i = 0; i < x->length(); i++) {
     517    for (unsigned i = 0; i < x->length(); i++) {
    455518        if (x->digit(i) != y->digit(i))
    456519            return false;
     
    480543    }
    481544
    482     int length = x->length();
     545    unsigned length = x->length();
    483546    if (quotient != nullptr) {
    484547        if (*quotient == nullptr)
     
    507570};
    508571
    509 static const int bitsPerCharTableShift = 5;
     572static const unsigned bitsPerCharTableShift = 5;
    510573static const size_t bitsPerCharTableMultiplier = 1u << bitsPerCharTableShift;
    511574
    512575// Compute (an overapproximation of) the length of the resulting string:
    513576// Divide bit length of the BigInt by bits representable per character.
    514 uint64_t JSBigInt::calculateMaximumCharactersRequired(int length, int radix, Digit lastDigit, bool sign)
    515 {
    516     int leadingZeros;
     577uint64_t JSBigInt::calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign)
     578{
     579    unsigned leadingZeros;
    517580    if (sizeof(lastDigit) == 8)
    518581        leadingZeros = clz64(lastDigit);
     
    542605}
    543606
    544 String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, int radix)
     607String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, unsigned radix)
    545608{
    546609    // FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString
     
    551614    ASSERT(!x->isZero());
    552615
    553     int length = x->length();
     616    unsigned length = x->length();
    554617    bool sign = x->sign();
    555618
     
    567630        lastDigit = x->digit(0);
    568631    else {
    569         int chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar;
     632        unsigned chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar;
    570633        Digit chunkDivisor = digitPow(radix, chunkChars);
    571634
    572635        // By construction of chunkChars, there can't have been overflow.
    573636        ASSERT(chunkDivisor);
    574         int nonZeroDigit = length - 1;
     637        unsigned nonZeroDigit = length - 1;
    575638        ASSERT(x->digit(nonZeroDigit));
    576639
     
    588651
    589652            dividend = &rest;
    590             for (int i = 0; i < chunkChars; i++) {
     653            for (unsigned i = 0; i < chunkChars; i++) {
    591654                resultString.append(radixDigits[chunk % radix]);
    592655                chunk /= radix;
     
    613676
    614677    // Remove leading zeroes.
    615     int newSizeNoLeadingZeroes = resultString.size();
     678    unsigned newSizeNoLeadingZeroes = resultString.size();
    616679    while (newSizeNoLeadingZeroes  > 1 && resultString[newSizeNoLeadingZeroes - 1] == '0')
    617680        newSizeNoLeadingZeroes--;
     
    631694    if (isZero())
    632695        return this;
     696
     697    ASSERT(m_length);
    633698
    634699    int nonZeroIndex = m_length - 1;
     
    636701        nonZeroIndex--;
    637702
    638     if (nonZeroIndex == m_length - 1)
     703    if (nonZeroIndex == static_cast<int>(m_length - 1))
    639704        return this;
    640705
    641     int newLength = nonZeroIndex + 1;
     706    unsigned newLength = nonZeroIndex + 1;
    642707    JSBigInt* trimmedBigInt = createWithLength(vm, newLength);
    643708    RELEASE_ASSERT(trimmedBigInt);
     
    649714}
    650715
    651 JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, int radix, int charcount)
     716JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, unsigned radix, unsigned charcount)
    652717{
    653718    ASSERT(2 <= radix && radix <= 36);
     
    656721    size_t bitsPerChar = maxBitsPerCharTable[radix];
    657722    size_t chars = charcount;
    658     const int roundup = bitsPerCharTableMultiplier - 1;
     723    const unsigned roundup = bitsPerCharTableMultiplier - 1;
    659724    if (chars <= (std::numeric_limits<size_t>::max() - roundup) / bitsPerChar) {
    660725        size_t bitsMin = bitsPerChar * chars;
     
    664729        if (bitsMin <= static_cast<size_t>(maxInt)) {
    665730            // Divide by kDigitsBits, rounding up.
    666             int length = (static_cast<int>(bitsMin) + digitBits - 1) / digitBits;
     731            unsigned length = (bitsMin + digitBits - 1) / digitBits;
    667732            if (length <= maxLength) {
    668733                JSBigInt* result = JSBigInt::createWithLength(vm, length);
     
    772837        return createZero(vm);
    773838
    774     int limit0 = '0' + (radix < 10 ? radix : 10);
    775     int limita = 'a' + (radix - 10);
    776     int limitA = 'A' + (radix - 10);
     839    unsigned limit0 = '0' + (radix < 10 ? radix : 10);
     840    unsigned limita = 'a' + (radix - 10);
     841    unsigned limitA = 'A' + (radix - 10);
    777842
    778843    JSBigInt* result = allocateFor(state, vm, radix, length - p);
     
    810875}
    811876
    812 inline JSBigInt::Digit JSBigInt::digit(int n)
     877JSBigInt::Digit JSBigInt::digit(unsigned n)
    813878{
    814879    ASSERT(n >= 0 && n < length());
     
    816881}
    817882
    818 inline void JSBigInt::setDigit(int n, Digit value)
     883void JSBigInt::setDigit(unsigned n, Digit value)
    819884{
    820885    ASSERT(n >= 0 && n < length());
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.h

    r231629 r231733  
    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    enum ErrorParseMode {
     
    9392
    9493    JSObject* toObject(ExecState*, JSGlobalObject*) const;
     94
     95    static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y);
    9596   
    9697private:
     
    104105
    105106    using Digit = uintptr_t;
    106     static constexpr const int bitsPerByte = 8;
    107     static constexpr const int digitBits = sizeof(Digit) * bitsPerByte;
    108     static constexpr const int halfDigitBits = digitBits / 2;
     107    static constexpr const unsigned bitsPerByte = 8;
     108    static constexpr const unsigned digitBits = sizeof(Digit) * bitsPerByte;
     109    static constexpr const unsigned halfDigitBits = digitBits / 2;
    109110    static constexpr const Digit halfDigitMask = (1ull << halfDigitBits) - 1;
    110111    static constexpr const int maxInt = 0x7FFFFFFF;
     
    114115    // raising it later is easier than lowering it.
    115116    // Support up to 1 million bits.
    116     static const int maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
     117    static const unsigned maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
    117118   
    118     static uint64_t calculateMaximumCharactersRequired(int length, int radix, Digit lastDigit, bool sign);
     119    static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign);
    119120   
    120121    static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder);
    121     static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int, JSBigInt* result);
     122    static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result);
     123    static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex);
    122124
    123125    // Digit arithmetic helpers.
     
    128130    static Digit digitPow(Digit base, Digit exponent);
    129131
    130     static String toStringGeneric(ExecState&, JSBigInt*, int radix);
     132    static String toStringGeneric(ExecState&, JSBigInt*, unsigned radix);
    131133
    132134    bool isZero();
     
    140142    static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, bool allowEmptyString = true);
    141143
    142     static JSBigInt* allocateFor(ExecState*, VM&, int radix, int charcount);
     144    static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount);
    143145
    144146    JSBigInt* rightTrim(VM&);
     
    149151    Digit* dataStorage();
    150152
    151     Digit digit(int);
    152     void setDigit(int, Digit);
     153    Digit digit(unsigned);
     154    void setDigit(unsigned, Digit);
    153155       
    154     int m_length;
     156    unsigned m_length;
    155157    bool m_sign;
    156158};
  • trunk/Source/JavaScriptCore/runtime/JSCJSValue.h

    r230376 r231733  
    4040
    4141class AssemblyHelpers;
     42class JSBigInt;
    4243class ExecState;
    4344class JSCell;
     
    258259    // been set in the ExecState already.
    259260    double toNumber(ExecState*) const;
     261   
     262    Variant<JSBigInt*, double> toNumeric(ExecState*) const;
    260263
    261264    // toNumber conversion if it can be done without side effects.
  • trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h

    r231629 r231733  
    3838#include "JSStringInlines.h"
    3939#include "MathCommon.h"
     40#include <wtf/Variant.h>
    4041#include <wtf/text/StringImpl.h>
    4142
     
    727728        return asDouble();
    728729    return toNumberSlowCase(exec);
     730}
     731
     732ALWAYS_INLINE Variant<JSBigInt*, double> JSValue::toNumeric(ExecState* exec) const
     733{
     734    if (isInt32())
     735        return asInt32();
     736    if (isDouble())
     737        return asDouble();
     738    if (isBigInt())
     739        return asBigInt(*this);
     740
     741    VM& vm = exec->vm();
     742    auto scope = DECLARE_THROW_SCOPE(vm);
     743    JSValue primValue = this->toPrimitive(exec, PreferNumber);
     744    RETURN_IF_EXCEPTION(scope, 0);
     745    if (primValue.isBigInt())
     746        return asBigInt(primValue);
     747    double value = primValue.toNumber(exec);
     748    RETURN_IF_EXCEPTION(scope, 0);
     749    return value;
    729750}
    730751
  • trunk/Source/JavaScriptCore/runtime/Operations.h

    r231147 r231733  
    2424#include "CallFrame.h"
    2525#include "ExceptionHelpers.h"
     26#include "JSBigInt.h"
    2627#include "JSCJSValue.h"
     28#include <wtf/Variant.h>
    2729
    2830namespace JSC {
     
    257259}
    258260
     261ALWAYS_INLINE JSValue jsMul(ExecState* state, JSValue v1, JSValue v2)
     262{
     263    VM& vm = state->vm();
     264    auto scope = DECLARE_THROW_SCOPE(vm);
     265
     266    Variant<JSBigInt*, double> leftNumeric = v1.toNumeric(state);
     267    RETURN_IF_EXCEPTION(scope, { });
     268    Variant<JSBigInt*, double> rightNumeric = v2.toNumeric(state);
     269    RETURN_IF_EXCEPTION(scope, { });
     270
     271    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
     272        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
     273            return JSBigInt::multiply(state, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
     274
     275        throwTypeError(state, scope, ASCIILiteral("Invalid mix of BigInt and other type in multiplication."));
     276        return { };
     277    }
     278
     279    double leftValue =  WTF::get<double>(leftNumeric);
     280    double rightValue =  WTF::get<double>(rightNumeric);
     281    return jsNumber(leftValue * rightValue);
     282}
     283
    259284inline bool scribbleFreeCells()
    260285{
Note: See TracChangeset for help on using the changeset viewer.