Changeset 31404 in webkit for trunk/JavaScriptCore/kjs/dtoa.cpp


Ignore:
Timestamp:
Mar 28, 2008, 1:21:39 PM (17 years ago)
Author:
[email protected]
Message:

Reviewed by Sam Weinig.

Fix a dtoa thread safety issue.

WebCore can call kjs_strtod without holding JS lock, but we didn't have thread safety
compiled in for dtoa.

This is a 0.5% regression on SunSpider, which Sam Weinig has volunteered to cover with
his recent improvement.

  • kjs/dtoa.cpp: (Bigint::Balloc): (Bigint::Bfree): Changed to use fastMalloc/fastDelete - they are much faster than the dtoa custom version was in the presence of locking (but somewhat slower in single-threaded case). (Bigint::pow5mult): Got rid of the dreaded double-checked locking anti-pattern (had to restructure the code to avoid significant performance implications). (Bigint::lshift): Rewrote to avoid an allocation, if possible.

(Bigint::rv_alloc):
(Bigint::kjs_freedtoa):
(Bigint::kjs_dtoa):
Check for USE(MULTIPLE_THREADS), not dtoa legacy MULTIPLE_THREADS.

  • kjs/InitializeThreading.cpp: Added. (KJS::initializeThreading):
  • kjs/InitializeThreading.h: Added. Initialize threading at KJS level, if enabled.
  • kjs/dtoa.h: Expose dtoa mutex for KJS::initializeThreading.
  • kjs/testkjs.cpp: (kjsmain): Call initializeThreading.
  • wtf/Threading.h: Removed a using directive for WTF::initializeThreading - it is only to be called from KJS::initializeThreading, and having it in the global namespace is useless.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/dtoa.cpp

    r31318 r31404  
    9898 *    define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
    9999 *    FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
    100  * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
    101  *    memory allocations from a private pool of memory when possible.
    102  *    When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
    103  *    unless #defined to be a different length.  This default length
    104  *    suffices to get rid of MALLOC calls except for unusual cases,
    105  *    such as decimal-to-binary conversion of a very long string of
    106  *    digits.  The longest string dtoa can return is about 751 bytes
    107  *    long.  For conversions by strtod of strings of 800 digits and
    108  *    all dtoa conversions in single-threaded executions with 8-byte
    109  *    pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
    110  *    pointers, PRIVATE_MEM >= 7112 appears adequate.
    111100 * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
    112101 *    Infinity and NaN (case insensitively).  On some systems (e.g.,
     
    124113 *    fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
    125114 *    and NAN_WORD1 are used instead.
    126  * #define MULTIPLE_THREADS if the system offers preemptively scheduled
    127  *    multiple threads.  In this case, you must provide (or suitably
    128  *    #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
    129  *    by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
    130  *    in pow5mult, ensures lazy evaluation of only one copy of high
    131  *    powers of 5; omitting this lock would introduce a small
    132  *    probability of wasting memory, but would otherwise be harmless.)
    133  *    You must also invoke freedtoa(s) to free the value s returned by
    134  *    dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
    135115 * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
    136116 *    avoids underflows on inputs whose result does not underflow.
     
    187167#include <wtf/Assertions.h>
    188168#include <wtf/FastMalloc.h>
    189 
    190 #ifndef Omit_Private_Memory
    191 #ifndef PRIVATE_MEM
    192 #define PRIVATE_MEM 2304
    193 #endif
    194 #define PRIVATE_mem ((PRIVATE_MEM + sizeof(double) - 1) / sizeof(double))
    195 static double private_mem[PRIVATE_mem];
    196 static double* pmem_next = private_mem;
    197 #endif
     169#include <wtf/Threading.h>
    198170
    199171#undef IEEE_Arith
     
    246218#ifndef __MATH_H__
    247219#include <math.h>
     220#endif
     221
     222using namespace KJS;
     223
     224#if USE(MULTIPLE_THREADS)
     225Mutex* KJS::s_dtoaP5Mutex;
    248226#endif
    249227
     
    430408#endif
    431409
    432 #ifndef MULTIPLE_THREADS
    433 #define ACQUIRE_DTOA_LOCK(n)    /*nothing*/
    434 #define FREE_DTOA_LOCK(n)    /*nothing*/
    435 #endif
    436 
    437410#define Kmax 15
    438411
     
    443416};
    444417
    445 static Bigint* freelist[Kmax + 1];
    446 
    447418static Bigint* Balloc(int k)
    448419{
    449     Bigint* rv;
    450 
    451     ACQUIRE_DTOA_LOCK(0);
    452     if ((rv = freelist[k])) {
    453         freelist[k] = rv->next;
    454     } else {
    455         int x = 1 << k;
    456 #ifdef Omit_Private_Memory
    457         rv = (Bigint*)fastMalloc(sizeof(Bigint) + (x - 1)*sizeof(uint32_t));
    458 #else
    459         unsigned int len = (sizeof(Bigint) + (x - 1) * sizeof(uint32_t) + sizeof(double) - 1) / sizeof(double);
    460         if (pmem_next - private_mem + len <= (unsigned)PRIVATE_mem) {
    461             rv = (Bigint*)pmem_next;
    462             pmem_next += len;
    463         } else
    464             rv = (Bigint*)fastMalloc(len * sizeof(double));
    465 #endif
    466         rv->k = k;
    467         rv->maxwds = x;
    468     }
    469     FREE_DTOA_LOCK(0);
     420    int x = 1 << k;
     421    Bigint* rv = (Bigint*)fastMalloc(sizeof(Bigint) + (x - 1)*sizeof(uint32_t));
     422    rv->k = k;
     423    rv->maxwds = x;
     424    rv->next = 0;
    470425    rv->sign = rv->wds = 0;
     426
    471427    return rv;
    472428}
     
    474430static void Bfree(Bigint* v)
    475431{
    476     if (v) {
    477         ACQUIRE_DTOA_LOCK(0);
    478         v->next = freelist[v->k];
    479         freelist[v->k] = v;
    480         FREE_DTOA_LOCK(0);
    481     }
     432    fastFree(v);
    482433}
    483434
     
    738689
    739690static Bigint* p5s;
     691static int p5s_count;
    740692
    741693static Bigint* pow5mult(Bigint* b, int k)
    742694{
    743     Bigint *b1, *p5, *p51;
    744     int i;
    745695    static int p05[3] = { 5, 25, 125 };
    746696
    747     if ((i = k & 3))
     697    if (int i = k & 3)
    748698        b = multadd(b, p05[i - 1], 0);
    749699
    750700    if (!(k >>= 2))
    751701        return b;
    752     if (!(p5 = p5s)) {
     702
     703#if USE(MULTIPLE_THREADS)
     704    s_dtoaP5Mutex->lock();
     705#endif
     706    Bigint* p5 = p5s;
     707    if (!p5) {
    753708        /* first time */
    754 #ifdef MULTIPLE_THREADS
    755         ACQUIRE_DTOA_LOCK(1);
    756         if (!(p5 = p5s)) {
    757             p5 = p5s = i2b(625);
    758             p5->next = 0;
    759         }
    760         FREE_DTOA_LOCK(1);
    761 #else
    762709        p5 = p5s = i2b(625);
    763         p5->next = 0;
    764 #endif
    765     }
     710        p5s_count = 1;
     711    }
     712    int p5s_count_local = p5s_count;
     713#if USE(MULTIPLE_THREADS)
     714    s_dtoaP5Mutex->unlock();
     715#endif
     716    int p5s_used = 0;
     717
    766718    for (;;) {
    767719        if (k & 1) {
    768             b1 = mult(b, p5);
     720            Bigint* b1 = mult(b, p5);
    769721            Bfree(b);
    770722            b = b1;
     
    772724        if (!(k >>= 1))
    773725            break;
    774         if (!(p51 = p5->next)) {
    775 #ifdef MULTIPLE_THREADS
    776             ACQUIRE_DTOA_LOCK(1);
    777             if (!(p51 = p5->next)) {
    778                 p51 = p5->next = mult(p5,p5);
    779                 p51->next = 0;
    780             }
    781             FREE_DTOA_LOCK(1);
    782 #else
    783             p51 = p5->next = mult(p5,p5);
    784             p51->next = 0;
    785 #endif
    786         }
    787         p5 = p51;
    788     }
     726
     727        if (++p5s_used == p5s_count_local) {
     728#if USE(MULTIPLE_THREADS)
     729            s_dtoaP5Mutex->lock();
     730#endif
     731            if (p5s_used == p5s_count) {
     732                ASSERT(!p5->next);
     733                p5->next = mult(p5, p5);
     734                ++p5s_count;
     735            }
     736           
     737            p5s_count_local = p5s_count;
     738#if USE(MULTIPLE_THREADS)
     739            s_dtoaP5Mutex->unlock();
     740#endif
     741        }
     742        p5 = p5->next;
     743    }
     744
    789745    return b;
    790746}
     
    792748static Bigint* lshift(Bigint* b, int k)
    793749{
    794     int i, k1, n, n1;
    795     Bigint* b1;
    796     uint32_t *x, *x1, *xe, z;
     750    Bigint* result = b;
    797751
    798752#ifdef Pack_32
    799     n = k >> 5;
    800 #else
    801     n = k >> 4;
    802 #endif
    803     k1 = b->k;
    804     n1 = n + b->wds + 1;
    805     for (i = b->maxwds; n1 > i; i <<= 1)
     753    int n = k >> 5;
     754#else
     755    int n = k >> 4;
     756#endif
     757
     758    int k1 = b->k;
     759    int n1 = n + b->wds + 1;
     760    for (int i = b->maxwds; n1 > i; i <<= 1)
    806761        k1++;
    807     b1 = Balloc(k1);
    808     x1 = b1->x;
    809     for (i = 0; i < n; i++)
    810         *x1++ = 0;
    811     x = b->x;
    812     xe = x + b->wds;
     762    if (b->k < k1)
     763        result = Balloc(k1);
     764
     765    const uint32_t* srcStart = b->x;
     766    uint32_t* dstStart = result->x;
     767    const uint32_t* src = srcStart + b->wds - 1;
     768    uint32_t* dst = dstStart + n1 - 1;
    813769#ifdef Pack_32
    814770    if (k &= 0x1f) {
    815         k1 = 32 - k;
    816         z = 0;
     771        uint32_t hiSubword = 0;
     772        int s = 32 - k;
     773        for (; src >= srcStart; --src) {
     774            *dst-- = hiSubword | *src >> s;
     775            hiSubword = *src << k;
     776        }
     777        *dst = hiSubword;
     778        ASSERT(dst == dstStart + n);
     779        result->wds = b->wds + n + (result->x[n1 - 1] != 0);
     780    }
     781#else
     782    if (k &= 0xf) {
     783        uint32_t hiSubword = 0;
     784        int s = 16 - k;
     785        for (; src >= srcStart; --src) {
     786            *dst-- = hiSubword | *src >> s;
     787            hiSubword = (*src << k) & 0xffff;
     788        }
     789        *dst = hiSubword;
     790        ASSERT(dst == dstStart + n);
     791        result->wds = b->wds + n + (result->x[n1 - 1] != 0);
     792     }
     793 #endif
     794    else {
    817795        do {
    818             *x1++ = *x << k | z;
    819             z = *x++ >> k1;
    820         } while (x < xe);
    821         if ((*x1 = z))
    822             ++n1;
    823     }
    824 #else
    825     if (k &= 0xf) {
    826         k1 = 16 - k;
    827         z = 0;
    828         do {
    829             *x1++ = *x << k  & 0xffff | z;
    830             z = *x++ >> k1;
    831         } while (x < xe);
    832         if ((*x1 = z))
    833             ++n1;
    834     }
    835 #endif
    836     else do {
    837         *x1++ = *x++;
    838     } while (x < xe);
    839     b1->wds = n1 - 1;
    840     Bfree(b);
    841     return b1;
     796            *--dst = *src--;
     797        } while (src >= srcStart);
     798        result->wds = b->wds + n;
     799    }
     800    for (dst = dstStart + n; dst != dstStart; )
     801        *--dst = 0;
     802
     803    if (result != b)
     804        Bfree(b);
     805    return result;
    842806}
    843807
     
    22482212}
    22492213
    2250 #ifndef MULTIPLE_THREADS
     2214#if !USE(MULTIPLE_THREADS)
    22512215static char* dtoa_result;
    22522216#endif
     
    22642228    *r = k;
    22652229    return
    2266 #ifndef MULTIPLE_THREADS
     2230#if !USE(MULTIPLE_THREADS)
    22672231    dtoa_result =
    22682232#endif
     
    22932257    b->maxwds = 1 << (b->k = *(int*)b);
    22942258    Bfree(b);
    2295 #ifndef MULTIPLE_THREADS
     2259#if !USE(MULTIPLE_THREADS)
    22962260    if (s == dtoa_result)
    22972261        dtoa_result = 0;
     
    23872351#endif
    23882352
    2389 #ifndef MULTIPLE_THREADS
     2353#if !USE(MULTIPLE_THREADS)
    23902354    if (dtoa_result) {
    23912355        kjs_freedtoa(dtoa_result);
Note: See TracChangeset for help on using the changeset viewer.