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().
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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
Note: See TracChangeset for help on using the changeset viewer.