Changeset 36117

Show
Ignore:
Timestamp:
09/05/08 14:51:22 (3 months ago)
Author:
darin@apple.com
Message:

2008-09-05 Darin Adler <darin@apple.com>

Reviewed by Sam Weinig.

1.011x as fast on SunSpider overall
1.028x as fast on SunSpider string tests

For small strings, use a loop rather than calling memcpy. The loop can
be faster because there's no function call overhead, and because it can
assume the pointers are aligned instead of checking that. Currently the
threshold is set at 20 characters, based on some testing on one particular
computer. Later we can tune this for various platforms by setting
USTRING_COPY_CHARS_INLINE_CUTOFF appropriately, but it does no great harm
if not perfectly tuned.

  • kjs/ustring.cpp: (KJS::overflowIndicator): Removed bogus const. (KJS::maxUChars): Ditto. (KJS::copyChars): Added. (KJS::UString::Rep::createCopying): Call copyChars instead of memcpy. Also eliminated need for const_cast. (KJS::UString::expandPreCapacity): Ditto. (KJS::concatenate): Ditto. (KJS::UString::spliceSubstringsWithSeparators): Ditto. (KJS::UString::append): Ditto.
Location:
trunk/JavaScriptCore
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r36114 r36117  
     12008-09-05  Darin Adler  <darin@apple.com> 
     2 
     3        Reviewed by Sam Weinig. 
     4 
     5        - fix https://bugs.webkit.org/show_bug.cgi?id=20671 
     6          JavaScriptCore string manipulation spends too much time in memcpy 
     7 
     8        1.011x as fast on SunSpider overall 
     9        1.028x as fast on SunSpider string tests 
     10 
     11        For small strings, use a loop rather than calling memcpy. The loop can 
     12        be faster because there's no function call overhead, and because it can 
     13        assume the pointers are aligned instead of checking that. Currently the 
     14        threshold is set at 20 characters, based on some testing on one particular 
     15        computer. Later we can tune this for various platforms by setting 
     16        USTRING_COPY_CHARS_INLINE_CUTOFF appropriately, but it does no great harm 
     17        if not perfectly tuned. 
     18 
     19        * kjs/ustring.cpp: 
     20        (KJS::overflowIndicator): Removed bogus const. 
     21        (KJS::maxUChars): Ditto. 
     22        (KJS::copyChars): Added. 
     23        (KJS::UString::Rep::createCopying): Call copyChars instead of memcpy. 
     24        Also eliminated need for const_cast. 
     25        (KJS::UString::expandPreCapacity): Ditto. 
     26        (KJS::concatenate): Ditto. 
     27        (KJS::UString::spliceSubstringsWithSeparators): Ditto. 
     28        (KJS::UString::append): Ditto. 
     29 
    1302008-09-05  Kevin McCullough  <kmccullough@apple.com> 
    231 
  • trunk/JavaScriptCore/kjs/ustring.cpp

    r36006 r36117  
    5252using namespace std; 
    5353 
     54// This can be tuned differently per platform by putting platform #ifs right here. 
     55// If you don't define this macro at all, then copyChars will just call directly 
     56// to memcpy. 
     57#define USTRING_COPY_CHARS_INLINE_CUTOFF 20 
     58 
    5459namespace KJS { 
    55  
     60  
    5661extern const double NaN; 
    5762extern const double Inf; 
    5863 
    59 static inline const size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); } 
    60 static inline const size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); } 
     64static inline size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); } 
     65static inline size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); } 
    6166 
    6267static inline UChar* allocChars(size_t length) 
     
    7479        return 0; 
    7580    return static_cast<UChar*>(tryFastRealloc(buffer, sizeof(UChar) * length)); 
     81} 
     82 
     83static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) 
     84{ 
     85#ifdef USTRING_COPY_CHARS_INLINE_CUTOFF 
     86    if (numCharacters <= USTRING_COPY_CHARS_INLINE_CUTOFF) { 
     87        for (unsigned i = 0; i < numCharacters; ++i) 
     88            destination[i] = source[i]; 
     89        return; 
     90    } 
     91#endif 
     92    memcpy(destination, source, numCharacters * sizeof(UChar)); 
    7693} 
    7794 
     
    177194PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar* d, int l) 
    178195{ 
    179     int sizeInBytes = l * sizeof(UChar); 
    180     UChar* copyD = static_cast<UChar*>(fastMalloc(sizeInBytes)); 
    181     memcpy(copyD, d, sizeInBytes); 
    182  
     196    UChar* copyD = static_cast<UChar*>(fastMalloc(l * sizeof(UChar))); 
     197    copyChars(copyD, d, l); 
    183198    return create(copyD, l); 
    184199} 
     
    458473            return; 
    459474        } 
    460         memcpy(newBuf + delta, r->buf, (r->capacity + r->preCapacity) * sizeof(UChar)); 
     475        copyChars(newBuf + delta, r->buf, r->capacity + r->preCapacity); 
    461476        fastFree(r->buf); 
    462477        r->buf = newBuf; 
     
    556571        if (!a->data() || !x.data()) 
    557572            return 0; 
    558         memcpy(a->data() + aSize, b->data(), bSize * sizeof(UChar)); 
     573        copyChars(a->data() + aSize, b->data(), bSize); 
    559574        PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length); 
    560575 
     
    566581    } 
    567582 
    568     if (-bOffset == b->baseString->usedPreCapacity && bSize >= minShareSize  && 4 * bSize >= aSize) { 
     583    if (-bOffset == b->baseString->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize) { 
    569584        // - b reaches the beginning of its buffer so it qualifies for shared prepend 
    570585        // - also, it's at least a quarter the length of a - prepending to a much shorter 
     
    574589        if (!b->data() || !y.data()) 
    575590            return 0; 
    576         memcpy(b->data() - aSize, a->data(), aSize * sizeof(UChar)); 
     591        copyChars(b->data() - aSize, a->data(), aSize); 
    577592        PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length); 
    578593 
     
    589604    if (!d) 
    590605        return 0; 
    591     memcpy(d, a->data(), aSize * sizeof(UChar)); 
    592     memcpy(d + aSize, b->data(), bSize * sizeof(UChar)); 
     606    copyChars(d, a->data(), aSize); 
     607    copyChars(d + aSize, b->data(), bSize); 
    593608    PassRefPtr<UString::Rep> result = UString::Rep::create(d, length); 
    594609    result->capacity = newCapacity; 
     
    779794    for (int i = 0; i < maxCount; i++) { 
    780795        if (i < rangeCount) { 
    781             memcpy(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length * sizeof(UChar)); 
     796            copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length); 
    782797            bufferPos += substringRanges[i].length; 
    783798        } 
    784799        if (i < separatorCount) { 
    785             memcpy(buffer + bufferPos, separators[i].data(), separators[i].size() * sizeof(UChar)); 
     800            copyChars(buffer + bufferPos, separators[i].data(), separators[i].size()); 
    786801            bufferPos += separators[i].size(); 
    787802        } 
     
    811826        expandCapacity(thisOffset + length); 
    812827        if (data()) { 
    813             memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar)); 
     828            copyChars(m_rep->data() + thisSize, t.data(), tSize); 
    814829            m_rep->len = length; 
    815830            m_rep->_hash = 0; 
     
    819834        expandCapacity(thisOffset + length); 
    820835        if (data()) { 
    821             memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar)); 
     836            copyChars(m_rep->data() + thisSize, t.data(), tSize); 
    822837            m_rep = Rep::create(m_rep, 0, length); 
    823838        } 
     
    829844            makeNull(); 
    830845        else { 
    831             memcpy(d, data(), thisSize * sizeof(UChar)); 
    832             memcpy(const_cast<UChar*>(d + thisSize), t.data(), tSize * sizeof(UChar)); 
     846            copyChars(d, data(), thisSize); 
     847            copyChars(d + thisSize, t.data(), tSize); 
    833848            m_rep = Rep::create(d, length); 
    834849            m_rep->capacity = newCapacity; 
     
    860875        expandCapacity(thisOffset + length); 
    861876        if (data()) { 
    862             memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar)); 
     877            copyChars(m_rep->data() + thisSize, tData, tSize); 
    863878            m_rep->len = length; 
    864879            m_rep->_hash = 0; 
     
    868883        expandCapacity(thisOffset + length); 
    869884        if (data()) { 
    870             memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar)); 
     885            copyChars(m_rep->data() + thisSize, tData, tSize); 
    871886            m_rep = Rep::create(m_rep, 0, length); 
    872887        } 
     
    878893            makeNull(); 
    879894        else { 
    880             memcpy(d, data(), thisSize * sizeof(UChar)); 
    881             memcpy(const_cast<UChar*>(d + thisSize), tData, tSize * sizeof(UChar)); 
     895            copyChars(d, data(), thisSize); 
     896            copyChars(d + thisSize, tData, tSize); 
    882897            m_rep = Rep::create(d, length); 
    883898            m_rep->capacity = newCapacity; 
     
    908923        // this is direct and has refcount of 1 (so we can just alter it directly) 
    909924        expandCapacity(thisOffset + length); 
    910         UChar* d = const_cast<UChar*>(data()); 
     925        UChar* d = m_rep->data(); 
    911926        if (d) { 
    912927            for (int i = 0; i < tSize; ++i) 
     
    918933        // this string reaches the end of the buffer - extend it 
    919934        expandCapacity(thisOffset + length); 
    920         UChar* d = const_cast<UChar*>(data()); 
     935        UChar* d = m_rep->data(); 
    921936        if (d) { 
    922937            for (int i = 0; i < tSize; ++i) 
     
    931946            makeNull(); 
    932947        else { 
    933             memcpy(d, data(), thisSize * sizeof(UChar)); 
     948            copyChars(d, data(), thisSize); 
    934949            for (int i = 0; i < tSize; ++i) 
    935950                d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 
     
    966981        // this is direct and has refcount of 1 (so we can just alter it directly) 
    967982        expandCapacity(thisOffset + length + 1); 
    968         UChar* d = const_cast<UChar*>(data()); 
     983        UChar* d = m_rep->data(); 
    969984        if (d) { 
    970985            d[length] = c; 
     
    975990        // this reaches the end of the string - extend it and share 
    976991        expandCapacity(thisOffset + length + 1); 
    977         UChar* d = const_cast<UChar*>(data()); 
     992        UChar* d = m_rep->data(); 
    978993        if (d) { 
    979994            d[length] = c; 
     
    9871002            makeNull(); 
    9881003        else { 
    989             memcpy(d, data(), length * sizeof(UChar)); 
     1004            copyChars(d, data(), length); 
    9901005            d[length] = c; 
    9911006            m_rep = Rep::create(d, length + 1);