📄 jsarray.cpp
字号:
unsigned vectorLength = storage->m_vectorLength; Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); if (newNumValuesInVector == storage->m_numValuesInVector + 1) { for (unsigned j = vectorLength; j < newVectorLength; ++j) storage->m_vector[j] = noValue(); 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(); 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; storage->m_numValuesInVector = newNumValuesInVector; m_storage = storage; checkConsistency();}bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName){ bool isArrayIndex; unsigned i = propertyName.toArrayIndex(&isArrayIndex); if (isArrayIndex) return deleteProperty(exec, i); if (propertyName == exec->propertyNames().length) return false; return JSObject::deleteProperty(exec, propertyName);}bool JSArray::deleteProperty(ExecState* exec, unsigned i){ checkConsistency(); ArrayStorage* storage = m_storage; if (i < storage->m_vectorLength) { JSValuePtr& valueSlot = storage->m_vector[i]; if (!valueSlot) { checkConsistency(); return false; } valueSlot = noValue(); --storage->m_numValuesInVector; if (m_fastAccessCutoff > i) m_fastAccessCutoff = i; checkConsistency(); return true; } if (SparseArrayValueMap* map = storage->m_sparseValueMap) { if (i >= MIN_SPARSE_ARRAY_INDEX) { SparseArrayValueMap::iterator it = map->find(i); if (it != map->end()) { map->remove(it); checkConsistency(); return true; } } } checkConsistency(); if (i > MAX_ARRAY_INDEX) return deleteProperty(exec, Identifier::from(exec, i)); return false;}void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames){ // FIXME: Filling PropertyNameArray with an identifier for every integer // is incredibly inefficient for large arrays. We need a different approach, // which almost certainly means a different structure for PropertyNameArray. ArrayStorage* storage = m_storage; unsigned usedVectorLength = min(storage->m_length, storage->m_vectorLength); for (unsigned i = 0; i < usedVectorLength; ++i) { if (storage->m_vector[i]) propertyNames.add(Identifier::from(exec, i)); } if (SparseArrayValueMap* map = storage->m_sparseValueMap) { SparseArrayValueMap::iterator end = map->end(); for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) propertyNames.add(Identifier::from(exec, it->first)); } JSObject::getPropertyNames(exec, propertyNames);}bool JSArray::increaseVectorLength(unsigned newLength){ // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map // to the vector. Callers have to account for that, because they can do it more efficiently. ArrayStorage* storage = m_storage; unsigned vectorLength = storage->m_vectorLength; ASSERT(newLength > vectorLength); ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX); unsigned newVectorLength = increasedVectorLength(newLength); storage = static_cast<ArrayStorage*>(tryFastRealloc(storage, storageSize(newVectorLength))); if (!storage) return false; Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); storage->m_vectorLength = newVectorLength; for (unsigned i = vectorLength; i < newVectorLength; ++i) storage->m_vector[i] = noValue(); m_storage = storage; return true;}void JSArray::setLength(unsigned newLength){ checkConsistency(); ArrayStorage* storage = m_storage; unsigned length = m_storage->m_length; if (newLength < length) { if (m_fastAccessCutoff > newLength) m_fastAccessCutoff = newLength; unsigned usedVectorLength = min(length, storage->m_vectorLength); for (unsigned i = newLength; i < usedVectorLength; ++i) { JSValuePtr& valueSlot = storage->m_vector[i]; bool hadValue = valueSlot; valueSlot = noValue(); storage->m_numValuesInVector -= hadValue; } if (SparseArrayValueMap* map = storage->m_sparseValueMap) { SparseArrayValueMap copy = *map; SparseArrayValueMap::iterator end = copy.end(); for (SparseArrayValueMap::iterator it = copy.begin(); it != end; ++it) { if (it->first >= newLength) map->remove(it->first); } if (map->isEmpty()) { delete map; storage->m_sparseValueMap = 0; } } } m_storage->m_length = newLength; checkConsistency();}JSValuePtr JSArray::pop(){ checkConsistency(); unsigned length = m_storage->m_length; if (!length) return jsUndefined(); --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) --m_storage->m_numValuesInVector; else result = jsUndefined(); } else { result = jsUndefined(); if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) { SparseArrayValueMap::iterator it = map->find(length); if (it != map->end()) { result = it->second; map->remove(it); if (map->isEmpty()) { delete map; m_storage->m_sparseValueMap = 0; } } } } m_storage->m_length = length; checkConsistency(); return result;}void JSArray::push(ExecState* exec, JSValuePtr value){ checkConsistency(); if (m_storage->m_length < m_storage->m_vectorLength) { ASSERT(!m_storage->m_vector[m_storage->m_length]); m_storage->m_vector[m_storage->m_length] = value; if (++m_storage->m_numValuesInVector == ++m_storage->m_length) m_fastAccessCutoff = m_storage->m_length; checkConsistency(); return; } if (m_storage->m_length < MIN_SPARSE_ARRAY_INDEX) { SparseArrayValueMap* map = m_storage->m_sparseValueMap; 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; checkConsistency(); return; } checkConsistency(); throwOutOfMemoryError(exec); return; } } putSlowCase(exec, m_storage->m_length++, value);}void JSArray::mark(){ 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(); } }}static int compareNumbersForQSort(const void* a, const void* b){ double da = static_cast<const JSValuePtr*>(a)->uncheckedGetNumber(); double db = static_cast<const JSValuePtr*>(b)->uncheckedGetNumber(); return (da > db) - (da < db);}typedef std::pair<JSValuePtr, UString> ValueStringPair;static int compareByStringPairForQSort(const void* a, const void* b){ const ValueStringPair* va = static_cast<const ValueStringPair*>(a); const ValueStringPair* vb = static_cast<const ValueStringPair*>(b); return compare(va->second, vb->second);}void JSArray::sortNumeric(ExecState* exec, JSValuePtr compareFunction, CallType callType, const CallData& callData){ unsigned lengthNotIncludingUndefined = compactForSorting(); if (m_storage->m_sparseValueMap) { throwOutOfMemoryError(exec); return; } if (!lengthNotIncludingUndefined) return; bool allValuesAreNumbers = true; size_t size = m_storage->m_numValuesInVector; for (size_t i = 0; i < size; ++i) { if (!m_storage->m_vector[i].isNumber()) { allValuesAreNumbers = false; break; } } if (!allValuesAreNumbers) return sort(exec, compareFunction, callType, callData); // 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); checkConsistency(SortConsistencyCheck);}void JSArray::sort(ExecState* exec){ unsigned lengthNotIncludingUndefined = compactForSorting(); if (m_storage->m_sparseValueMap) { throwOutOfMemoryError(exec); return; } if (!lengthNotIncludingUndefined) return; // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that. // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return // random or otherwise changing results, effectively making compare function inconsistent. Vector<ValueStringPair> values(lengthNotIncludingUndefined); if (!values.begin()) { throwOutOfMemoryError(exec); return; } for (size_t i = 0; i < lengthNotIncludingUndefined; i++) { JSValuePtr value = m_storage->m_vector[i]; ASSERT(!value.isUndefined()); values[i].first = value; } // FIXME: While calling these toString functions, the array could be mutated. // In that case, objects pointed to by values in this vector might get garbage-collected! // FIXME: The following loop continues to call toString on subsequent values even after
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -