Changeset 31677 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Apr 6, 2008, 11:33:20 PM (17 years ago)
Author:
[email protected]
Message:

Reviewed by Darin.

Make UString thread-safe.

No change on SunSpider total, although individual tests have changed a lot, up to 3%.

  • kjs/InitializeThreading.cpp: (KJS::initializeThreading): Call UString::null() to initialize a static.


  • kjs/identifier.cpp: (KJS::CStringTranslator::translate): (KJS::UCharBufferTranslator::translate): Use "true" for a boolean value instead of 1, because it's C++.
  • kjs/ustring.h: (KJS::CString::adopt): Added a method to create from a char* buffer without copying. (KJS::UString::Rep::ref): Removed an assertion for JSLock::lockCount, as it's no longer necessary to hold JSLock when working with strings. (KJS::UString::Rep::deref): Ditto. (KJS::UString::Rep::isStatic): Added a field to quickly determine that this is an empty or null static string.
  • kjs/ustring.cpp: (KJS::): Removed normalStatBufferSize and statBufferSize, as there is no reason to have such an advanced implementation of a debug-only ascii() method. Removed a long-obsolete comment about UChar. (KJS::UString::Rep::createCopying): Removed an assertion for JSLock::lockCount. (KJS::UString::Rep::create): Ditto. (KJS::UString::Rep::destroy): Ditto. Do not do anything for static null and empty strings, as refcounting is not reliable for those. Reordered branches for a noticeable speed gain - apparently this functiton is hot enough for SunSpider to see an effect from this! (KJS::UString::null): Moved a star, added a comment. (KJS::UString::cstring): Reimplemented to not call ascii(), which is not thread-safe. (KJS::UString::ascii): Simplified statBuffer handling logic. (KJS::UString::toDouble): Use cstring() instead of ascii().
Location:
trunk/JavaScriptCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r31577 r31677  
     12008-04-06  Alexey Proskuryakov  <[email protected]>
     2
     3        Reviewed by Darin.
     4
     5        Make UString thread-safe.
     6
     7        No change on SunSpider total, although individual tests have changed a lot, up to 3%.
     8
     9        * kjs/InitializeThreading.cpp: (KJS::initializeThreading): Call UString::null() to initialize
     10        a static.
     11       
     12        * kjs/identifier.cpp:
     13        (KJS::CStringTranslator::translate):
     14        (KJS::UCharBufferTranslator::translate):
     15        Use "true" for a boolean value instead of 1, because it's C++.
     16
     17        * kjs/ustring.h:
     18        (KJS::CString::adopt): Added a method to create from a char* buffer without copying.
     19        (KJS::UString::Rep::ref): Removed an assertion for JSLock::lockCount, as it's no longer
     20        necessary to hold JSLock when working with strings.
     21        (KJS::UString::Rep::deref): Ditto.
     22        (KJS::UString::Rep::isStatic): Added a field to quickly determine that this is an empty
     23        or null static string.
     24
     25        * kjs/ustring.cpp:
     26        (KJS::): Removed normalStatBufferSize and statBufferSize, as there is no reason to have such
     27        an advanced implementation of a debug-only ascii() method. Removed a long-obsolete comment
     28        about UChar.
     29        (KJS::UString::Rep::createCopying): Removed an assertion for JSLock::lockCount.
     30        (KJS::UString::Rep::create): Ditto.
     31        (KJS::UString::Rep::destroy): Ditto. Do not do anything for static null and empty strings,
     32        as refcounting is not reliable for those. Reordered branches for a noticeable speed gain -
     33        apparently this functiton is hot enough for SunSpider to see an effect from this!
     34        (KJS::UString::null): Moved a star, added a comment.
     35        (KJS::UString::cstring): Reimplemented to not call ascii(), which is not thread-safe.
     36        (KJS::UString::ascii): Simplified statBuffer handling logic.
     37        (KJS::UString::toDouble): Use cstring() instead of ascii().
     38
    1392008-04-02  Mark Rowe  <[email protected]>
    240
  • trunk/JavaScriptCore/kjs/InitializeThreading.cpp

    r31433 r31677  
    3131
    3232#include "dtoa.h"
     33#include "ustring.h"
    3334#include <wtf/Threading.h>
    3435
     
    4142    if (!s_dtoaP5Mutex)
    4243        s_dtoaP5Mutex = new Mutex;
     44    UString::null();
    4345#endif
    4446}
  • trunk/JavaScriptCore/kjs/identifier.cpp

    r31319 r31677  
    127127       
    128128        UString::Rep *r = UString::Rep::create(d, static_cast<int>(length)).releaseRef();
    129         r->isIdentifier = 1;
     129        r->isIdentifier = true;
    130130        r->rc = 0;
    131131        r->_hash = hash;
     
    184184       
    185185        UString::Rep *r = UString::Rep::create(d, buf.length).releaseRef();
    186         r->isIdentifier = 1;
     186        r->isIdentifier = true;
    187187        r->rc = 0;
    188188        r->_hash = hash;
  • trunk/JavaScriptCore/kjs/ustring.cpp

    r30942 r31677  
    111111}
    112112
     113CString CString::adopt(char* c, size_t len)
     114{
     115    CString s;
     116    s.data = c;
     117    s.length = len;
     118   
     119    return s;
     120}
     121
    113122CString &CString::append(const CString &t)
    114123{
     
    163172}
    164173
    165 // Hack here to avoid a global with a constructor; point to an unsigned short instead of a UChar.
     174// These static strings are immutable, except for rc, whose initial value is chosen to reduce the possibility of it becoming zero due to ref/deref not being thread-safe.
    166175static UChar sharedEmptyChar;
    167 UString::Rep UString::Rep::null = { 0, 0, 1, 0, 0, &UString::Rep::null, 0, 0, 0, 0, 0, 0 };
    168 UString::Rep UString::Rep::empty = { 0, 0, 1, 0, 0, &UString::Rep::empty, 0, &sharedEmptyChar, 0, 0, 0, 0 };
    169 const int normalStatBufferSize = 4096;
    170 static char *statBuffer = 0; // FIXME: This buffer is never deallocated.
    171 static int statBufferSize = 0;
     176UString::Rep UString::Rep::null = { 0, 0, INT_MAX / 2, 0, false, true, &UString::Rep::null, 0, 0, 0, 0, 0, 0 };
     177UString::Rep UString::Rep::empty = { 0, 0, INT_MAX / 2, 0, false, true, &UString::Rep::empty, 0, &sharedEmptyChar, 0, 0, 0, 0 };
     178
     179static char* statBuffer = 0; // Only used for debugging via UString::ascii().
    172180
    173181PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar *d, int l)
    174182{
    175   ASSERT(JSLock::lockCount() > 0);
    176 
    177183  int sizeInBytes = l * sizeof(UChar);
    178184  UChar *copyD = static_cast<UChar *>(fastMalloc(sizeInBytes));
     
    184190PassRefPtr<UString::Rep> UString::Rep::create(UChar *d, int l)
    185191{
    186   ASSERT(JSLock::lockCount() > 0);
    187 
    188192  Rep* r = new Rep;
    189193  r->offset = 0;
     
    191195  r->rc = 1;
    192196  r->_hash = 0;
    193   r->isIdentifier = 0;
     197  r->isIdentifier = false;
     198  r->isStatic = false;
    194199  r->baseString = r;
    195200  r->reportedCost = 0;
     
    206211PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<Rep> base, int offset, int length)
    207212{
    208   ASSERT(JSLock::lockCount() > 0);
    209213  ASSERT(base);
    210214
     
    221225  r->rc = 1;
    222226  r->_hash = 0;
    223   r->isIdentifier = 0;
     227  r->isIdentifier = false;
     228  r->isStatic = false;
    224229  r->baseString = base.releaseRef();
    225230  r->reportedCost = 0;
     
    236241void UString::Rep::destroy()
    237242{
    238   ASSERT(JSLock::lockCount() > 0);
    239 
    240   if (isIdentifier)
    241     Identifier::remove(this);
    242   if (baseString != this) {
    243     baseString->deref();
    244   } else {
    245     fastFree(buf);
    246   }
    247   delete this;
     243  // Static null and empty strings can never be destroyed, but we cannot rely on reference counting, because ref/deref are not thread-safe.
     244  if (!isStatic) {
     245    if (isIdentifier)
     246      Identifier::remove(this);
     247    if (baseString == this)
     248      fastFree(buf);
     249    else
     250      baseString->deref();
     251
     252    delete this;
     253  }
    248254}
    249255
     
    519525const UString& UString::null()
    520526{
    521   static UString* n = new UString;
     527  static UString* n = new UString; // Should be called from main thread at least once to be safely initialized.
    522528  return *n;
    523529}
     
    858864CString UString::cstring() const
    859865{
    860   return ascii();
    861 }
    862 
    863 char *UString::ascii() const
    864 {
    865   // Never make the buffer smaller than normalStatBufferSize.
    866   // Thus we almost never need to reallocate.
    867866  int length = size();
    868867  int neededSize = length + 1;
    869   if (neededSize < normalStatBufferSize) {
    870     neededSize = normalStatBufferSize;
    871   }
    872   if (neededSize != statBufferSize) {
    873     delete [] statBuffer;
    874     statBuffer = new char [neededSize];
    875     statBufferSize = neededSize;
    876   }
     868  char* buf = new char[neededSize];
     869 
     870  const UChar* p = data();
     871  char* q = buf;
     872  const UChar* limit = p + length;
     873  while (p != limit) {
     874    *q = static_cast<char>(p[0]);
     875    ++p;
     876    ++q;
     877  }
     878  *q = '\0';
     879 
     880  return CString::adopt(buf, length);
     881}
     882
     883char *UString::ascii() const
     884{
     885  int length = size();
     886  int neededSize = length + 1;
     887  delete[] statBuffer;
     888  statBuffer = new char[neededSize];
    877889 
    878890  const UChar *p = data();
     
    950962    return NaN;
    951963
    952   const char *c = ascii();
     964  CString s = cstring();
     965  const char* c = s.c_str();
    953966
    954967  // skip leading white space
  • trunk/JavaScriptCore/kjs/ustring.h

    r30943 r31677  
    6262    ~CString();
    6363
     64    static CString adopt(char* c, size_t len); // c should be allocated with new[].
     65
    6466    CString &append(const CString &);
    6567    CString &operator=(const char *c);
     
    102104      static unsigned computeHash(const char *);
    103105
    104       Rep* ref() { ASSERT(JSLock::lockCount() > 0); ++rc; return this; }
    105       ALWAYS_INLINE void deref() { ASSERT(JSLock::lockCount() > 0); if (--rc == 0) destroy(); }
     106      Rep* ref() { ++rc; return this; }
     107      ALWAYS_INLINE void deref() { if (--rc == 0) destroy(); }
    106108
    107109      // unshared data
    108110      int offset;
    109111      int len;
    110       int rc;
     112      int rc; // For null and empty static strings, this field does not reflect a correct count, because ref/deref are not thread-safe. A special case in destroy() guarantees that these do not get deleted.
    111113      mutable unsigned _hash;
    112       bool isIdentifier;
     114      bool isIdentifier : 1;
     115      bool isStatic : 1;
    113116      UString::Rep* baseString;
    114117      size_t reportedCost;
     
    223226     * Convert the Unicode string to plain ASCII chars chopping of any higher
    224227     * bytes. This method should only be used for *debugging* purposes as it
    225      * is neither Unicode safe nor free from side effects. In order not to
    226      * waste any memory the char buffer is static and *shared* by all UString
    227      * instances.
     228     * is neither Unicode safe nor free from side effects nor thread-safe.
     229     * In order not to waste any memory the char buffer is static and *shared*
     230     * by all UString instances.
    228231     */
    229232    char* ascii() const;
Note: See TracChangeset for help on using the changeset viewer.