Ignore:
Timestamp:
Feb 13, 2009, 3:28:04 PM (16 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2009-02-13 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.


Fixed <rdar://problem/6584057> Optimize sort by JS numeric comparison
function not to run the comparison function


  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::CodeBlock):
  • bytecode/CodeBlock.h: (JSC::CodeBlock::setIsNumericCompareFunction): (JSC::CodeBlock::isNumericCompareFunction): Added the ability to track whether a CodeBlock performs a sort-like numeric comparison.
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): Set the isNumericCompareFunction bit after compiling.
  • parser/Nodes.cpp: (JSC::FunctionBodyNode::emitBytecode): Fixed a bug that caused us to codegen an extra return at the end of all functions (eek!), since this made it harder / weirder to detect the numeric comparison pattern in bytecode.
  • runtime/ArrayPrototype.cpp: (JSC::arrayProtoFuncSort): Use the isNumericCompareFunction bit to do a faster sort if we can.
  • runtime/FunctionConstructor.cpp: (JSC::extractFunctionBody): (JSC::constructFunction):
  • runtime/FunctionConstructor.h: Renamed and exported extractFunctionBody for use in initializing lazyNumericCompareFunction.
  • runtime/JSArray.cpp: (JSC::compareNumbersForQSort): (JSC::compareByStringPairForQSort): (JSC::JSArray::sortNumeric): (JSC::JSArray::sort):
  • runtime/JSArray.h: Added a fast numeric sort. Renamed ArrayQSortPair to be more specific since we do different kinds of qsort now.
  • runtime/JSGlobalData.cpp: (JSC::JSGlobalData::JSGlobalData): (JSC::JSGlobalData::numericCompareFunction): (JSC::JSGlobalData::ClientData::~ClientData):
  • runtime/JSGlobalData.h: Added helper data for computing the isNumericCompareFunction bit.

LayoutTests:

2009-02-13 Geoffrey Garen <[email protected]>

Reviewed by Sam Weinig.


Added a test for an edge case in <rdar://problem/6584057>.

  • fast/js/resources/sort-non-numbers.js: Added.
  • fast/js/sort-non-numbers.html: Added.
  • fast/js/sort-non-numbers-expected.txt: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/JSArray.cpp

    r40339 r40993  
    618618}
    619619
    620 typedef std::pair<JSValuePtr, UString> ArrayQSortPair;
     620static int compareNumbersForQSort(const void* a, const void* b)
     621{
     622    double da = static_cast<const JSValuePtr*>(a)->uncheckedGetNumber();
     623    double db = static_cast<const JSValuePtr*>(b)->uncheckedGetNumber();
     624    return (da > db) - (da < db);
     625}
     626
     627typedef std::pair<JSValuePtr, UString> ValueStringPair;
    621628
    622629static int compareByStringPairForQSort(const void* a, const void* b)
    623630{
    624     const ArrayQSortPair* va = static_cast<const ArrayQSortPair*>(a);
    625     const ArrayQSortPair* vb = static_cast<const ArrayQSortPair*>(b);
     631    const ValueStringPair* va = static_cast<const ValueStringPair*>(a);
     632    const ValueStringPair* vb = static_cast<const ValueStringPair*>(b);
    626633    return compare(va->second, vb->second);
     634}
     635
     636void JSArray::sortNumeric(ExecState* exec, JSValuePtr compareFunction, CallType callType, const CallData& callData)
     637{
     638    unsigned lengthNotIncludingUndefined = compactForSorting();
     639    if (m_storage->m_sparseValueMap) {
     640        throwOutOfMemoryError(exec);
     641        return;
     642    }
     643
     644    if (!lengthNotIncludingUndefined)
     645        return;
     646       
     647    bool allValuesAreNumbers = true;
     648    size_t size = m_storage->m_numValuesInVector;
     649    for (size_t i = 0; i < size; ++i) {
     650        if (!m_storage->m_vector[i].isNumber()) {
     651            allValuesAreNumbers = false;
     652            break;
     653        }
     654    }
     655
     656    if (!allValuesAreNumbers)
     657        return sort(exec, compareFunction, callType, callData);
     658
     659    // For numeric comparison, which is fast, qsort is faster than mergesort. We
     660    // also don't require mergesort's stability, since there's no user visible
     661    // side-effect from swapping the order of equal primitive values.
     662    qsort(m_storage->m_vector, size, sizeof(JSValuePtr), compareNumbersForQSort);
     663
     664    checkConsistency(SortConsistencyCheck);
    627665}
    628666
     
    643681    // random or otherwise changing results, effectively making compare function inconsistent.
    644682
    645     Vector<ArrayQSortPair> values(lengthNotIncludingUndefined);
     683    Vector<ValueStringPair> values(lengthNotIncludingUndefined);
    646684    if (!values.begin()) {
    647685        throwOutOfMemoryError(exec);
     
    671709
    672710#if HAVE(MERGESORT)
    673     mergesort(values.begin(), values.size(), sizeof(ArrayQSortPair), compareByStringPairForQSort);
     711    mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
    674712#else
    675713    // FIXME: The qsort library function is likely to not be a stable sort.
    676714    // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
    677     qsort(values.begin(), values.size(), sizeof(ArrayQSortPair), compareByStringPairForQSort);
     715    qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
    678716#endif
    679717
Note: See TracChangeset for help on using the changeset viewer.