⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 211128 in webkit


Ignore:
Timestamp:
Jan 24, 2017, 6:40:52 PM (10 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] Optimize Number#toString with Int52
https://bugs.webkit.org/show_bug.cgi?id=167303

Reviewed by Sam Weinig.

JSTests:

  • stress/to-string-with-int52.js: Added.

(shouldBe):

Source/JavaScriptCore:

In kraken crypto-sha256-iterative, we frequently call Number.prototype.toString with
Int52. In that case, toString handles it in the generic double path. But we should
have a fast path for this since it can be represented in int64_t.

The stanford-crypto-sha256-iterative shows 1.6% performance improvement (on Linux machine hanayamata).

Collected 100 samples per benchmark/VM, with 100 VM invocations per benchmark. Emitted a call to gc() between
sample measurements. Used 1 benchmark iteration per VM invocation for warm-up. Used the jsc-specific preciseTime()
function to get microsecond-level timing. Reporting benchmark execution times with 95% confidence intervals in
milliseconds.

baseline patched

stanford-crypto-sha256-iterative 32.853+-0.075 32.325+-0.055 definitely 1.0163x faster

  • runtime/JSCJSValue.h:
  • runtime/NumberPrototype.cpp:

(JSC::int52ToStringWithRadix):
(JSC::toStringWithRadix):

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r211122 r211128  
     12017-01-24  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Optimize Number#toString with Int52
     4        https://bugs.webkit.org/show_bug.cgi?id=167303
     5
     6        Reviewed by Sam Weinig.
     7
     8        * stress/to-string-with-int52.js: Added.
     9        (shouldBe):
     10
    1112017-01-24  Filip Pizlo  <fpizlo@apple.com>
    212
  • trunk/Source/JavaScriptCore/ChangeLog

    r211124 r211128  
     12017-01-24  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Optimize Number#toString with Int52
     4        https://bugs.webkit.org/show_bug.cgi?id=167303
     5
     6        Reviewed by Sam Weinig.
     7
     8        In kraken crypto-sha256-iterative, we frequently call Number.prototype.toString with
     9        Int52. In that case, toString handles it in the generic double path. But we should
     10        have a fast path for this since it can be represented in int64_t.
     11
     12        The stanford-crypto-sha256-iterative shows 1.6% performance improvement (on Linux machine hanayamata).
     13
     14            Collected 100 samples per benchmark/VM, with 100 VM invocations per benchmark. Emitted a call to gc() between
     15            sample measurements. Used 1 benchmark iteration per VM invocation for warm-up. Used the jsc-specific preciseTime()
     16            function to get microsecond-level timing. Reporting benchmark execution times with 95% confidence intervals in
     17            milliseconds.
     18
     19                                                       baseline                  patched
     20
     21            stanford-crypto-sha256-iterative        32.853+-0.075      ^      32.325+-0.055         ^ definitely 1.0163x faster
     22
     23        * runtime/JSCJSValue.h:
     24        * runtime/NumberPrototype.cpp:
     25        (JSC::int52ToStringWithRadix):
     26        (JSC::toStringWithRadix):
     27
    1282017-01-24  Michael Saboff  <msaboff@apple.com>
    229
  • trunk/Source/JavaScriptCore/runtime/JSCJSValue.h

    r208985 r211128  
    317317    // Constants used for Int52. Int52 isn't part of JSValue right now, but JSValues may be
    318318    // converted to Int52s and back again.
    319     static const unsigned numberOfInt52Bits = 52;
    320     static const int64_t notInt52 = static_cast<int64_t>(1) << numberOfInt52Bits;
    321     static const unsigned int52ShiftAmount = 12;
     319    static constexpr const unsigned numberOfInt52Bits = 52;
     320    static constexpr const int64_t notInt52 = static_cast<int64_t>(1) << numberOfInt52Bits;
     321    static constexpr const unsigned int52ShiftAmount = 12;
    322322   
    323323    static ptrdiff_t offsetOfPayload() { return OBJECT_OFFSETOF(JSValue, u.asBits.payload); }
  • trunk/Source/JavaScriptCore/runtime/NumberPrototype.cpp

    r209906 r211128  
    145145static const char radixDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    146146
    147 static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
    148 {
    149     ASSERT(std::isfinite(number));
     147static char* int52ToStringWithRadix(char* startOfResultString, int64_t int52Value, unsigned radix)
     148{
     149    bool negative = false;
     150    uint64_t positiveNumber = int52Value;
     151    if (int52Value < 0) {
     152        negative = true;
     153        positiveNumber = -int52Value;
     154    }
     155
     156    do {
     157        uint64_t index = positiveNumber % radix;
     158        ASSERT(index < sizeof(radixDigits));
     159        *--startOfResultString = radixDigits[index];
     160        positiveNumber /= radix;
     161    } while (positiveNumber);
     162    if (negative)
     163        *--startOfResultString = '-';
     164
     165    return startOfResultString;
     166}
     167
     168static char* toStringWithRadix(RadixBuffer& buffer, double originalNumber, unsigned radix)
     169{
     170    ASSERT(std::isfinite(originalNumber));
    150171    ASSERT(radix >= 2 && radix <= 36);
    151172
     
    156177
    157178    // Extract the sign.
    158     bool isNegative = number < 0;
    159     if (std::signbit(number))
    160         number = -number;
     179    bool isNegative = originalNumber < 0;
     180    double number = originalNumber;
     181    if (std::signbit(originalNumber))
     182        number = -originalNumber;
    161183    double integerPart = floor(number);
    162 
    163     // We use this to test for odd values in odd radix bases.
    164     // Where the base is even, (e.g. 10), to determine whether a value is even we need only
    165     // consider the least significant digit. For example, 124 in base 10 is even, because '4'
    166     // is even. if the radix is odd, then the radix raised to an integer power is also odd.
    167     // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
    168     // is multiplied by an odd number, the result is even if the sum of all digits is even.
    169     //
    170     // For the integer portion of the result, we only need test whether the integer value is
    171     // even or odd. For each digit of the fraction added, we should invert our idea of whether
    172     // the number is odd if the new digit is odd.
    173     //
    174     // Also initialize digit to this value; for even radix values we only need track whether
    175     // the last individual digit was odd.
    176     bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
    177     ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
    178     bool isOddInOddRadix = integerPartIsOdd;
    179     uint32_t digit = integerPartIsOdd;
    180184
    181185    // Check if the value has a fractional part to convert.
    182186    double fractionPart = number - integerPart;
    183     if (fractionPart) {
     187    if (!fractionPart) {
     188        *decimalPoint = '\0';
     189        // We do not need to care the negative zero (-0) since it is also converted to "0" in all the radix.
     190        if (integerPart < (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
     191            return int52ToStringWithRadix(startOfResultString, static_cast<int64_t>(originalNumber), radix);
     192    } else {
     193        // We use this to test for odd values in odd radix bases.
     194        // Where the base is even, (e.g. 10), to determine whether a value is even we need only
     195        // consider the least significant digit. For example, 124 in base 10 is even, because '4'
     196        // is even. if the radix is odd, then the radix raised to an integer power is also odd.
     197        // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
     198        // is multiplied by an odd number, the result is even if the sum of all digits is even.
     199        //
     200        // For the integer portion of the result, we only need test whether the integer value is
     201        // even or odd. For each digit of the fraction added, we should invert our idea of whether
     202        // the number is odd if the new digit is odd.
     203        //
     204        // Also initialize digit to this value; for even radix values we only need track whether
     205        // the last individual digit was odd.
     206        bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
     207        ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
     208        bool isOddInOddRadix = integerPartIsOdd;
     209        uint32_t digit = integerPartIsOdd;
     210
    184211        // Write the decimal point now.
    185212        *decimalPoint = '.';
     
    311338        *endOfResultString = '\0';
    312339        ASSERT(endOfResultString < buffer + sizeof(buffer));
    313     } else
    314         *decimalPoint = '\0';
     340    }
    315341
    316342    BigInteger units(integerPart);
     
    322348        // Read a single digit and write it to the front of the string.
    323349        // Divide by radix to remove one digit from the value.
    324         digit = units.divide(radix);
     350        uint32_t digit = units.divide(radix);
    325351        *--startOfResultString = radixDigits[digit];
    326352    } while (!!units);
Note: See TracChangeset for help on using the changeset viewer.