Changeset 28782 in webkit for trunk/JavaScriptCore/kjs


Ignore:
Timestamp:
Dec 16, 2007, 5:14:36 PM (17 years ago)
Author:
[email protected]
Message:

Fix http://bugs.webkit.org/show_bug.cgi?id=16448 ([GTK] Celtic Kane JavaScript performance on Array test is slow relative to Mac).

Reviewed by Maciej Stachowiak.

  • kjs/array_instance.cpp:

(KJS::compareByStringPairForQSort):
(KJS::ArrayInstance::sort): Convert JSValue's to strings once up front and then sort the
results. This avoids calling toString twice per comparison, but requires a temporary buffer
so we only use this approach in cases where the array being sorted is not too large.

File:
1 edited

Legend:

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

    r28468 r28782  
    5050static const unsigned minDensityMultiplier = 8;
    5151
    52 static const unsigned mergeSortCutoff = 10000;
     52static const unsigned copyingSortCutoff = 50000;
    5353
    5454const ClassInfo ArrayInstance::info = {"Array", 0, 0};
     
    430430}
    431431
     432static int compareByStringPairForQSort(const void* a, const void* b)
     433{
     434    const std::pair<JSValue*, UString>* va = static_cast<const std::pair<JSValue*, UString>*>(a);
     435    const std::pair<JSValue*, UString>* vb = static_cast<const std::pair<JSValue*, UString>*>(b);
     436    return compare(va->second, vb->second);
     437}
     438
    432439static ExecState* execForCompareByStringForQSort = 0;
    433 
    434440static int compareByStringForQSort(const void* a, const void* b)
    435441{
     
    448454    unsigned lengthNotIncludingUndefined = compactForSorting();
    449455
     456    if (lengthNotIncludingUndefined < copyingSortCutoff) {
     457        // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
     458        // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
     459        // buffer.  For large arrays, we fall back to a qsort on the JavaScriptValues to avoid creating copies.
     460
     461        Vector<std::pair<JSValue*, UString> > values(lengthNotIncludingUndefined);
     462        for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
     463            JSValue* value = m_storage->m_vector[i];
     464            ASSERT(!value->isUndefined());
     465            values[i].first = value;
     466            values[i].second = value->toString(exec);
     467        }
     468
     469        // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
     470        // than O(N log N).
     471
     472#if HAVE(MERGESORT)
     473        mergesort(values.begin(), values.size(), sizeof(std::pair<JSValue*, UString>), compareByStringPairForQSort);
     474#else
     475        qsort(values.begin(), values.size(), sizeof(std::pair<JSValue*, UString>), compareByStringPairForQSort);
     476#endif
     477        for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
     478            m_storage->m_vector[i] = values[i].first;
     479        return;
     480    }
     481
    450482    ExecState* oldExec = execForCompareByStringForQSort;
    451483    execForCompareByStringForQSort = exec;
    452 
    453 #if HAVE(MERGESORT)
    454     // Because mergesort usually does fewer compares, it is faster than qsort here.
    455     // However, because it requires extra copies of the storage buffer, don't use it for very
    456     // large arrays.
    457 
    458     // FIXME: Since we sort by string value, a fast algorithm might be to convert all the
    459     // values to string once up front, and then use a radix sort. That would be O(N) rather
    460     // than O(N log N).
    461 
    462     if (lengthNotIncludingUndefined < mergeSortCutoff) {
    463         // During the sort, we could do a garbage collect, and it's important to still
    464         // have references to every object in the array for ArrayInstance::mark.
    465         // The mergesort algorithm does not guarantee this, so we sort a copy rather
    466         // than the original.
    467         size_t size = storageSize(m_vectorLength);
    468         ArrayStorage* copy = static_cast<ArrayStorage*>(fastMalloc(size));
    469         memcpy(copy, m_storage, size);
    470         mergesort(copy->m_vector, lengthNotIncludingUndefined, sizeof(JSValue*), compareByStringForQSort);
    471         fastFree(m_storage);
    472         m_storage = copy;
    473         execForCompareByStringForQSort = oldExec;
    474         return;
    475     }
    476 #endif
    477 
    478484    qsort(m_storage->m_vector, lengthNotIncludingUndefined, sizeof(JSValue*), compareByStringForQSort);
    479485    execForCompareByStringForQSort = oldExec;
     
    529535    // better job of minimizing compares.
    530536
    531     if (lengthNotIncludingUndefined < mergeSortCutoff) {
     537    if (lengthNotIncludingUndefined < copyingSortCutoff) {
    532538        // During the sort, we could do a garbage collect, and it's important to still
    533539        // have references to every object in the array for ArrayInstance::mark.
Note: See TracChangeset for help on using the changeset viewer.