summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSArray.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSArray.cpp')
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp297
1 files changed, 149 insertions, 148 deletions
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index b3210083d..c84fb5b10 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -24,6 +24,8 @@
#include "JSArray.h"
#include "ArrayPrototype.h"
+#include "BumpSpace.h"
+#include "BumpSpaceInlineMethods.h"
#include "CachedCall.h"
#include "Error.h"
#include "Executable.h"
@@ -130,7 +132,10 @@ inline void JSArray::checkConsistency(ConsistencyCheckType)
JSArray::JSArray(JSGlobalData& globalData, Structure* structure)
: JSNonFinalObject(globalData, structure)
+ , m_indexBias(0)
, m_storage(0)
+ , m_sparseValueMap(0)
+ , m_subclassData(0)
{
}
@@ -142,13 +147,14 @@ void JSArray::finishCreation(JSGlobalData& globalData, unsigned initialLength)
unsigned initialVectorLength = BASE_VECTOR_LEN;
unsigned initialStorageSize = storageSize(initialVectorLength);
- m_storage = static_cast<ArrayStorage*>(fastMalloc(initialStorageSize));
+ void* newStorage = 0;
+ if (!globalData.heap.tryAllocateStorage(initialStorageSize, &newStorage))
+ CRASH();
+
+ m_storage = static_cast<ArrayStorage*>(newStorage);
m_storage->m_allocBase = m_storage;
m_storage->m_length = initialLength;
- m_indexBias = 0;
m_vectorLength = initialVectorLength;
- m_storage->m_sparseValueMap = 0;
- m_storage->subclassData = 0;
m_storage->m_numValuesInVector = 0;
#if CHECK_ARRAY_CONSISTENCY
m_storage->m_inCompactInitialization = false;
@@ -159,8 +165,6 @@ void JSArray::finishCreation(JSGlobalData& globalData, unsigned initialLength)
vector[i].clear();
checkConsistency();
-
- Heap::heap(this)->reportExtraMemoryCost(initialStorageSize);
}
JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsigned initialLength)
@@ -175,14 +179,16 @@ JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsig
unsigned initialVectorLength = max(initialLength, BASE_VECTOR_LEN);
unsigned initialStorageSize = storageSize(initialVectorLength);
- m_storage = static_cast<ArrayStorage*>(fastMalloc(initialStorageSize));
+ void* newStorage = 0;
+ if (!globalData.heap.tryAllocateStorage(initialStorageSize, &newStorage))
+ CRASH();
+
+ m_storage = static_cast<ArrayStorage*>(newStorage);
m_storage->m_allocBase = m_storage;
m_storage->m_length = 0;
- m_indexBias = 0;
m_vectorLength = initialVectorLength;
- m_storage->m_sparseValueMap = 0;
- m_storage->subclassData = 0;
m_storage->m_numValuesInVector = initialLength;
+
#if CHECK_ARRAY_CONSISTENCY
m_storage->m_inCompactInitialization = true;
#endif
@@ -191,26 +197,15 @@ JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsig
for (size_t i = initialLength; i < initialVectorLength; ++i)
vector[i].clear();
- Heap::heap(this)->reportExtraMemoryCost(initialStorageSize);
return this;
}
-JSArray::~JSArray()
-{
- ASSERT(jsCast<JSArray*>(this));
-
- // If we are unable to allocate memory for m_storage then this may be null.
- if (!m_storage)
- return;
-
- checkConsistency(DestructorConsistencyCheck);
- delete m_storage->m_sparseValueMap;
- fastFree(m_storage->m_allocBase);
-}
-
-void JSArray::destroy(JSCell* cell)
+// This function can be called multiple times on the same object.
+void JSArray::finalize(JSCell* cell)
{
- jsCast<JSArray*>(cell)->JSArray::~JSArray();
+ JSArray* thisObject = jsCast<JSArray*>(cell);
+ thisObject->checkConsistency(DestructorConsistencyCheck);
+ thisObject->deallocateSparseMap();
}
inline std::pair<SparseArrayValueMap::iterator, bool> SparseArrayValueMap::add(JSArray* array, unsigned i)
@@ -229,7 +224,7 @@ inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i
{
SparseArrayEntry& entry = add(array, i).first->second;
- if (!(entry.attributes & (Getter | Setter))) {
+ if (!(entry.attributes & Accessor)) {
if (entry.attributes & ReadOnly) {
// FIXME: should throw if being called from strict mode.
// throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
@@ -310,13 +305,27 @@ inline void SparseArrayValueMap::visitChildren(SlotVisitor& visitor)
visitor.append(&it->second);
}
-void JSArray::enterSparseMode(JSGlobalData& globalData)
+void JSArray::allocateSparseMap(JSGlobalData& globalData)
+{
+ m_sparseValueMap = new SparseArrayValueMap;
+ globalData.heap.addFinalizer(this, finalize);
+}
+
+void JSArray::deallocateSparseMap()
+{
+ delete m_sparseValueMap;
+ m_sparseValueMap = 0;
+}
+
+void JSArray::enterDictionaryMode(JSGlobalData& globalData)
{
ArrayStorage* storage = m_storage;
- SparseArrayValueMap* map = storage->m_sparseValueMap;
+ SparseArrayValueMap* map = m_sparseValueMap;
- if (!map)
- map = storage->m_sparseValueMap = new SparseArrayValueMap;
+ if (!map) {
+ allocateSparseMap(globalData);
+ map = m_sparseValueMap;
+ }
if (map->sparseMode())
return;
@@ -332,10 +341,13 @@ void JSArray::enterSparseMode(JSGlobalData& globalData)
map->add(this, i).first->second.set(globalData, this, value);
}
- ArrayStorage* newStorage = static_cast<ArrayStorage*>(fastMalloc(storageSize(0)));
+ void* newRawStorage = 0;
+ if (!globalData.heap.tryAllocateStorage(storageSize(0), &newRawStorage))
+ CRASH();
+
+ ArrayStorage* newStorage = static_cast<ArrayStorage*>(newRawStorage);
memcpy(newStorage, m_storage, storageSize(0));
newStorage->m_allocBase = newStorage;
- fastFree(m_storage);
m_storage = newStorage;
m_indexBias = 0;
m_vectorLength = 0;
@@ -348,25 +360,21 @@ void JSArray::putDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, Prope
entryInMap->set(exec->globalData(), this, descriptor.value());
else if (oldDescriptor.isAccessorDescriptor())
entryInMap->set(exec->globalData(), this, jsUndefined());
- entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~(Getter | Setter);
+ entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor;
return;
}
if (descriptor.isAccessorDescriptor()) {
JSObject* getter = 0;
- if (descriptor.getter() && descriptor.getter().isObject())
- getter = asObject(descriptor.getter());
- if (!getter && oldDescriptor.isAccessorDescriptor()) {
- if (oldDescriptor.getter() && oldDescriptor.getter().isObject())
- getter = asObject(oldDescriptor.getter());
- }
+ if (descriptor.getterPresent())
+ getter = descriptor.getterObject();
+ else if (oldDescriptor.isAccessorDescriptor())
+ getter = oldDescriptor.getterObject();
JSObject* setter = 0;
- if (descriptor.setter() && descriptor.setter().isObject())
- setter = asObject(descriptor.setter());
- if (!setter && oldDescriptor.isAccessorDescriptor()) {
- if (oldDescriptor.setter() && oldDescriptor.setter().isObject())
- setter = asObject(oldDescriptor.setter());
- }
+ if (descriptor.setterPresent())
+ setter = descriptor.setterObject();
+ else if (oldDescriptor.isAccessorDescriptor())
+ setter = oldDescriptor.setterObject();
GetterSetter* accessor = GetterSetter::create(exec);
if (getter)
@@ -406,10 +414,10 @@ bool JSArray::defineOwnNumericProperty(ExecState* exec, unsigned index, Property
return true;
}
- enterSparseMode(exec->globalData());
+ enterDictionaryMode(exec->globalData());
}
- SparseArrayValueMap* map = m_storage->m_sparseValueMap;
+ SparseArrayValueMap* map = m_sparseValueMap;
ASSERT(map);
// 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
@@ -491,6 +499,7 @@ bool JSArray::defineOwnNumericProperty(ExecState* exec, unsigned index, Property
}
// 10.b. else, the [[Configurable]] field of current is true, so any change is acceptable.
} else {
+ ASSERT(current.isAccessorDescriptor() && current.getterPresent() && current.setterPresent());
// 11. Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true so, if the [[Configurable]] field of current is false, then
if (!current.configurable()) {
// 11.i. Reject, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]]) is false.
@@ -515,9 +524,9 @@ void JSArray::setLengthWritable(ExecState* exec, bool writable)
if (!isLengthWritable() || writable)
return;
- enterSparseMode(exec->globalData());
+ enterDictionaryMode(exec->globalData());
- SparseArrayValueMap* map = m_storage->m_sparseValueMap;
+ SparseArrayValueMap* map = m_sparseValueMap;
ASSERT(map);
map->setLengthIsReadOnly();
}
@@ -531,10 +540,10 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identif
if (propertyName == exec->propertyNames().length) {
// All paths through length definition call the default [[DefineOwnProperty]], hence:
// from ES5.1 8.12.9 7.a.
- if (descriptor.configurable())
+ if (descriptor.configurablePresent() && descriptor.configurable())
return reject(exec, throwException, "Attempting to change configurable attribute of unconfigurable property.");
// from ES5.1 8.12.9 7.b.
- if (descriptor.enumerable())
+ if (descriptor.enumerablePresent() && descriptor.enumerable())
return reject(exec, throwException, "Attempting to change enumerable attribute of unconfigurable property.");
// a. If the [[Value]] field of Desc is absent, then
@@ -542,11 +551,12 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identif
if (descriptor.isAccessorDescriptor())
return reject(exec, throwException, "Attempting to change access mechanism for an unconfigurable property.");
// from ES5.1 8.12.9 10.a.
- if (!array->isLengthWritable() && descriptor.writable())
+ if (!array->isLengthWritable() && descriptor.writablePresent() && descriptor.writable())
return reject(exec, throwException, "Attempting to change writable attribute of unconfigurable property.");
// This descriptor is either just making length read-only, or changing nothing!
if (!descriptor.value()) {
- array->setLengthWritable(exec, descriptor.writable());
+ if (descriptor.writablePresent())
+ array->setLengthWritable(exec, descriptor.writable());
return true;
}
@@ -561,7 +571,8 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identif
// Based on SameValue check in 8.12.9, this is always okay.
if (newLen == array->length()) {
- array->setLengthWritable(exec, descriptor.writable());
+ if (descriptor.writablePresent())
+ array->setLengthWritable(exec, descriptor.writable());
return true;
}
@@ -588,13 +599,17 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identif
// 2. If newWritable is false, set newLenDesc.[[Writable] to false.
// 3. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and false as arguments.
// 4. Reject.
- array->setLengthWritable(exec, descriptor.writable());
+ if (descriptor.writablePresent())
+ array->setLengthWritable(exec, descriptor.writable());
return false;
}
// m. If newWritable is false, then
- // i. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", Property Descriptor{[[Writable]]: false}, and false as arguments. This call will always return true.
- array->setLengthWritable(exec, descriptor.writable());
+ // i. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length",
+ // Property Descriptor{[[Writable]]: false}, and false as arguments. This call will always
+ // return true.
+ if (descriptor.writablePresent())
+ array->setLengthWritable(exec, descriptor.writable());
// n. Return true.
return true;
}
@@ -623,7 +638,7 @@ bool JSArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
{
JSArray* thisObject = jsCast<JSArray*>(cell);
ArrayStorage* storage = thisObject->m_storage;
-
+
if (i >= storage->m_length) {
if (i > MAX_ARRAY_INDEX)
return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
@@ -636,7 +651,7 @@ bool JSArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
slot.setValue(value);
return true;
}
- } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->notFound()) {
it->second.get(slot);
@@ -684,7 +699,7 @@ bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const
descriptor.setDescriptor(value.get(), 0);
return true;
}
- } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->notFound()) {
it->second.get(descriptor);
@@ -765,7 +780,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne
ASSERT(i <= MAX_ARRAY_INDEX);
ArrayStorage* storage = m_storage;
- SparseArrayValueMap* map = storage->m_sparseValueMap;
+ SparseArrayValueMap* map = m_sparseValueMap;
// First, handle cases where we don't currently have a sparse map.
if (LIKELY(!map)) {
@@ -774,7 +789,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne
storage->m_length = i + 1;
// Check that it is sensible to still be using a vector, and then try to grow the vector.
- if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(i + 1))) {
+ if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(globalData, i + 1))) {
// success! - reread m_storage since it has likely been reallocated, and store to the vector.
storage = m_storage;
storage->m_vector[i].set(globalData, this, value);
@@ -782,8 +797,8 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne
return;
}
// We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
- map = new SparseArrayValueMap;
- storage->m_sparseValueMap = map;
+ allocateSparseMap(exec->globalData());
+ map = m_sparseValueMap;
map->put(exec, this, i, value);
return;
}
@@ -803,7 +818,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne
// We are currently using a map - check whether we still want to be doing so.
// We will continue to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
- if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(length)) {
+ if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->globalData(), length)) {
map->put(exec, this, i, value);
return;
}
@@ -817,8 +832,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
vector[it->first].set(globalData, this, it->second.getNonSparseMode());
- delete map;
- storage->m_sparseValueMap = 0;
+ deallocateSparseMap();
// Store the new property into the vector.
WriteBarrier<Unknown>& valueSlot = vector[i];
@@ -857,7 +871,7 @@ bool JSArray::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
valueSlot.clear();
--storage->m_numValuesInVector;
}
- } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->notFound()) {
if (it->second.attributes & DontDelete)
@@ -892,7 +906,7 @@ void JSArray::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNam
propertyNames.add(Identifier::from(exec, i));
}
- if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) {
Vector<unsigned> keys;
keys.reserveCapacity(map->size());
@@ -940,7 +954,7 @@ ALWAYS_INLINE unsigned JSArray::getNewVectorLength(unsigned desiredLength)
return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH);
}
-bool JSArray::increaseVectorLength(unsigned newLength)
+bool JSArray::increaseVectorLength(JSGlobalData& globalData, 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.
@@ -952,15 +966,16 @@ bool JSArray::increaseVectorLength(unsigned newLength)
unsigned vectorLength = m_vectorLength;
ASSERT(newLength > vectorLength);
unsigned newVectorLength = getNewVectorLength(newLength);
- void* baseStorage = storage->m_allocBase;
// Fast case - there is no precapacity. In these cases a realloc makes sense.
if (LIKELY(!m_indexBias)) {
- if (!tryFastRealloc(baseStorage, storageSize(newVectorLength)).getValue(baseStorage))
+ void* newStorage = storage->m_allocBase;
+ if (!globalData.heap.tryReallocateStorage(&newStorage, storageSize(vectorLength), storageSize(newVectorLength)))
return false;
- storage = m_storage = reinterpret_cast_ptr<ArrayStorage*>(baseStorage);
- m_storage->m_allocBase = baseStorage;
+ storage = m_storage = reinterpret_cast_ptr<ArrayStorage*>(static_cast<char*>(newStorage));
+ m_storage->m_allocBase = newStorage;
+ ASSERT(m_storage->m_allocBase);
WriteBarrier<Unknown>* vector = storage->m_vector;
for (unsigned i = vectorLength; i < newVectorLength; ++i)
@@ -968,7 +983,6 @@ bool JSArray::increaseVectorLength(unsigned newLength)
m_vectorLength = newVectorLength;
- Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
return true;
}
@@ -976,15 +990,11 @@ bool JSArray::increaseVectorLength(unsigned newLength)
unsigned newIndexBias = min(m_indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength);
// Calculate new stoarge capcity, allowing room for the pre-capacity.
unsigned newStorageCapacity = newVectorLength + newIndexBias;
- void* newAllocBase;
- if (!tryFastMalloc(storageSize(newStorageCapacity)).getValue(newAllocBase))
+ void* newAllocBase = 0;
+ if (!globalData.heap.tryAllocateStorage(storageSize(newStorageCapacity), &newAllocBase))
return false;
// The sum of m_vectorLength and m_indexBias will never exceed MAX_STORAGE_VECTOR_LENGTH.
ASSERT(m_vectorLength <= MAX_STORAGE_VECTOR_LENGTH && (MAX_STORAGE_VECTOR_LENGTH - m_vectorLength) >= m_indexBias);
- unsigned currentCapacity = m_vectorLength + m_indexBias;
- // Currently there is no way to report to the heap that the extra capacity is shrinking!
- if (newStorageCapacity > currentCapacity)
- Heap::heap(this)->reportExtraMemoryCost((newStorageCapacity - currentCapacity) * sizeof(WriteBarrier<Unknown>));
m_vectorLength = newVectorLength;
m_indexBias = newIndexBias;
@@ -996,14 +1006,13 @@ bool JSArray::increaseVectorLength(unsigned newLength)
m_storage->m_vector[i].clear();
// Free the old allocation, update m_allocBase.
- fastFree(m_storage->m_allocBase);
m_storage->m_allocBase = newAllocBase;
return true;
}
// This method makes room in the vector, but leaves the new space uncleared.
-bool JSArray::unshiftCountSlowCase(unsigned count)
+bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
{
// If not, we should have handled this on the fast path.
ASSERT(count > m_indexBias);
@@ -1034,19 +1043,16 @@ bool JSArray::unshiftCountSlowCase(unsigned count)
// Step 2:
// We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing on.
- void* newAllocBase;
+ 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 = storage->m_allocBase;
newStorageCapacity = currentCapacity;
} else {
- if (!tryFastMalloc(storageSize(desiredCapacity)).getValue(newAllocBase))
+ if (!globalData.heap.tryAllocateStorage(storageSize(desiredCapacity), &newAllocBase))
return false;
newStorageCapacity = desiredCapacity;
- // Currently there is no way to report to the heap that the extra capacity is shrinking!
- if (desiredCapacity > currentCapacity)
- Heap::heap(this)->reportExtraMemoryCost((desiredCapacity - currentCapacity) * sizeof(WriteBarrier<Unknown>));
}
// Step 3:
@@ -1079,7 +1085,6 @@ bool JSArray::unshiftCountSlowCase(unsigned count)
// Are we copying into a new allocation?
if (newAllocBase != m_storage->m_allocBase) {
// Free the old allocation, update m_allocBase.
- fastFree(m_storage->m_allocBase);
m_storage->m_allocBase = newAllocBase;
// We need to clear any entries in the vector beyond length. We only need to
@@ -1101,9 +1106,9 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
unsigned length = storage->m_length;
// If the length is read only then we enter sparse mode, so should enter the following 'if'.
- ASSERT(isLengthWritable() || storage->m_sparseValueMap);
+ ASSERT(isLengthWritable() || m_sparseValueMap);
- if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ if (SparseArrayValueMap* map = m_sparseValueMap) {
// Fail if the length is not writable.
if (map->lengthIsReadOnly())
return reject(exec, throwException, StrictModeReadonlyPropertyWriteError);
@@ -1138,10 +1143,8 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
} else {
for (unsigned i = 0; i < keys.size(); ++i)
map->remove(keys[i]);
- if (map->isEmpty()) {
- delete map;
- storage->m_sparseValueMap = 0;
- }
+ if (map->isEmpty())
+ deallocateSparseMap();
}
}
}
@@ -1190,7 +1193,7 @@ JSValue JSArray::pop(ExecState* exec)
result = jsUndefined();
} else {
result = jsUndefined();
- if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ if (SparseArrayValueMap* map = m_sparseValueMap) {
SparseArrayValueMap::iterator it = map->find(length);
if (it != map->notFound()) {
unsigned attributes = it->second.attributes;
@@ -1206,10 +1209,8 @@ JSValue JSArray::pop(ExecState* exec)
}
map->remove(it);
- if (map->isEmpty() && !map->sparseMode()) {
- delete map;
- storage->m_sparseValueMap = 0;
- }
+ if (map->isEmpty() && !map->sparseMode())
+ deallocateSparseMap();
}
}
}
@@ -1331,7 +1332,7 @@ void JSArray::unshiftCount(ExecState* exec, unsigned count)
memmove(newBaseStorage, storage, storageSize(0));
m_storage = reinterpret_cast_ptr<ArrayStorage*>(newBaseStorage);
m_vectorLength += count;
- } else if (!unshiftCountSlowCase(count)) {
+ } else if (!unshiftCountSlowCase(exec->globalData(), count)) {
throwOutOfMemoryError(exec);
return;
}
@@ -1349,13 +1350,21 @@ void JSArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
JSNonFinalObject::visitChildren(thisObject, visitor);
-
- ArrayStorage* storage = thisObject->m_storage;
- unsigned usedVectorLength = std::min(storage->m_length, thisObject->m_vectorLength);
- visitor.appendValues(storage->m_vector, usedVectorLength);
+ if (thisObject->m_storage) {
+ ArrayStorage* storage = thisObject->m_storage;
+ void* baseStorage = storage->m_allocBase;
+
+ visitor.copyAndAppend(reinterpret_cast<void**>(&baseStorage), storageSize(thisObject->m_vectorLength + thisObject->m_indexBias), storage->m_vector->slot(), thisObject->m_vectorLength);
+
+ if (baseStorage != thisObject->m_storage->m_allocBase) {
+ thisObject->m_storage = reinterpret_cast<ArrayStorage*>(static_cast<char*>(baseStorage) + sizeof(JSValue) * thisObject->m_indexBias);
+ thisObject->m_storage->m_allocBase = baseStorage;
+ ASSERT(thisObject->m_storage->m_allocBase);
+ }
+ }
- if (SparseArrayValueMap* map = storage->m_sparseValueMap)
+ if (SparseArrayValueMap* map = thisObject->m_sparseValueMap)
map->visitChildren(visitor);
}
@@ -1379,8 +1388,8 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal
ArrayStorage* storage = m_storage;
- unsigned lengthNotIncludingUndefined = compactForSorting();
- if (storage->m_sparseValueMap) {
+ unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData());
+ if (m_sparseValueMap) {
throwOutOfMemoryError(exec);
return;
}
@@ -1412,10 +1421,8 @@ void JSArray::sort(ExecState* exec)
{
ASSERT(!inSparseMode());
- ArrayStorage* storage = m_storage;
-
- unsigned lengthNotIncludingUndefined = compactForSorting();
- if (storage->m_sparseValueMap) {
+ unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData());
+ if (m_sparseValueMap) {
throwOutOfMemoryError(exec);
return;
}
@@ -1437,7 +1444,7 @@ void JSArray::sort(ExecState* exec)
Heap::heap(this)->pushTempSortVector(&values);
for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
- JSValue value = storage->m_vector[i].get();
+ JSValue value = m_storage->m_vector[i].get();
ASSERT(!value.isUndefined());
values[i].first = value;
}
@@ -1446,7 +1453,7 @@ void JSArray::sort(ExecState* exec)
// a toString call raises an exception.
for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
- values[i].second = values[i].first.toString(exec);
+ values[i].second = values[i].first.toString(exec)->value(exec);
if (exec->hadException()) {
Heap::heap(this)->popTempSortVector(&values);
@@ -1467,13 +1474,13 @@ void JSArray::sort(ExecState* exec)
// If the toString function changed the length of the array or vector storage,
// increase the length to handle the orignal number of actual values.
if (m_vectorLength < lengthNotIncludingUndefined)
- increaseVectorLength(lengthNotIncludingUndefined);
- if (storage->m_length < lengthNotIncludingUndefined)
- storage->m_length = lengthNotIncludingUndefined;
+ increaseVectorLength(exec->globalData(), lengthNotIncludingUndefined);
+ if (m_storage->m_length < lengthNotIncludingUndefined)
+ m_storage->m_length = lengthNotIncludingUndefined;
JSGlobalData& globalData = exec->globalData();
for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
- storage->m_vector[i].set(globalData, this, values[i].first);
+ m_storage->m_vector[i].set(globalData, this, values[i].first);
Heap::heap(this)->popTempSortVector(&values);
@@ -1563,18 +1570,16 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
checkConsistency();
- ArrayStorage* storage = m_storage;
-
// 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(storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max()));
- if (storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max()))
+ 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;
- unsigned usedVectorLength = min(storage->m_length, m_vectorLength);
- unsigned nodeCount = usedVectorLength + (storage->m_sparseValueMap ? storage->m_sparseValueMap->size() : 0);
+ unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength);
+ unsigned nodeCount = usedVectorLength + (m_sparseValueMap ? m_sparseValueMap->size() : 0);
if (!nodeCount)
return;
@@ -1602,14 +1607,14 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
// Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
for (; numDefined < usedVectorLength; ++numDefined) {
- JSValue v = storage->m_vector[numDefined].get();
+ JSValue v = m_storage->m_vector[numDefined].get();
if (!v || v.isUndefined())
break;
tree.abstractor().m_nodes[numDefined].value = v;
tree.insert(numDefined);
}
for (unsigned i = numDefined; i < usedVectorLength; ++i) {
- JSValue v = storage->m_vector[i].get();
+ JSValue v = m_storage->m_vector[i].get();
if (v) {
if (v.isUndefined())
++numUndefined;
@@ -1623,17 +1628,15 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
unsigned newUsedVectorLength = numDefined + numUndefined;
- if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ if (SparseArrayValueMap* map = m_sparseValueMap) {
newUsedVectorLength += map->size();
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)) {
+ if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(exec->globalData(), newUsedVectorLength)) {
throwOutOfMemoryError(exec);
return;
}
}
-
- storage = m_storage;
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
@@ -1642,8 +1645,7 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
++numDefined;
}
- delete map;
- storage->m_sparseValueMap = 0;
+ deallocateSparseMap();
}
ASSERT(tree.abstractor().m_nodes.size() >= numDefined);
@@ -1656,19 +1658,19 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
iter.start_iter_least(tree);
JSGlobalData& globalData = exec->globalData();
for (unsigned i = 0; i < numDefined; ++i) {
- storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
+ m_storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
++iter;
}
// Put undefined values back in.
for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
- storage->m_vector[i].setUndefined();
+ m_storage->m_vector[i].setUndefined();
// Ensure that unused values in the vector are zeroed out.
for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
- storage->m_vector[i].clear();
+ m_storage->m_vector[i].clear();
- storage->m_numValuesInVector = newUsedVectorLength;
+ m_storage->m_numValuesInVector = newUsedVectorLength;
checkConsistency(SortConsistencyCheck);
}
@@ -1709,7 +1711,7 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le
callFrame->setArgument(i, get(exec, i));
}
-unsigned JSArray::compactForSorting()
+unsigned JSArray::compactForSorting(JSGlobalData& globalData)
{
ASSERT(!inSparseMode());
@@ -1740,12 +1742,12 @@ unsigned JSArray::compactForSorting()
unsigned newUsedVectorLength = numDefined + numUndefined;
- if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ if (SparseArrayValueMap* map = m_sparseValueMap) {
newUsedVectorLength += map->size();
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))
+ if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(globalData, newUsedVectorLength))
return 0;
storage = m_storage;
@@ -1755,8 +1757,7 @@ unsigned JSArray::compactForSorting()
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
storage->m_vector[numDefined++].setWithoutWriteBarrier(it->second.getNonSparseMode());
- delete map;
- storage->m_sparseValueMap = 0;
+ deallocateSparseMap();
}
for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
@@ -1773,12 +1774,12 @@ unsigned JSArray::compactForSorting()
void* JSArray::subclassData() const
{
- return m_storage->subclassData;
+ return m_subclassData;
}
void JSArray::setSubclassData(void* d)
{
- m_storage->subclassData = d;
+ m_subclassData = d;
}
#if CHECK_ARRAY_CONSISTENCY
@@ -1791,7 +1792,7 @@ void JSArray::checkConsistency(ConsistencyCheckType type)
ASSERT(storage);
if (type == SortConsistencyCheck)
- ASSERT(!storage->m_sparseValueMap);
+ ASSERT(!m_sparseValueMap);
unsigned numValuesInVector = 0;
for (unsigned i = 0; i < m_vectorLength; ++i) {
@@ -1808,9 +1809,9 @@ void JSArray::checkConsistency(ConsistencyCheckType type)
ASSERT(numValuesInVector == storage->m_numValuesInVector);
ASSERT(numValuesInVector <= storage->m_length);
- if (storage->m_sparseValueMap) {
- SparseArrayValueMap::iterator end = storage->m_sparseValueMap->end();
- for (SparseArrayValueMap::iterator it = storage->m_sparseValueMap->begin(); it != end; ++it) {
+ if (m_sparseValueMap) {
+ SparseArrayValueMap::iterator end = m_sparseValueMap->end();
+ for (SparseArrayValueMap::iterator it = m_sparseValueMap->begin(); it != end; ++it) {
unsigned index = it->first;
ASSERT(index < storage->m_length);
ASSERT(index >= storage->m_vectorLength);