/*
* 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)
*
#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 <wtf/AVLTree.h>
#include <wtf/Assertions.h>
#include <wtf/OwnPtr.h>
-#include <Operations.h>
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);
}
// 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<JSArray*>(object);
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;
}
return array->JSObject::defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
}
-bool JSArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-{
- JSArray* thisObject = jsCast<JSArray*>(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<JSArray*>(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
if (propertyName == exec->propertyNames().length) {
unsigned newLength = value.toUInt32(exec);
if (value.toNumber(exec) != static_cast<double>(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());
{
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);
// 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;
}
// 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;
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);
newButterfly->arrayStorage()->setVectorLength(newVectorLength);
newButterfly->arrayStorage()->m_indexBias = newIndexBias;
-
- m_butterfly = newButterfly;
+ setButterflyWithoutChangingStructure(vm, newButterfly);
return true;
}
bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
if (!newLength)
return true;
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();
JSValue JSArray::pop(ExecState* exec)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
return jsUndefined();
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);
}
// - 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: {
}
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;
}
}
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;
}
}
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;
}
setLength(exec, oldLength + 1, true);
return;
}
- // Fall through.
+ FALLTHROUGH;
}
case ArrayWithArrayStorage: {
// 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;
}
}
}
-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;
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;
// 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) {
- // 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.
- JSValue v = m_butterfly->contiguous()[i + count].get();
- if (UNLIKELY(!v)) {
- // The purpose of this path is to ensure that we don't make the same
- // mistake in the future: shiftCountWithArrayStorage() can't do anything
- // about holes (at least for now), but it can detect them quickly. So
- // we convert to array storage and then allow the array storage path to
- // figure it out.
- 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);
}
- // 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);
+ } else {
+ memmove(m_butterfly->contiguous().data() + startIndex,
+ m_butterfly->contiguous().data() + startIndex + count,
+ sizeof(JSValue) * (end - startIndex));
}
+
for (unsigned i = end; i < oldLength; ++i)
m_butterfly->contiguous()[i].clear();
// 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) {
- // 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.
- double v = m_butterfly->contiguousDouble()[i + count];
- if (UNLIKELY(v != v)) {
- // The purpose of this path is to ensure that we don't make the same
- // mistake in the future: shiftCountWithArrayStorage() can't do anything
- // about holes (at least for now), but it can detect them quickly. So
- // we convert to array storage and then allow the array storage path to
- // figure it out.
- return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
+ 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;
}
- // 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;
+ } 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;
case ArrayWithArrayStorage:
case ArrayWithSlowPutArrayStorage:
- return shiftCountWithArrayStorage(startIndex, count, arrayStorage());
+ return shiftCountWithArrayStorage(vm, startIndex, count, arrayStorage());
default:
CRASH();
// 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;
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))
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.
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
ensureLength(exec->vm(), oldLength + count);
-
+
+ // 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.
for (unsigned i = oldLength; i-- > startIndex;) {
JSValue v = m_butterfly->contiguous()[i].get();
if (UNLIKELY(!v))
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
+ }
+
+ for (unsigned i = oldLength; i-- > startIndex;) {
+ JSValue v = m_butterfly->contiguous()[i].get();
+ ASSERT(v);
m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
}
ensureLength(exec->vm(), oldLength + count);
+ // 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.
for (unsigned i = oldLength; i-- > startIndex;) {
double v = m_butterfly->contiguousDouble()[i];
if (UNLIKELY(v != v))
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
+ }
+
+ for (unsigned i = oldLength; i-- > startIndex;) {
+ double v = m_butterfly->contiguousDouble()[i];
+ ASSERT(v == v);
m_butterfly->contiguousDouble()[i + count] = v;
}
return codePointCompare(va->second, vb->second);
}
-template<IndexingType indexingType>
+template<IndexingType arrayIndexingType>
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<indexingType>(
+ compactForSorting<arrayIndexingType>(
lengthNotIncludingUndefined,
newRelevantLength);
- ContiguousJSValues data = indexingData<indexingType>();
+ ContiguousJSValues data = indexingData<arrayIndexingType>();
- if (indexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) {
+ if (arrayIndexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) {
throwOutOfMemoryError(exec);
return;
}
return;
bool allValuesAreNumbers = true;
- switch (indexingType) {
+ switch (arrayIndexingType) {
case ArrayWithInt32:
case ArrayWithDouble:
break;
// 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;
{
ASSERT(!inSparseIndexingMode());
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
return;
};
-template<IndexingType indexingType, typename StorageType>
+template<IndexingType arrayIndexingType, typename StorageType>
void JSArray::sortCompactedVector(ExecState* exec, ContiguousData<StorageType> data, unsigned relevantLength)
{
if (!relevantLength)
bool isSortingPrimitiveValues = true;
for (size_t i = 0; i < relevantLength; i++) {
- JSValue value = ContiguousTypeAccessor<indexingType>::getAsValue(data, i);
- ASSERT(indexingType != ArrayWithInt32 || value.isInt32());
+ JSValue value = ContiguousTypeAccessor<arrayIndexingType>::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();
}
// 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:
case ArrayWithArrayStorage:
if (arrayStorage()->vectorLength() < relevantLength) {
increaseVectorLength(exec->vm(), relevantLength);
- ContiguousTypeAccessor<indexingType>::replaceDataReference(&data, arrayStorage()->vector());
+ ContiguousTypeAccessor<arrayIndexingType>::replaceDataReference(&data, arrayStorage()->vector());
}
if (arrayStorage()->length() < relevantLength)
arrayStorage()->setLength(relevantLength);
}
for (size_t i = 0; i < relevantLength; i++)
- ContiguousTypeAccessor<indexingType>::setWithValue(vm, this, data, i, values[i].first);
+ ContiguousTypeAccessor<arrayIndexingType>::setWithValue(vm, this, data, i, values[i].first);
Heap::heap(this)->popTempSortVector(&values);
}
{
ASSERT(!inSparseIndexingMode());
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
case ArrayWithUndecided:
return;
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);
static handle null() { return 0x7FFFFFFF; }
};
-template<IndexingType indexingType>
+template<IndexingType arrayIndexingType>
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.
if (m_butterfly->publicLength() > static_cast<unsigned>(std::numeric_limits<int>::max()))
return;
- unsigned usedVectorLength = relevantLength<indexingType>();
+ unsigned usedVectorLength = relevantLength<arrayIndexingType>();
unsigned nodeCount = usedVectorLength;
if (!nodeCount)
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);
// 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;
}
{
ASSERT(!inSparseIndexingMode());
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
case ArrayWithUndecided:
return;
unsigned vectorEnd;
WriteBarrier<Unknown>* vector;
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
return;
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<Unknown>* vector;
unsigned vectorEnd;
-
+ unsigned length = copyLength + firstVarArgOffset;
ASSERT(length == this->length());
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
return;
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;
}
WriteBarrier<Unknown>& 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<IndexingType indexingType>
+template<IndexingType arrayIndexingType>
void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLength)
{
ASSERT(!inSparseIndexingMode());
- ASSERT(indexingType == structure()->indexingType());
+ ASSERT(arrayIndexingType == indexingType());
- unsigned myRelevantLength = relevantLength<indexingType>();
+ unsigned myRelevantLength = relevantLength<arrayIndexingType>();
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<indexingType>()[numDefined].get();
+ JSValue v = indexingData<arrayIndexingType>()[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;
m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v);
continue;
}
- if (indexingType == ArrayWithDouble) {
+ if (arrayIndexingType == ArrayWithDouble) {
double v = m_butterfly->contiguousDouble()[i];
if (v != v)
continue;
m_butterfly->contiguousDouble()[numDefined++] = v;
continue;
}
- JSValue v = indexingData<indexingType>()[i].get();
+ JSValue v = indexingData<arrayIndexingType>()[i].get();
if (v) {
if (v.isUndefined())
++numUndefined;
else {
ASSERT(numDefined < m_butterfly->vectorLength());
- indexingData<indexingType>()[numDefined++].setWithoutWriteBarrier(v);
+ indexingData<arrayIndexingType>()[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);
default:
for (unsigned i = numDefined; i < newRelevantLength; ++i) {
ASSERT(i < m_butterfly->vectorLength());
- indexingData<indexingType>()[i].setUndefined();
+ indexingData<arrayIndexingType>()[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<indexingType>()[i].clear();
+ indexingData<arrayIndexingType>()[i].clear();
}
- if (hasArrayStorage(indexingType))
+ if (hasAnyArrayStorage(arrayIndexingType))
arrayStorage()->m_numValuesInVector = newRelevantLength;
}