Changeset 36117 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Sep 5, 2008, 2:51:22 PM (17 years ago)
Author:
Darin Adler
Message:

2008-09-05 Darin Adler <Darin Adler>

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 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r36114 r36117  
     12008-09-05  Darin Adler  <[email protected]>
     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  <[email protected]>
    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);
Note: See TracChangeset for help on using the changeset viewer.