📄 jsarray.cpp
字号:
// a toString call raises an exception. for (size_t i = 0; i < lengthNotIncludingUndefined; i++) values[i].second = values[i].first.toString(exec); if (exec->hadException()) return; // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather // than O(N log N).#if HAVE(MERGESORT) mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);#else // FIXME: The qsort library function is likely to not be a stable sort. // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort. qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);#endif // FIXME: If the toString function changed the length of the array, this might be // modifying the vector incorrectly. for (size_t i = 0; i < lengthNotIncludingUndefined; i++) m_storage->m_vector[i] = values[i].first; checkConsistency(SortConsistencyCheck);}struct AVLTreeNodeForArrayCompare { JSValuePtr 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 // the magnitude of the balance factor. int32_t gt; int32_t lt;};struct AVLTreeAbstractorForArrayCompare { typedef int32_t handle; // Handle is an index into m_nodes vector. typedef JSValuePtr key; typedef int32_t size; Vector<AVLTreeNodeForArrayCompare> m_nodes; ExecState* m_exec; JSValuePtr m_compareFunction; CallType m_compareCallType; const CallData* m_compareCallData; JSValuePtr m_globalThisValue; 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; } handle get_greater(handle h) { return m_nodes[h].gt & 0x7FFFFFFF; } void set_greater(handle h, handle gh) { m_nodes[h].gt &= 0x80000000; m_nodes[h].gt |= gh; } int get_balance_factor(handle h) { if (m_nodes[h].gt & 0x80000000) return -1; return static_cast<unsigned>(m_nodes[h].lt) >> 31; } void set_balance_factor(handle h, int bf) { if (bf == 0) { m_nodes[h].lt &= 0x7FFFFFFF; m_nodes[h].gt &= 0x7FFFFFFF; } else { m_nodes[h].lt |= 0x80000000; if (bf < 0) m_nodes[h].gt |= 0x80000000; else m_nodes[h].gt &= 0x7FFFFFFF; } } int compare_key_key(key va, key vb) { ASSERT(!va.isUndefined()); ASSERT(!vb.isUndefined()); 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); return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent. } int compare_key_node(key k, handle h) { return compare_key_key(k, m_nodes[h].value); } int compare_node_node(handle h1, handle h2) { return compare_key_key(m_nodes[h1].value, m_nodes[h2].value); } static handle null() { return 0x7FFFFFFF; }};void JSArray::sort(ExecState* exec, JSValuePtr compareFunction, CallType callType, const CallData& callData){ checkConsistency(); // FIXME: This ignores exceptions raised in the compare function or in toNumber. // The maximum tree depth is compiled in - but the caller is clearly up to no good // if a larger array is passed. ASSERT(m_storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max())); if (m_storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max())) return; if (!m_storage->m_length) return; unsigned usedVectorLength = min(m_storage->m_length, m_storage->m_vectorLength); AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items tree.abstractor().m_exec = exec; tree.abstractor().m_compareFunction = compareFunction; tree.abstractor().m_compareCallType = callType; tree.abstractor().m_compareCallData = &callData; tree.abstractor().m_globalThisValue = exec->globalThisValue(); tree.abstractor().m_nodes.resize(usedVectorLength + (m_storage->m_sparseValueMap ? m_storage->m_sparseValueMap->size() : 0)); if (!tree.abstractor().m_nodes.begin()) { throwOutOfMemoryError(exec); return; } // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified // right out from under us while we're building the tree here. unsigned numDefined = 0; unsigned numUndefined = 0; // 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]; 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]; if (v) { if (v.isUndefined()) ++numUndefined; else { tree.abstractor().m_nodes[numDefined].value = v; tree.insert(numDefined); ++numDefined; } } } unsigned newUsedVectorLength = numDefined + numUndefined; if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) { newUsedVectorLength += map->size(); if (newUsedVectorLength > m_storage->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); return; } } SparseArrayValueMap::iterator end = map->end(); for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) { tree.abstractor().m_nodes[numDefined].value = it->second; tree.insert(numDefined); ++numDefined; } delete map; m_storage->m_sparseValueMap = 0; } ASSERT(tree.abstractor().m_nodes.size() >= numDefined); // FIXME: If the compare function changed the length of the array, the following might be // modifying the vector incorrectly. // Copy the values back into m_storage. AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter; iter.start_iter_least(tree); for (unsigned i = 0; i < numDefined; ++i) { m_storage->m_vector[i] = tree.abstractor().m_nodes[*iter].value; ++iter; } // Put undefined values back in. for (unsigned i = numDefined; i < newUsedVectorLength; ++i) m_storage->m_vector[i] = jsUndefined(); // Ensure that unused values in the vector are zeroed out. for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) m_storage->m_vector[i] = noValue(); m_fastAccessCutoff = newUsedVectorLength; m_storage->m_numValuesInVector = newUsedVectorLength; checkConsistency(SortConsistencyCheck);}void JSArray::fillArgList(ExecState* exec, ArgList& args){ unsigned fastAccessLength = min(m_storage->m_length, m_fastAccessCutoff); unsigned i = 0; for (; i < fastAccessLength; ++i) args.append(getIndex(i)); for (; i < m_storage->m_length; ++i) args.append(get(exec, i));}unsigned JSArray::compactForSorting(){ checkConsistency(); ArrayStorage* storage = m_storage; unsigned usedVectorLength = min(m_storage->m_length, storage->m_vectorLength); unsigned numDefined = 0; unsigned numUndefined = 0; for (; numDefined < usedVectorLength; ++numDefined) { JSValuePtr v = storage->m_vector[numDefined]; if (!v || v.isUndefined()) break; } for (unsigned i = numDefined; i < usedVectorLength; ++i) { JSValuePtr v = storage->m_vector[i]; if (v) { if (v.isUndefined()) ++numUndefined; else storage->m_vector[numDefined++] = v; } } unsigned newUsedVectorLength = numDefined + numUndefined; if (SparseArrayValueMap* map = storage->m_sparseValueMap) { newUsedVectorLength += map->size(); if (newUsedVectorLength > storage->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)) return 0; storage = m_storage; } SparseArrayValueMap::iterator end = map->end(); for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) storage->m_vector[numDefined++] = it->second; delete map; storage->m_sparseValueMap = 0; } for (unsigned i = numDefined; i < newUsedVectorLength; ++i) storage->m_vector[i] = jsUndefined(); for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) storage->m_vector[i] = noValue(); m_fastAccessCutoff = newUsedVectorLength; storage->m_numValuesInVector = newUsedVectorLength; checkConsistency(SortConsistencyCheck); return numDefined;}void* JSArray::lazyCreationData(){ return m_storage->lazyCreationData;}void JSArray::setLazyCreationData(void* d){ m_storage->lazyCreationData = d;}#if CHECK_ARRAY_CONSISTENCYvoid JSArray::checkConsistency(ConsistencyCheckType type){ ASSERT(m_storage); 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]) { 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); 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 <= MAX_ARRAY_INDEX); ASSERT(it->second); if (type != DestructorConsistencyCheck) it->second->type(); // Likely to crash if the object was deallocated. } }}#endifJSArray* 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -