X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/12899fa232562c774004a3a9d7d3149944dec712..ef99ff287df9046eb88937225e0554eabb00e33c:/runtime/JSArray.cpp diff --git a/runtime/JSArray.cpp b/runtime/JSArray.cpp index 2527b14..f4bc093 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, 2009, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2003 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * @@ -27,31 +27,31 @@ #include "ButterflyInlines.h" #include "CachedCall.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlines.h" #include "Error.h" #include "Executable.h" #include "GetterSetter.h" #include "IndexingHeaderInlines.h" +#include "JSCInlines.h" #include "PropertyNameArray.h" #include "Reject.h" #include #include #include -#include using namespace std; using namespace WTF; namespace JSC { -ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSArray); +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSArray); const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)}; -Butterfly* createArrayButterflyInDictionaryIndexingMode(VM& vm, unsigned initialLength) +Butterfly* createArrayButterflyInDictionaryIndexingMode( + VM& vm, JSCell* intendedOwner, unsigned initialLength) { Butterfly* butterfly = Butterfly::create( - vm, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0)); + vm, intendedOwner, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0)); ArrayStorage* storage = butterfly->arrayStorage(); storage->setLength(initialLength); storage->setVectorLength(0); @@ -75,7 +75,7 @@ void JSArray::setLengthWritable(ExecState* exec, bool writable) } // Defined in ES5.1 15.4.5.1 -bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException) +bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException) { JSArray* array = jsCast(object); @@ -108,7 +108,7 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName unsigned newLen = descriptor.value().toUInt32(exec); // d. If newLen is not equal to ToNumber( Desc.[[Value]]), throw a RangeError exception. if (newLen != descriptor.value().toNumber(exec)) { - throwError(exec, createRangeError(exec, "Invalid array length")); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return false; } @@ -176,26 +176,16 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName return array->JSObject::defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException); } -bool JSArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - JSArray* thisObject = jsCast(cell); - if (propertyName == exec->propertyNames().length) { - slot.setValue(jsNumber(thisObject->length())); - return true; - } - - return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); -} - -bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) +bool JSArray::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSArray* thisObject = jsCast(object); if (propertyName == exec->propertyNames().length) { - descriptor.setDescriptor(jsNumber(thisObject->length()), thisObject->isLengthWritable() ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly); + unsigned attributes = thisObject->isLengthWritable() ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly; + slot.setValue(thisObject, attributes, jsNumber(thisObject->length())); return true; } - return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); + return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); } // ECMA 15.4.5.1 @@ -206,7 +196,7 @@ void JSArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSVa if (propertyName == exec->propertyNames().length) { unsigned newLength = value.toUInt32(exec); if (value.toNumber(exec) != static_cast(newLength)) { - throwError(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); + exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); return; } thisObject->setLength(exec, newLength, slot.isStrictMode()); @@ -248,8 +238,8 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) { ArrayStorage* storage = ensureArrayStorage(vm); Butterfly* butterfly = storage->butterfly(); - unsigned propertyCapacity = structure()->outOfLineCapacity(); - unsigned propertySize = structure()->outOfLineSize(); + unsigned propertyCapacity = structure(vm)->outOfLineCapacity(); + unsigned propertySize = structure(vm)->outOfLineSize(); // If not, we should have handled this on the fast path. ASSERT(!addToFront || count > storage->m_indexBias); @@ -278,15 +268,16 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) // Step 2: // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing one. + DeferGC deferGC(vm.heap); void* newAllocBase = 0; unsigned newStorageCapacity; // If the current storage array is sufficiently large (but not too large!) then just keep using it. if (currentCapacity > desiredCapacity && isDenseEnoughForVector(currentCapacity, requiredVectorLength)) { - newAllocBase = butterfly->base(structure()); + newAllocBase = butterfly->base(structure(vm)); newStorageCapacity = currentCapacity; } else { size_t newSize = Butterfly::totalSize(0, propertyCapacity, true, ArrayStorage::sizeFor(desiredCapacity)); - if (!vm.heap.tryAllocateStorage(newSize, &newAllocBase)) + if (!vm.heap.tryAllocateStorage(this, newSize, &newAllocBase)) return false; newStorageCapacity = desiredCapacity; } @@ -306,7 +297,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) // Atomic decay, + the post-capacity cannot be greater than what is available. postCapacity = min((storage->vectorLength() - length) >> 1, newStorageCapacity - requiredVectorLength); // If we're moving contents within the same allocation, the post-capacity is being reduced. - ASSERT(newAllocBase != butterfly->base(structure()) || postCapacity < storage->vectorLength() - length); + ASSERT(newAllocBase != butterfly->base(structure(vm)) || postCapacity < storage->vectorLength() - length); } unsigned newVectorLength = requiredVectorLength + postCapacity; @@ -318,7 +309,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) ASSERT(count + usedVectorLength <= newVectorLength); memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength); memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); - } else if ((newAllocBase != butterfly->base(structure())) || (newIndexBias != storage->m_indexBias)) { + } else if ((newAllocBase != butterfly->base(structure(vm))) || (newIndexBias != storage->m_indexBias)) { memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); memmove(newButterfly->arrayStorage()->m_vector, storage->m_vector, sizeof(JSValue) * usedVectorLength); @@ -329,8 +320,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) newButterfly->arrayStorage()->setVectorLength(newVectorLength); newButterfly->arrayStorage()->m_indexBias = newIndexBias; - - m_butterfly = newButterfly; + setButterflyWithoutChangingStructure(vm, newButterfly); return true; } @@ -401,7 +391,7 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException) { - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: if (!newLength) return true; @@ -430,9 +420,9 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException ensureLength(exec->vm(), newLength); return true; } - if (structure()->indexingType() == ArrayWithDouble) { + if (indexingType() == ArrayWithDouble) { for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) - m_butterfly->contiguousDouble()[i] = QNaN; + m_butterfly->contiguousDouble()[i] = PNaN; } else { for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) m_butterfly->contiguous()[i].clear(); @@ -452,7 +442,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException JSValue JSArray::pop(ExecState* exec) { - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: return jsUndefined(); @@ -488,7 +478,7 @@ JSValue JSArray::pop(ExecState* exec) RELEASE_ASSERT(length < m_butterfly->vectorLength()); double value = m_butterfly->contiguousDouble()[length]; if (value == value) { - m_butterfly->contiguousDouble()[length] = QNaN; + m_butterfly->contiguousDouble()[length] = PNaN; m_butterfly->setPublicLength(length); return JSValue(JSValue::EncodeAsDouble, value); } @@ -547,10 +537,10 @@ JSValue JSArray::pop(ExecState* exec) // - pushing to an array of length 2^32-1 stores the property, but throws a range error. void JSArray::push(ExecState* exec, JSValue value) { - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: { createInitialUndecided(exec->vm(), 0); - // Fall through. + FALLTHROUGH; } case ArrayWithUndecided: { @@ -575,9 +565,9 @@ void JSArray::push(ExecState* exec, JSValue value) } if (length > MAX_ARRAY_INDEX) { - methodTable()->putByIndex(this, exec, length, value, true); + methodTable(exec->vm())->putByIndex(this, exec, length, value, true); if (!exec->hadException()) - throwError(exec, createRangeError(exec, "Invalid array length")); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return; } @@ -595,9 +585,9 @@ void JSArray::push(ExecState* exec, JSValue value) } if (length > MAX_ARRAY_INDEX) { - methodTable()->putByIndex(this, exec, length, value, true); + methodTable(exec->vm())->putByIndex(this, exec, length, value, true); if (!exec->hadException()) - throwError(exec, createRangeError(exec, "Invalid array length")); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return; } @@ -627,9 +617,9 @@ void JSArray::push(ExecState* exec, JSValue value) } if (length > MAX_ARRAY_INDEX) { - methodTable()->putByIndex(this, exec, length, value, true); + methodTable(exec->vm())->putByIndex(this, exec, length, value, true); if (!exec->hadException()) - throwError(exec, createRangeError(exec, "Invalid array length")); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return; } @@ -644,7 +634,7 @@ void JSArray::push(ExecState* exec, JSValue value) setLength(exec, oldLength + 1, true); return; } - // Fall through. + FALLTHROUGH; } case ArrayWithArrayStorage: { @@ -661,10 +651,10 @@ void JSArray::push(ExecState* exec, JSValue value) // Pushing to an array of invalid length (2^31-1) stores the property, but throws a range error. if (storage->length() > MAX_ARRAY_INDEX) { - methodTable()->putByIndex(this, exec, storage->length(), value, true); + methodTable(exec->vm())->putByIndex(this, exec, storage->length(), value, true); // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d. if (!exec->hadException()) - throwError(exec, createRangeError(exec, "Invalid array length")); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return; } @@ -678,15 +668,18 @@ void JSArray::push(ExecState* exec, JSValue value) } } -bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage) +bool JSArray::shiftCountWithArrayStorage(VM& vm, unsigned startIndex, unsigned count, ArrayStorage* storage) { unsigned oldLength = storage->length(); RELEASE_ASSERT(count <= oldLength); // If the array contains holes or is otherwise in an abnormal state, // use the generic algorithm in ArrayPrototype. - if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode() || shouldUseSlowPut(structure()->indexingType())) + if ((storage->hasHoles() && this->structure(vm)->holesMustForwardToPrototype(vm)) + || inSparseIndexingMode() + || shouldUseSlowPut(indexingType())) { return false; + } if (!oldLength) return true; @@ -708,37 +701,83 @@ bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, Ar unsigned usedVectorLength = min(vectorLength, oldLength); - vectorLength -= count; - storage->setVectorLength(vectorLength); - - if (vectorLength) { - if (startIndex < usedVectorLength - (startIndex + count)) { - if (startIndex) { - memmove( - storage->m_vector + count, + unsigned numElementsBeforeShiftRegion = startIndex; + unsigned firstIndexAfterShiftRegion = startIndex + count; + unsigned numElementsAfterShiftRegion = usedVectorLength - firstIndexAfterShiftRegion; + ASSERT(numElementsBeforeShiftRegion + count + numElementsAfterShiftRegion == usedVectorLength); + + // The point of this comparison seems to be to minimize the amount of elements that have to + // be moved during a shift operation. + if (numElementsBeforeShiftRegion < numElementsAfterShiftRegion) { + // The number of elements before the shift region is less than the number of elements + // after the shift region, so we move the elements before to the right. + if (numElementsBeforeShiftRegion) { + RELEASE_ASSERT(count + startIndex <= vectorLength); + if (storage->hasHoles()) { + for (unsigned i = startIndex; i-- > 0;) { + unsigned destinationIndex = count + i; + JSValue source = storage->m_vector[i].get(); + JSValue dest = storage->m_vector[destinationIndex].get(); + // Any time we overwrite a hole we know we overcounted the number of values we removed + // when we subtracted count from m_numValuesInVector above. + if (!dest && destinationIndex >= firstIndexAfterShiftRegion) + storage->m_numValuesInVector++; + storage->m_vector[count + i].setWithoutWriteBarrier(source); + } + } else { + memmove(storage->m_vector + count, storage->m_vector, sizeof(JSValue) * startIndex); } - m_butterfly = m_butterfly->shift(structure(), count); - storage = m_butterfly->arrayStorage(); - storage->m_indexBias += count; + } + // Adjust the Butterfly and the index bias. We only need to do this here because we're changing + // the start of the Butterfly, which needs to point at the first indexed property in the used + // portion of the vector. + m_butterfly.setWithoutWriteBarrier(m_butterfly->shift(structure(), count)); + storage = m_butterfly->arrayStorage(); + storage->m_indexBias += count; + + // Since we're consuming part of the vector by moving its beginning to the left, + // we need to modify the vector length appropriately. + storage->setVectorLength(vectorLength - count); + } else { + // The number of elements before the shift region is greater than or equal to the number + // of elements after the shift region, so we move the elements after the shift region to the left. + if (storage->hasHoles()) { + for (unsigned i = 0; i < numElementsAfterShiftRegion; ++i) { + unsigned destinationIndex = startIndex + i; + JSValue source = storage->m_vector[firstIndexAfterShiftRegion + i].get(); + JSValue dest = storage->m_vector[destinationIndex].get(); + // Any time we overwrite a hole we know we overcounted the number of values we removed + // when we subtracted count from m_numValuesInVector above. + if (!dest && destinationIndex < firstIndexAfterShiftRegion) + storage->m_numValuesInVector++; + storage->m_vector[startIndex + i].setWithoutWriteBarrier(source); + } } else { - memmove( - storage->m_vector + startIndex, - storage->m_vector + startIndex + count, - sizeof(JSValue) * (usedVectorLength - (startIndex + count))); - for (unsigned i = usedVectorLength - count; i < usedVectorLength; ++i) - storage->m_vector[i].clear(); + memmove(storage->m_vector + startIndex, + storage->m_vector + firstIndexAfterShiftRegion, + sizeof(JSValue) * numElementsAfterShiftRegion); } + // Clear the slots of the elements we just moved. + unsigned startOfEmptyVectorTail = usedVectorLength - count; + for (unsigned i = startOfEmptyVectorTail; i < usedVectorLength; ++i) + storage->m_vector[i].clear(); + // We don't modify the index bias or the Butterfly pointer in this case because we're not changing + // the start of the Butterfly, which needs to point at the first indexed property in the used + // portion of the vector. We also don't modify the vector length because we're not actually changing + // its length; we're just using less of it. } + return true; } -bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count) +bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startIndex, unsigned count) { + VM& vm = exec->vm(); RELEASE_ASSERT(count > 0); - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: return true; @@ -754,27 +793,28 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex // We may have to walk the entire array to do the shift. We're willing to do // so only if it's not horribly slow. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); + return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm)); // Storing to a hole is fine since we're still having a good time. But reading from a hole // is totally not fine, since we might have to read from the proto chain. // We have to check for holes before we start moving things around so that we don't get halfway // through shifting and then realize we should have been in ArrayStorage mode. unsigned end = oldLength - count; - for (unsigned i = startIndex; i < end; ++i) { - JSValue v = m_butterfly->contiguous()[i + count].get(); - if (UNLIKELY(!v)) - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); + if (this->structure(vm)->holesMustForwardToPrototype(vm)) { + for (unsigned i = startIndex; i < end; ++i) { + JSValue v = m_butterfly->contiguous()[i + count].get(); + if (UNLIKELY(!v)) { + startIndex = i; + return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm)); + } + m_butterfly->contiguous()[i].setWithoutWriteBarrier(v); + } + } else { + memmove(m_butterfly->contiguous().data() + startIndex, + m_butterfly->contiguous().data() + startIndex + count, + sizeof(JSValue) * (end - startIndex)); } - for (unsigned i = startIndex; i < end; ++i) { - JSValue v = m_butterfly->contiguous()[i + count].get(); - ASSERT(v); - // No need for a barrier since we're just moving data around in the same vector. - // This is in line with our standing assumption that we won't have a deletion - // barrier. - m_butterfly->contiguous()[i].setWithoutWriteBarrier(v); - } for (unsigned i = end; i < oldLength; ++i) m_butterfly->contiguous()[i].clear(); @@ -789,29 +829,29 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex // We may have to walk the entire array to do the shift. We're willing to do // so only if it's not horribly slow. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); + return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm)); // Storing to a hole is fine since we're still having a good time. But reading from a hole // is totally not fine, since we might have to read from the proto chain. // We have to check for holes before we start moving things around so that we don't get halfway // through shifting and then realize we should have been in ArrayStorage mode. unsigned end = oldLength - count; - for (unsigned i = startIndex; i < end; ++i) { - double v = m_butterfly->contiguousDouble()[i + count]; - if (UNLIKELY(v != v)) - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); - } - - for (unsigned i = startIndex; i < end; ++i) { - double v = m_butterfly->contiguousDouble()[i + count]; - ASSERT(v == v); - // No need for a barrier since we're just moving data around in the same vector. - // This is in line with our standing assumption that we won't have a deletion - // barrier. - m_butterfly->contiguousDouble()[i] = v; + if (this->structure(vm)->holesMustForwardToPrototype(vm)) { + for (unsigned i = startIndex; i < end; ++i) { + double v = m_butterfly->contiguousDouble()[i + count]; + if (UNLIKELY(v != v)) { + startIndex = i; + return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm)); + } + m_butterfly->contiguousDouble()[i] = v; + } + } else { + memmove(m_butterfly->contiguousDouble().data() + startIndex, + m_butterfly->contiguousDouble().data() + startIndex + count, + sizeof(JSValue) * (end - startIndex)); } for (unsigned i = end; i < oldLength; ++i) - m_butterfly->contiguousDouble()[i] = QNaN; + m_butterfly->contiguousDouble()[i] = PNaN; m_butterfly->setPublicLength(oldLength - count); return true; @@ -819,7 +859,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex case ArrayWithArrayStorage: case ArrayWithSlowPutArrayStorage: - return shiftCountWithArrayStorage(startIndex, count, arrayStorage()); + return shiftCountWithArrayStorage(vm, startIndex, count, arrayStorage()); default: CRASH(); @@ -836,7 +876,7 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, // If the array contains holes or is otherwise in an abnormal state, // use the generic algorithm in ArrayPrototype. - if (length != storage->m_numValuesInVector || storage->inSparseMode() || shouldUseSlowPut(structure()->indexingType())) + if (storage->hasHoles() || storage->inSparseMode() || shouldUseSlowPut(indexingType())) return false; bool moveFront = !startIndex || startIndex < length / 2; @@ -844,10 +884,11 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, unsigned vectorLength = storage->vectorLength(); if (moveFront && storage->m_indexBias >= count) { - m_butterfly = storage->butterfly()->unshift(structure(), count); - storage = m_butterfly->arrayStorage(); + Butterfly* newButterfly = storage->butterfly()->unshift(structure(), count); + storage = newButterfly->arrayStorage(); storage->m_indexBias -= count; storage->setVectorLength(vectorLength + count); + setButterflyWithoutChangingStructure(exec->vm(), newButterfly); } else if (!moveFront && vectorLength - length >= count) storage = storage->butterfly()->arrayStorage(); else if (unshiftCountSlowCase(exec->vm(), moveFront, count)) @@ -873,7 +914,7 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count) { - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: case ArrayWithUndecided: // We could handle this. But it shouldn't ever come up, so we won't. @@ -982,20 +1023,20 @@ static int compareByStringPairForQSort(const void* a, const void* b) return codePointCompare(va->second, vb->second); } -template +template void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { - ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage); + ASSERT(arrayIndexingType == ArrayWithInt32 || arrayIndexingType == ArrayWithDouble || arrayIndexingType == ArrayWithContiguous || arrayIndexingType == ArrayWithArrayStorage); unsigned lengthNotIncludingUndefined; unsigned newRelevantLength; - compactForSorting( + compactForSorting( lengthNotIncludingUndefined, newRelevantLength); - ContiguousJSValues data = indexingData(); + ContiguousJSValues data = indexingData(); - if (indexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) { + if (arrayIndexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) { throwOutOfMemoryError(exec); return; } @@ -1004,7 +1045,7 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy return; bool allValuesAreNumbers = true; - switch (indexingType) { + switch (arrayIndexingType) { case ArrayWithInt32: case ArrayWithDouble: break; @@ -1026,7 +1067,7 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy // also don't require mergesort's stability, since there's no user visible // side-effect from swapping the order of equal primitive values. int (*compare)(const void*, const void*); - switch (indexingType) { + switch (arrayIndexingType) { case ArrayWithInt32: compare = compareNumbersForQSortWithInt32; break; @@ -1049,7 +1090,7 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal { ASSERT(!inSparseIndexingMode()); - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: return; @@ -1102,7 +1143,7 @@ template <> struct ContiguousTypeAccessor { }; -template +template void JSArray::sortCompactedVector(ExecState* exec, ContiguousData data, unsigned relevantLength) { if (!relevantLength) @@ -1126,11 +1167,11 @@ void JSArray::sortCompactedVector(ExecState* exec, ContiguousData d bool isSortingPrimitiveValues = true; for (size_t i = 0; i < relevantLength; i++) { - JSValue value = ContiguousTypeAccessor::getAsValue(data, i); - ASSERT(indexingType != ArrayWithInt32 || value.isInt32()); + JSValue value = ContiguousTypeAccessor::getAsValue(data, i); + ASSERT(arrayIndexingType != ArrayWithInt32 || value.isInt32()); ASSERT(!value.isUndefined()); values[i].first = value; - if (indexingType != ArrayWithDouble && indexingType != ArrayWithInt32) + if (arrayIndexingType != ArrayWithDouble && arrayIndexingType != ArrayWithInt32) isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive(); } @@ -1161,7 +1202,7 @@ void JSArray::sortCompactedVector(ExecState* exec, ContiguousData d // If the toString function changed the length of the array or vector storage, // increase the length to handle the orignal number of actual values. - switch (indexingType) { + switch (arrayIndexingType) { case ArrayWithInt32: case ArrayWithDouble: case ArrayWithContiguous: @@ -1171,7 +1212,7 @@ void JSArray::sortCompactedVector(ExecState* exec, ContiguousData d case ArrayWithArrayStorage: if (arrayStorage()->vectorLength() < relevantLength) { increaseVectorLength(exec->vm(), relevantLength); - ContiguousTypeAccessor::replaceDataReference(&data, arrayStorage()->vector()); + ContiguousTypeAccessor::replaceDataReference(&data, arrayStorage()->vector()); } if (arrayStorage()->length() < relevantLength) arrayStorage()->setLength(relevantLength); @@ -1182,7 +1223,7 @@ void JSArray::sortCompactedVector(ExecState* exec, ContiguousData d } for (size_t i = 0; i < relevantLength; i++) - ContiguousTypeAccessor::setWithValue(vm, this, data, i, values[i].first); + ContiguousTypeAccessor::setWithValue(vm, this, data, i, values[i].first); Heap::heap(this)->popTempSortVector(&values); } @@ -1191,7 +1232,7 @@ void JSArray::sort(ExecState* exec) { ASSERT(!inSparseIndexingMode()); - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: case ArrayWithUndecided: return; @@ -1307,7 +1348,7 @@ struct AVLTreeAbstractorForArrayCompare { m_cachedCall->setThis(jsUndefined()); m_cachedCall->setArgument(0, va); m_cachedCall->setArgument(1, vb); - compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame(m_exec)); + compareResult = m_cachedCall->call().toNumber(m_exec); } else { MarkedArgumentBuffer arguments; arguments.append(va); @@ -1323,11 +1364,11 @@ struct AVLTreeAbstractorForArrayCompare { static handle null() { return 0x7FFFFFFF; } }; -template +template void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { ASSERT(!inSparseIndexingMode()); - ASSERT(indexingType == structure()->indexingType()); + ASSERT(arrayIndexingType == indexingType()); // FIXME: This ignores exceptions raised in the compare function or in toNumber. @@ -1337,7 +1378,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call if (m_butterfly->publicLength() > static_cast(std::numeric_limits::max())) return; - unsigned usedVectorLength = relevantLength(); + unsigned usedVectorLength = relevantLength(); unsigned nodeCount = usedVectorLength; if (!nodeCount) @@ -1404,14 +1445,14 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call VM& vm = exec->vm(); for (unsigned i = 0; i < elementsToExtractThreshold; ++i) { ASSERT(i < butterfly()->vectorLength()); - if (structure()->indexingType() == ArrayWithDouble) + if (indexingType() == ArrayWithDouble) butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber(); else currentIndexingData()[i].set(vm, this, tree.abstractor().m_nodes[*iter].value); ++iter; } // Put undefined values back in. - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayWithInt32: case ArrayWithDouble: ASSERT(elementsToExtractThreshold == undefinedElementsThreshold); @@ -1427,13 +1468,13 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call // Ensure that unused values in the vector are zeroed out. for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) { ASSERT(i < butterfly()->vectorLength()); - if (structure()->indexingType() == ArrayWithDouble) - butterfly()->contiguousDouble()[i] = QNaN; + if (indexingType() == ArrayWithDouble) + butterfly()->contiguousDouble()[i] = PNaN; else currentIndexingData()[i].clear(); } - if (hasArrayStorage(structure()->indexingType())) + if (hasAnyArrayStorage(indexingType())) arrayStorage()->m_numValuesInVector = newUsedVectorLength; } @@ -1441,7 +1482,7 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, { ASSERT(!inSparseIndexingMode()); - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: case ArrayWithUndecided: return; @@ -1473,7 +1514,7 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) unsigned vectorEnd; WriteBarrier* vector; - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: return; @@ -1528,14 +1569,14 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) args.append(get(exec, i)); } -void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length) +void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t copyLength, int32_t firstVarArgOffset) { - unsigned i = 0; + unsigned i = firstVarArgOffset; WriteBarrier* vector; unsigned vectorEnd; - + unsigned length = copyLength + firstVarArgOffset; ASSERT(length == this->length()); - switch (structure()->indexingType()) { + switch (indexingType()) { case ArrayClass: return; @@ -1560,7 +1601,7 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le double v = m_butterfly->contiguousDouble()[i]; if (v != v) break; - callFrame->setArgument(i, JSValue(JSValue::EncodeAsDouble, v)); + callFrame->setArgument(i - firstVarArgOffset, JSValue(JSValue::EncodeAsDouble, v)); } break; } @@ -1583,47 +1624,47 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le WriteBarrier& v = vector[i]; if (!v) break; - callFrame->setArgument(i, v.get()); + callFrame->setArgument(i - firstVarArgOffset, v.get()); } for (; i < length; ++i) - callFrame->setArgument(i, get(exec, i)); + callFrame->setArgument(i - firstVarArgOffset, get(exec, i)); } -template +template void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLength) { ASSERT(!inSparseIndexingMode()); - ASSERT(indexingType == structure()->indexingType()); + ASSERT(arrayIndexingType == indexingType()); - unsigned myRelevantLength = relevantLength(); + unsigned myRelevantLength = relevantLength(); numDefined = 0; unsigned numUndefined = 0; for (; numDefined < myRelevantLength; ++numDefined) { ASSERT(numDefined < m_butterfly->vectorLength()); - if (indexingType == ArrayWithInt32) { + if (arrayIndexingType == ArrayWithInt32) { JSValue v = m_butterfly->contiguousInt32()[numDefined].get(); if (!v) break; ASSERT(v.isInt32()); continue; } - if (indexingType == ArrayWithDouble) { + if (arrayIndexingType == ArrayWithDouble) { double v = m_butterfly->contiguousDouble()[numDefined]; if (v != v) break; continue; } - JSValue v = indexingData()[numDefined].get(); + JSValue v = indexingData()[numDefined].get(); if (!v || v.isUndefined()) break; } for (unsigned i = numDefined; i < myRelevantLength; ++i) { ASSERT(i < m_butterfly->vectorLength()); - if (indexingType == ArrayWithInt32) { + if (arrayIndexingType == ArrayWithInt32) { JSValue v = m_butterfly->contiguousInt32()[i].get(); if (!v) continue; @@ -1632,7 +1673,7 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v); continue; } - if (indexingType == ArrayWithDouble) { + if (arrayIndexingType == ArrayWithDouble) { double v = m_butterfly->contiguousDouble()[i]; if (v != v) continue; @@ -1640,23 +1681,23 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt m_butterfly->contiguousDouble()[numDefined++] = v; continue; } - JSValue v = indexingData()[i].get(); + JSValue v = indexingData()[i].get(); if (v) { if (v.isUndefined()) ++numUndefined; else { ASSERT(numDefined < m_butterfly->vectorLength()); - indexingData()[numDefined++].setWithoutWriteBarrier(v); + indexingData()[numDefined++].setWithoutWriteBarrier(v); } } } newRelevantLength = numDefined + numUndefined; - if (hasArrayStorage(indexingType)) + if (hasAnyArrayStorage(arrayIndexingType)) RELEASE_ASSERT(!arrayStorage()->m_sparseMap); - switch (indexingType) { + switch (arrayIndexingType) { case ArrayWithInt32: case ArrayWithDouble: RELEASE_ASSERT(numDefined == newRelevantLength); @@ -1665,19 +1706,19 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt default: for (unsigned i = numDefined; i < newRelevantLength; ++i) { ASSERT(i < m_butterfly->vectorLength()); - indexingData()[i].setUndefined(); + indexingData()[i].setUndefined(); } break; } for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) { ASSERT(i < m_butterfly->vectorLength()); - if (indexingType == ArrayWithDouble) - m_butterfly->contiguousDouble()[i] = QNaN; + if (arrayIndexingType == ArrayWithDouble) + m_butterfly->contiguousDouble()[i] = PNaN; else - indexingData()[i].clear(); + indexingData()[i].clear(); } - if (hasArrayStorage(indexingType)) + if (hasAnyArrayStorage(arrayIndexingType)) arrayStorage()->m_numValuesInVector = newRelevantLength; }