X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..4e4e5a6f2694187498445a6ac6f1634ce8141119:/runtime/JSArray.cpp?ds=sidebyside diff --git a/runtime/JSArray.cpp b/runtime/JSArray.cpp index 89a2b45..ae9e038 100644 --- a/runtime/JSArray.cpp +++ b/runtime/JSArray.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2003 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * @@ -24,9 +24,13 @@ #include "JSArray.h" #include "ArrayPrototype.h" +#include "CachedCall.h" +#include "Error.h" +#include "Executable.h" #include "PropertyNameArray.h" #include #include +#include #include #define CHECK_ARRAY_CONSISTENCY 0 @@ -65,9 +69,9 @@ ASSERT_CLASS_FITS_IN_CELL(JSArray); // The definition of MAX_STORAGE_VECTOR_LENGTH is dependant on the definition storageSize // function below - the MAX_STORAGE_VECTOR_LENGTH limit is defined such that the storage -// size calculation cannot overflow. (sizeof(ArrayStorage) - sizeof(JSValuePtr)) + -// (vectorLength * sizeof(JSValuePtr)) must be <= 0xFFFFFFFFU (which is maximum value of size_t). -#define MAX_STORAGE_VECTOR_LENGTH static_cast((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(JSValuePtr))) / sizeof(JSValuePtr)) +// size calculation cannot overflow. (sizeof(ArrayStorage) - sizeof(JSValue)) + +// (vectorLength * sizeof(JSValue)) must be <= 0xFFFFFFFFU (which is maximum value of size_t). +#define MAX_STORAGE_VECTOR_LENGTH static_cast((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(JSValue))) / sizeof(JSValue)) // These values have to be macros to be used in max() and min() without introducing // a PIC branch in Mach-O binaries, see . @@ -90,10 +94,10 @@ static inline size_t storageSize(unsigned vectorLength) // MAX_STORAGE_VECTOR_LENGTH is defined such that provided (vectorLength <= MAX_STORAGE_VECTOR_LENGTH) // - as asserted above - the following calculation cannot overflow. - size_t size = (sizeof(ArrayStorage) - sizeof(JSValuePtr)) + (vectorLength * sizeof(JSValuePtr)); + size_t size = (sizeof(ArrayStorage) - sizeof(JSValue)) + (vectorLength * sizeof(JSValue)); // Assertion to detect integer overflow in previous calculation (should not be possible, provided that // MAX_STORAGE_VECTOR_LENGTH is correctly defined). - ASSERT(((size - (sizeof(ArrayStorage) - sizeof(JSValuePtr))) / sizeof(JSValuePtr) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(JSValuePtr)))); + ASSERT(((size - (sizeof(ArrayStorage) - sizeof(JSValue))) / sizeof(JSValue) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(JSValue)))); return size; } @@ -126,62 +130,65 @@ inline void JSArray::checkConsistency(ConsistencyCheckType) #endif -JSArray::JSArray(PassRefPtr structure) +JSArray::JSArray(NonNullPassRefPtr structure) : JSObject(structure) { unsigned initialCapacity = 0; m_storage = static_cast(fastZeroedMalloc(storageSize(initialCapacity))); - m_fastAccessCutoff = 0; - m_storage->m_vectorLength = initialCapacity; - m_storage->m_length = 0; + m_vectorLength = initialCapacity; checkConsistency(); } -JSArray::JSArray(PassRefPtr structure, unsigned initialLength) +JSArray::JSArray(NonNullPassRefPtr structure, unsigned initialLength) : JSObject(structure) { unsigned initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX); - m_storage = static_cast(fastZeroedMalloc(storageSize(initialCapacity))); - m_fastAccessCutoff = 0; - m_storage->m_vectorLength = initialCapacity; + m_storage = static_cast(fastMalloc(storageSize(initialCapacity))); m_storage->m_length = initialLength; + m_vectorLength = initialCapacity; + m_storage->m_numValuesInVector = 0; + m_storage->m_sparseValueMap = 0; + m_storage->subclassData = 0; + m_storage->reportedMapCapacity = 0; - Heap::heap(this)->reportExtraMemoryCost(initialCapacity * sizeof(JSValuePtr)); + JSValue* vector = m_storage->m_vector; + for (size_t i = 0; i < initialCapacity; ++i) + vector[i] = JSValue(); checkConsistency(); + + Heap::heap(this)->reportExtraMemoryCost(initialCapacity * sizeof(JSValue)); } -JSArray::JSArray(ExecState* exec, PassRefPtr structure, const ArgList& list) +JSArray::JSArray(NonNullPassRefPtr structure, const ArgList& list) : JSObject(structure) { - unsigned length = list.size(); - - m_fastAccessCutoff = length; + unsigned initialCapacity = list.size(); - ArrayStorage* storage = static_cast(fastMalloc(storageSize(length))); - - storage->m_vectorLength = length; - storage->m_numValuesInVector = length; - storage->m_sparseValueMap = 0; - storage->m_length = length; + m_storage = static_cast(fastMalloc(storageSize(initialCapacity))); + m_storage->m_length = initialCapacity; + m_vectorLength = initialCapacity; + m_storage->m_numValuesInVector = initialCapacity; + m_storage->m_sparseValueMap = 0; + m_storage->subclassData = 0; + m_storage->reportedMapCapacity = 0; size_t i = 0; ArgList::const_iterator end = list.end(); for (ArgList::const_iterator it = list.begin(); it != end; ++it, ++i) - storage->m_vector[i] = (*it).jsValue(exec); - - m_storage = storage; - - Heap::heap(this)->reportExtraMemoryCost(storageSize(length)); + m_storage->m_vector[i] = *it; checkConsistency(); + + Heap::heap(this)->reportExtraMemoryCost(storageSize(initialCapacity)); } JSArray::~JSArray() { + ASSERT(vptr() == JSGlobalData::jsArrayVPtr); checkConsistency(DestructorConsistencyCheck); delete m_storage->m_sparseValueMap; @@ -198,8 +205,8 @@ bool JSArray::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot return false; } - if (i < storage->m_vectorLength) { - JSValuePtr& valueSlot = storage->m_vector[i]; + if (i < m_vectorLength) { + JSValue& valueSlot = storage->m_vector[i]; if (valueSlot) { slot.setValueSlot(&valueSlot); return true; @@ -214,7 +221,7 @@ bool JSArray::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot } } - return false; + return JSObject::getOwnPropertySlot(exec, Identifier::from(exec, i), slot); } bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) @@ -232,8 +239,39 @@ bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName return JSObject::getOwnPropertySlot(exec, propertyName, slot); } +bool JSArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + if (propertyName == exec->propertyNames().length) { + descriptor.setDescriptor(jsNumber(exec, length()), DontDelete | DontEnum); + return true; + } + + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex) { + if (i >= m_storage->m_length) + return false; + if (i < m_vectorLength) { + JSValue& value = m_storage->m_vector[i]; + if (value) { + descriptor.setDescriptor(value, 0); + return true; + } + } else if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) { + if (i >= MIN_SPARSE_ARRAY_INDEX) { + SparseArrayValueMap::iterator it = map->find(i); + if (it != map->end()) { + descriptor.setDescriptor(it->second, 0); + return true; + } + } + } + } + return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); +} + // ECMA 15.4.5.1 -void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValuePtr value, PutPropertySlot& slot) +void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { bool isArrayIndex; unsigned i = propertyName.toArrayIndex(&isArrayIndex); @@ -255,7 +293,7 @@ void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValuePtr va JSObject::put(exec, propertyName, value, slot); } -void JSArray::put(ExecState* exec, unsigned i, JSValuePtr value) +void JSArray::put(ExecState* exec, unsigned i, JSValue value) { checkConsistency(); @@ -265,16 +303,15 @@ void JSArray::put(ExecState* exec, unsigned i, JSValuePtr value) m_storage->m_length = length; } - if (i < m_storage->m_vectorLength) { - JSValuePtr& valueSlot = m_storage->m_vector[i]; + if (i < m_vectorLength) { + JSValue& valueSlot = m_storage->m_vector[i]; if (valueSlot) { valueSlot = value; checkConsistency(); return; } valueSlot = value; - if (++m_storage->m_numValuesInVector == m_storage->m_length) - m_fastAccessCutoff = m_storage->m_length; + ++m_storage->m_numValuesInVector; checkConsistency(); return; } @@ -282,7 +319,7 @@ void JSArray::put(ExecState* exec, unsigned i, JSValuePtr value) putSlowCase(exec, i, value); } -NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValuePtr value) +NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue value) { ArrayStorage* storage = m_storage; SparseArrayValueMap* map = storage->m_sparseValueMap; @@ -295,13 +332,24 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValuePtr v } // We miss some cases where we could compact the storage, such as a large array that is being filled from the end - // (which will only be compacted as we reach indices that are less than cutoff) - but this makes the check much faster. + // (which will only be compacted as we reach indices that are less than MIN_SPARSE_ARRAY_INDEX) - but this makes the check much faster. if ((i > MAX_STORAGE_VECTOR_INDEX) || !isDenseEnoughForVector(i + 1, storage->m_numValuesInVector + 1)) { if (!map) { map = new SparseArrayValueMap; storage->m_sparseValueMap = map; } - map->set(i, value); + + pair result = map->add(i, value); + if (!result.second) { // pre-existing entry + result.first->second = value; + return; + } + + size_t capacity = map->capacity(); + if (capacity != storage->reportedMapCapacity) { + Heap::heap(this)->reportExtraMemoryCost((capacity - storage->reportedMapCapacity) * (sizeof(unsigned) + sizeof(JSValue))); + storage->reportedMapCapacity = capacity; + } return; } } @@ -312,8 +360,7 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValuePtr v if (increaseVectorLength(i + 1)) { storage = m_storage; storage->m_vector[i] = value; - if (++storage->m_numValuesInVector == storage->m_length) - m_fastAccessCutoff = storage->m_length; + ++storage->m_numValuesInVector; checkConsistency(); } else throwOutOfMemoryError(exec); @@ -323,7 +370,7 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValuePtr v // Decide how many values it would be best to move from the map. unsigned newNumValuesInVector = storage->m_numValuesInVector + 1; unsigned newVectorLength = increasedVectorLength(i + 1); - for (unsigned j = max(storage->m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) + for (unsigned j = max(m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) newNumValuesInVector += map->contains(j); if (i >= MIN_SPARSE_ARRAY_INDEX) newNumValuesInVector -= map->contains(i); @@ -341,36 +388,35 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValuePtr v } } - storage = static_cast(tryFastRealloc(storage, storageSize(newVectorLength))); - if (!storage) { + if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) { throwOutOfMemoryError(exec); return; } - unsigned vectorLength = storage->m_vectorLength; - - Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); + unsigned vectorLength = m_vectorLength; if (newNumValuesInVector == storage->m_numValuesInVector + 1) { for (unsigned j = vectorLength; j < newVectorLength; ++j) - storage->m_vector[j] = noValue(); + storage->m_vector[j] = JSValue(); if (i > MIN_SPARSE_ARRAY_INDEX) map->remove(i); } else { for (unsigned j = vectorLength; j < max(vectorLength, MIN_SPARSE_ARRAY_INDEX); ++j) - storage->m_vector[j] = noValue(); + storage->m_vector[j] = JSValue(); for (unsigned j = max(vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) storage->m_vector[j] = map->take(j); } storage->m_vector[i] = value; - storage->m_vectorLength = newVectorLength; + m_vectorLength = newVectorLength; storage->m_numValuesInVector = newNumValuesInVector; m_storage = storage; checkConsistency(); + + Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); } bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName) @@ -392,16 +438,14 @@ bool JSArray::deleteProperty(ExecState* exec, unsigned i) ArrayStorage* storage = m_storage; - if (i < storage->m_vectorLength) { - JSValuePtr& valueSlot = storage->m_vector[i]; + if (i < m_vectorLength) { + JSValue& valueSlot = storage->m_vector[i]; if (!valueSlot) { checkConsistency(); return false; } - valueSlot = noValue(); + valueSlot = JSValue(); --storage->m_numValuesInVector; - if (m_fastAccessCutoff > i) - m_fastAccessCutoff = i; checkConsistency(); return true; } @@ -425,7 +469,7 @@ bool JSArray::deleteProperty(ExecState* exec, unsigned i) return false; } -void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { // FIXME: Filling PropertyNameArray with an identifier for every integer // is incredibly inefficient for large arrays. We need a different approach, @@ -433,7 +477,7 @@ void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames ArrayStorage* storage = m_storage; - unsigned usedVectorLength = min(storage->m_length, storage->m_vectorLength); + unsigned usedVectorLength = min(storage->m_length, m_vectorLength); for (unsigned i = 0; i < usedVectorLength; ++i) { if (storage->m_vector[i]) propertyNames.add(Identifier::from(exec, i)); @@ -445,7 +489,10 @@ void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames propertyNames.add(Identifier::from(exec, it->first)); } - JSObject::getPropertyNames(exec, propertyNames); + if (mode == IncludeDontEnumProperties) + propertyNames.add(exec->propertyNames().length); + + JSObject::getOwnPropertyNames(exec, propertyNames, mode); } bool JSArray::increaseVectorLength(unsigned newLength) @@ -455,22 +502,23 @@ bool JSArray::increaseVectorLength(unsigned newLength) ArrayStorage* storage = m_storage; - unsigned vectorLength = storage->m_vectorLength; + unsigned vectorLength = m_vectorLength; ASSERT(newLength > vectorLength); ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX); unsigned newVectorLength = increasedVectorLength(newLength); - storage = static_cast(tryFastRealloc(storage, storageSize(newVectorLength))); - if (!storage) + if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) return false; - Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); - storage->m_vectorLength = newVectorLength; + m_vectorLength = newVectorLength; for (unsigned i = vectorLength; i < newVectorLength; ++i) - storage->m_vector[i] = noValue(); + storage->m_vector[i] = JSValue(); m_storage = storage; + + Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); + return true; } @@ -483,14 +531,11 @@ void JSArray::setLength(unsigned newLength) unsigned length = m_storage->m_length; if (newLength < length) { - if (m_fastAccessCutoff > newLength) - m_fastAccessCutoff = newLength; - - unsigned usedVectorLength = min(length, storage->m_vectorLength); + unsigned usedVectorLength = min(length, m_vectorLength); for (unsigned i = newLength; i < usedVectorLength; ++i) { - JSValuePtr& valueSlot = storage->m_vector[i]; + JSValue& valueSlot = storage->m_vector[i]; bool hadValue = valueSlot; - valueSlot = noValue(); + valueSlot = JSValue(); storage->m_numValuesInVector -= hadValue; } @@ -513,7 +558,7 @@ void JSArray::setLength(unsigned newLength) checkConsistency(); } -JSValuePtr JSArray::pop() +JSValue JSArray::pop() { checkConsistency(); @@ -523,22 +568,15 @@ JSValuePtr JSArray::pop() --length; - JSValuePtr result; - - if (m_fastAccessCutoff > length) { - JSValuePtr& valueSlot = m_storage->m_vector[length]; - result = valueSlot; - ASSERT(result); - valueSlot = noValue(); - --m_storage->m_numValuesInVector; - m_fastAccessCutoff = length; - } else if (length < m_storage->m_vectorLength) { - JSValuePtr& valueSlot = m_storage->m_vector[length]; - result = valueSlot; - valueSlot = noValue(); - if (result) + JSValue result; + + if (length < m_vectorLength) { + JSValue& valueSlot = m_storage->m_vector[length]; + if (valueSlot) { --m_storage->m_numValuesInVector; - else + result = valueSlot; + valueSlot = JSValue(); + } else result = jsUndefined(); } else { result = jsUndefined(); @@ -562,15 +600,14 @@ JSValuePtr JSArray::pop() return result; } -void JSArray::push(ExecState* exec, JSValuePtr value) +void JSArray::push(ExecState* exec, JSValue value) { checkConsistency(); - if (m_storage->m_length < m_storage->m_vectorLength) { - ASSERT(!m_storage->m_vector[m_storage->m_length]); + if (m_storage->m_length < m_vectorLength) { m_storage->m_vector[m_storage->m_length] = value; - if (++m_storage->m_numValuesInVector == ++m_storage->m_length) - m_fastAccessCutoff = m_storage->m_length; + ++m_storage->m_numValuesInVector; + ++m_storage->m_length; checkConsistency(); return; } @@ -580,8 +617,8 @@ void JSArray::push(ExecState* exec, JSValuePtr value) if (!map || map->isEmpty()) { if (increaseVectorLength(m_storage->m_length + 1)) { m_storage->m_vector[m_storage->m_length] = value; - if (++m_storage->m_numValuesInVector == ++m_storage->m_length) - m_fastAccessCutoff = m_storage->m_length; + ++m_storage->m_numValuesInVector; + ++m_storage->m_length; checkConsistency(); return; } @@ -594,37 +631,19 @@ void JSArray::push(ExecState* exec, JSValuePtr value) putSlowCase(exec, m_storage->m_length++, value); } -void JSArray::mark() +void JSArray::markChildren(MarkStack& markStack) { - JSObject::mark(); - - ArrayStorage* storage = m_storage; - - unsigned usedVectorLength = min(storage->m_length, storage->m_vectorLength); - for (unsigned i = 0; i < usedVectorLength; ++i) { - JSValuePtr value = storage->m_vector[i]; - if (value && !value.marked()) - value.mark(); - } - - if (SparseArrayValueMap* map = storage->m_sparseValueMap) { - SparseArrayValueMap::iterator end = map->end(); - for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) { - JSValuePtr value = it->second; - if (!value.marked()) - value.mark(); - } - } + markChildrenDirect(markStack); } static int compareNumbersForQSort(const void* a, const void* b) { - double da = static_cast(a)->uncheckedGetNumber(); - double db = static_cast(b)->uncheckedGetNumber(); + double da = static_cast(a)->uncheckedGetNumber(); + double db = static_cast(b)->uncheckedGetNumber(); return (da > db) - (da < db); } -typedef std::pair ValueStringPair; +typedef std::pair ValueStringPair; static int compareByStringPairForQSort(const void* a, const void* b) { @@ -633,7 +652,7 @@ static int compareByStringPairForQSort(const void* a, const void* b) return compare(va->second, vb->second); } -void JSArray::sortNumeric(ExecState* exec, JSValuePtr compareFunction, CallType callType, const CallData& callData) +void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { unsigned lengthNotIncludingUndefined = compactForSorting(); if (m_storage->m_sparseValueMap) { @@ -659,7 +678,7 @@ void JSArray::sortNumeric(ExecState* exec, JSValuePtr compareFunction, CallType // For numeric comparison, which is fast, qsort is faster than mergesort. We // also don't require mergesort's stability, since there's no user visible // side-effect from swapping the order of equal primitive values. - qsort(m_storage->m_vector, size, sizeof(JSValuePtr), compareNumbersForQSort); + qsort(m_storage->m_vector, size, sizeof(JSValue), compareNumbersForQSort); checkConsistency(SortConsistencyCheck); } @@ -687,7 +706,7 @@ void JSArray::sort(ExecState* exec) } for (size_t i = 0; i < lengthNotIncludingUndefined; i++) { - JSValuePtr value = m_storage->m_vector[i]; + JSValue value = m_storage->m_vector[i]; ASSERT(!value.isUndefined()); values[i].first = value; } @@ -725,7 +744,7 @@ void JSArray::sort(ExecState* exec) } struct AVLTreeNodeForArrayCompare { - JSValuePtr value; + JSValue value; // Child pointers. The high bit of gt is robbed and used as the // balance factor sign. The high bit of lt is robbed and used as @@ -736,15 +755,16 @@ struct AVLTreeNodeForArrayCompare { struct AVLTreeAbstractorForArrayCompare { typedef int32_t handle; // Handle is an index into m_nodes vector. - typedef JSValuePtr key; + typedef JSValue key; typedef int32_t size; Vector m_nodes; ExecState* m_exec; - JSValuePtr m_compareFunction; + JSValue m_compareFunction; CallType m_compareCallType; const CallData* m_compareCallData; - JSValuePtr m_globalThisValue; + JSValue m_globalThisValue; + OwnPtr m_cachedCall; handle get_less(handle h) { return m_nodes[h].lt & 0x7FFFFFFF; } void set_less(handle h, handle lh) { m_nodes[h].lt &= 0x80000000; m_nodes[h].lt |= lh; } @@ -780,10 +800,18 @@ struct AVLTreeAbstractorForArrayCompare { if (m_exec->hadException()) return 1; - ArgList arguments; - arguments.append(va); - arguments.append(vb); - double compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, m_globalThisValue, arguments).toNumber(m_exec); + double compareResult; + if (m_cachedCall) { + m_cachedCall->setThis(m_globalThisValue); + m_cachedCall->setArgument(0, va); + m_cachedCall->setArgument(1, vb); + compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame(m_exec)); + } else { + MarkedArgumentBuffer arguments; + arguments.append(va); + arguments.append(vb); + compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, m_globalThisValue, arguments).toNumber(m_exec); + } return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent. } @@ -793,7 +821,7 @@ struct AVLTreeAbstractorForArrayCompare { static handle null() { return 0x7FFFFFFF; } }; -void JSArray::sort(ExecState* exec, JSValuePtr compareFunction, CallType callType, const CallData& callData) +void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { checkConsistency(); @@ -808,7 +836,7 @@ void JSArray::sort(ExecState* exec, JSValuePtr compareFunction, CallType callTyp if (!m_storage->m_length) return; - unsigned usedVectorLength = min(m_storage->m_length, m_storage->m_vectorLength); + unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength); AVLTree tree; // Depth 44 is enough for 2^31 items tree.abstractor().m_exec = exec; @@ -818,6 +846,9 @@ void JSArray::sort(ExecState* exec, JSValuePtr compareFunction, CallType callTyp tree.abstractor().m_globalThisValue = exec->globalThisValue(); tree.abstractor().m_nodes.resize(usedVectorLength + (m_storage->m_sparseValueMap ? m_storage->m_sparseValueMap->size() : 0)); + if (callType == CallTypeJS) + tree.abstractor().m_cachedCall.set(new CachedCall(exec, asFunction(compareFunction), 2, exec->exceptionSlot())); + if (!tree.abstractor().m_nodes.begin()) { throwOutOfMemoryError(exec); return; @@ -831,14 +862,14 @@ void JSArray::sort(ExecState* exec, JSValuePtr compareFunction, CallType callTyp // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree. for (; numDefined < usedVectorLength; ++numDefined) { - JSValuePtr v = m_storage->m_vector[numDefined]; + JSValue v = m_storage->m_vector[numDefined]; if (!v || v.isUndefined()) break; tree.abstractor().m_nodes[numDefined].value = v; tree.insert(numDefined); } for (unsigned i = numDefined; i < usedVectorLength; ++i) { - JSValuePtr v = m_storage->m_vector[i]; + JSValue v = m_storage->m_vector[i]; if (v) { if (v.isUndefined()) ++numUndefined; @@ -854,7 +885,7 @@ void JSArray::sort(ExecState* exec, JSValuePtr compareFunction, CallType callTyp if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) { newUsedVectorLength += map->size(); - if (newUsedVectorLength > m_storage->m_vectorLength) { + if (newUsedVectorLength > m_vectorLength) { // Check that it is possible to allocate an array large enough to hold all the entries. if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) { throwOutOfMemoryError(exec); @@ -892,42 +923,65 @@ void JSArray::sort(ExecState* exec, JSValuePtr compareFunction, CallType callTyp // Ensure that unused values in the vector are zeroed out. for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) - m_storage->m_vector[i] = noValue(); + m_storage->m_vector[i] = JSValue(); - m_fastAccessCutoff = newUsedVectorLength; m_storage->m_numValuesInVector = newUsedVectorLength; checkConsistency(SortConsistencyCheck); } -void JSArray::fillArgList(ExecState* exec, ArgList& args) +void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) { - unsigned fastAccessLength = min(m_storage->m_length, m_fastAccessCutoff); + JSValue* vector = m_storage->m_vector; + unsigned vectorEnd = min(m_storage->m_length, m_vectorLength); unsigned i = 0; - for (; i < fastAccessLength; ++i) - args.append(getIndex(i)); + for (; i < vectorEnd; ++i) { + JSValue& v = vector[i]; + if (!v) + break; + args.append(v); + } + for (; i < m_storage->m_length; ++i) args.append(get(exec, i)); } +void JSArray::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize) +{ + ASSERT(m_storage->m_length >= maxSize); + UNUSED_PARAM(maxSize); + JSValue* vector = m_storage->m_vector; + unsigned vectorEnd = min(maxSize, m_vectorLength); + unsigned i = 0; + for (; i < vectorEnd; ++i) { + JSValue& v = vector[i]; + if (!v) + break; + buffer[i] = v; + } + + for (; i < maxSize; ++i) + buffer[i] = get(exec, i); +} + unsigned JSArray::compactForSorting() { checkConsistency(); ArrayStorage* storage = m_storage; - unsigned usedVectorLength = min(m_storage->m_length, storage->m_vectorLength); + unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength); unsigned numDefined = 0; unsigned numUndefined = 0; for (; numDefined < usedVectorLength; ++numDefined) { - JSValuePtr v = storage->m_vector[numDefined]; + JSValue v = storage->m_vector[numDefined]; if (!v || v.isUndefined()) break; } for (unsigned i = numDefined; i < usedVectorLength; ++i) { - JSValuePtr v = storage->m_vector[i]; + JSValue v = storage->m_vector[i]; if (v) { if (v.isUndefined()) ++numUndefined; @@ -940,7 +994,7 @@ unsigned JSArray::compactForSorting() if (SparseArrayValueMap* map = storage->m_sparseValueMap) { newUsedVectorLength += map->size(); - if (newUsedVectorLength > storage->m_vectorLength) { + if (newUsedVectorLength > m_vectorLength) { // Check that it is possible to allocate an array large enough to hold all the entries - if not, // exception is thrown by caller. if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) @@ -959,9 +1013,8 @@ unsigned JSArray::compactForSorting() for (unsigned i = numDefined; i < newUsedVectorLength; ++i) storage->m_vector[i] = jsUndefined(); for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) - storage->m_vector[i] = noValue(); + storage->m_vector[i] = JSValue(); - m_fastAccessCutoff = newUsedVectorLength; storage->m_numValuesInVector = newUsedVectorLength; checkConsistency(SortConsistencyCheck); @@ -969,14 +1022,14 @@ unsigned JSArray::compactForSorting() return numDefined; } -void* JSArray::lazyCreationData() +void* JSArray::subclassData() const { - return m_storage->lazyCreationData; + return m_storage->subclassData; } -void JSArray::setLazyCreationData(void* d) +void JSArray::setSubclassData(void* d) { - m_storage->lazyCreationData = d; + m_storage->subclassData = d; } #if CHECK_ARRAY_CONSISTENCY @@ -987,30 +1040,27 @@ void JSArray::checkConsistency(ConsistencyCheckType type) if (type == SortConsistencyCheck) ASSERT(!m_storage->m_sparseValueMap); - ASSERT(m_fastAccessCutoff <= m_storage->m_length); - ASSERT(m_fastAccessCutoff <= m_storage->m_numValuesInVector); - unsigned numValuesInVector = 0; - for (unsigned i = 0; i < m_storage->m_vectorLength; ++i) { - if (JSValuePtr value = m_storage->m_vector[i]) { + for (unsigned i = 0; i < m_vectorLength; ++i) { + if (JSValue value = m_storage->m_vector[i]) { ASSERT(i < m_storage->m_length); if (type != DestructorConsistencyCheck) value->type(); // Likely to crash if the object was deallocated. ++numValuesInVector; } else { - ASSERT(i >= m_fastAccessCutoff); if (type == SortConsistencyCheck) ASSERT(i >= m_storage->m_numValuesInVector); } } ASSERT(numValuesInVector == m_storage->m_numValuesInVector); + ASSERT(numValuesInVector <= m_storage->m_length); if (m_storage->m_sparseValueMap) { SparseArrayValueMap::iterator end = m_storage->m_sparseValueMap->end(); for (SparseArrayValueMap::iterator it = m_storage->m_sparseValueMap->begin(); it != end; ++it) { unsigned index = it->first; ASSERT(index < m_storage->m_length); - ASSERT(index >= m_storage->m_vectorLength); + ASSERT(index >= m_vectorLength); ASSERT(index <= MAX_ARRAY_INDEX); ASSERT(it->second); if (type != DestructorConsistencyCheck) @@ -1021,26 +1071,4 @@ void JSArray::checkConsistency(ConsistencyCheckType type) #endif -JSArray* constructEmptyArray(ExecState* exec) -{ - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); -} - -JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) -{ - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength); -} - -JSArray* constructArray(ExecState* exec, JSValuePtr singleItemValue) -{ - ArgList values; - values.append(singleItemValue); - return new (exec) JSArray(exec, exec->lexicalGlobalObject()->arrayStructure(), values); -} - -JSArray* constructArray(ExecState* exec, const ArgList& values) -{ - return new (exec) JSArray(exec, exec->lexicalGlobalObject()->arrayStructure(), values); -} - } // namespace JSC