JavaScriptCore/runtime/JSArray.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
       
     3  *  Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
       
     4  *  Copyright (C) 2003 Peter Kelly (pmk@post.com)
       
     5  *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
       
     6  *
       
     7  *  This library is free software; you can redistribute it and/or
       
     8  *  modify it under the terms of the GNU Lesser General Public
       
     9  *  License as published by the Free Software Foundation; either
       
    10  *  version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  *  This library is distributed in the hope that it will be useful,
       
    13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  *  Lesser General Public License for more details.
       
    16  *
       
    17  *  You should have received a copy of the GNU Lesser General Public
       
    18  *  License along with this library; if not, write to the Free Software
       
    19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
       
    20  *
       
    21  */
       
    22 
       
    23 #include "config.h"
       
    24 #include "JSArray.h"
       
    25 
       
    26 #include "ArrayPrototype.h"
       
    27 #include "CachedCall.h"
       
    28 #include "Error.h"
       
    29 #include "Executable.h"
       
    30 #include "PropertyNameArray.h"
       
    31 #include <wtf/AVLTree.h>
       
    32 #include <wtf/Assertions.h>
       
    33 #include <wtf/OwnPtr.h>
       
    34 #include <Operations.h>
       
    35 
       
    36 using namespace std;
       
    37 using namespace WTF;
       
    38 
       
    39 namespace JSC {
       
    40 
       
    41 ASSERT_CLASS_FITS_IN_CELL(JSArray);
       
    42 
       
    43 // Overview of JSArray
       
    44 //
       
    45 // Properties of JSArray objects may be stored in one of three locations:
       
    46 //   * The regular JSObject property map.
       
    47 //   * A storage vector.
       
    48 //   * A sparse map of array entries.
       
    49 //
       
    50 // Properties with non-numeric identifiers, with identifiers that are not representable
       
    51 // as an unsigned integer, or where the value is greater than  MAX_ARRAY_INDEX
       
    52 // (specifically, this is only one property - the value 0xFFFFFFFFU as an unsigned 32-bit
       
    53 // integer) are not considered array indices and will be stored in the JSObject property map.
       
    54 //
       
    55 // All properties with a numeric identifer, representable as an unsigned integer i,
       
    56 // where (i <= MAX_ARRAY_INDEX), are an array index and will be stored in either the
       
    57 // storage vector or the sparse map.  An array index i will be handled in the following
       
    58 // fashion:
       
    59 //
       
    60 //   * Where (i < MIN_SPARSE_ARRAY_INDEX) the value will be stored in the storage vector.
       
    61 //   * Where (MIN_SPARSE_ARRAY_INDEX <= i <= MAX_STORAGE_VECTOR_INDEX) the value will either
       
    62 //     be stored in the storage vector or in the sparse array, depending on the density of
       
    63 //     data that would be stored in the vector (a vector being used where at least
       
    64 //     (1 / minDensityMultiplier) of the entries would be populated).
       
    65 //   * Where (MAX_STORAGE_VECTOR_INDEX < i <= MAX_ARRAY_INDEX) the value will always be stored
       
    66 //     in the sparse array.
       
    67 
       
    68 // The definition of MAX_STORAGE_VECTOR_LENGTH is dependant on the definition storageSize
       
    69 // function below - the MAX_STORAGE_VECTOR_LENGTH limit is defined such that the storage
       
    70 // size calculation cannot overflow.  (sizeof(ArrayStorage) - sizeof(JSValue)) +
       
    71 // (vectorLength * sizeof(JSValue)) must be <= 0xFFFFFFFFU (which is maximum value of size_t).
       
    72 #define MAX_STORAGE_VECTOR_LENGTH static_cast<unsigned>((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(JSValue))) / sizeof(JSValue))
       
    73 
       
    74 // These values have to be macros to be used in max() and min() without introducing
       
    75 // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
       
    76 #define MIN_SPARSE_ARRAY_INDEX 10000U
       
    77 #define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1)
       
    78 // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer.
       
    79 #define MAX_ARRAY_INDEX 0xFFFFFFFEU
       
    80 
       
    81 // Our policy for when to use a vector and when to use a sparse map.
       
    82 // For all array indices under MIN_SPARSE_ARRAY_INDEX, we always use a vector.
       
    83 // When indices greater than MIN_SPARSE_ARRAY_INDEX are involved, we use a vector
       
    84 // as long as it is 1/8 full. If more sparse than that, we use a map.
       
    85 static const unsigned minDensityMultiplier = 8;
       
    86 
       
    87 const ClassInfo JSArray::info = {"Array", 0, 0, 0};
       
    88 
       
    89 static inline size_t storageSize(unsigned vectorLength)
       
    90 {
       
    91     ASSERT(vectorLength <= MAX_STORAGE_VECTOR_LENGTH);
       
    92 
       
    93     // MAX_STORAGE_VECTOR_LENGTH is defined such that provided (vectorLength <= MAX_STORAGE_VECTOR_LENGTH)
       
    94     // - as asserted above - the following calculation cannot overflow.
       
    95     size_t size = (sizeof(ArrayStorage) - sizeof(JSValue)) + (vectorLength * sizeof(JSValue));
       
    96     // Assertion to detect integer overflow in previous calculation (should not be possible, provided that
       
    97     // MAX_STORAGE_VECTOR_LENGTH is correctly defined).
       
    98     ASSERT(((size - (sizeof(ArrayStorage) - sizeof(JSValue))) / sizeof(JSValue) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(JSValue))));
       
    99 
       
   100     return size;
       
   101 }
       
   102 
       
   103 static inline unsigned increasedVectorLength(unsigned newLength)
       
   104 {
       
   105     ASSERT(newLength <= MAX_STORAGE_VECTOR_LENGTH);
       
   106 
       
   107     // Mathematically equivalent to:
       
   108     //   increasedLength = (newLength * 3 + 1) / 2;
       
   109     // or:
       
   110     //   increasedLength = (unsigned)ceil(newLength * 1.5));
       
   111     // This form is not prone to internal overflow.
       
   112     unsigned increasedLength = newLength + (newLength >> 1) + (newLength & 1);
       
   113     ASSERT(increasedLength >= newLength);
       
   114 
       
   115     return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH);
       
   116 }
       
   117 
       
   118 static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
       
   119 {
       
   120     return length / minDensityMultiplier <= numValues;
       
   121 }
       
   122 
       
   123 #if !CHECK_ARRAY_CONSISTENCY
       
   124 
       
   125 inline void JSArray::checkConsistency(ConsistencyCheckType)
       
   126 {
       
   127 }
       
   128 
       
   129 #endif
       
   130 
       
   131 JSArray::JSArray(NonNullPassRefPtr<Structure> structure)
       
   132     : JSObject(structure)
       
   133 {
       
   134     unsigned initialCapacity = 0;
       
   135 
       
   136     m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity)));
       
   137     m_vectorLength = initialCapacity;
       
   138 
       
   139     checkConsistency();
       
   140 }
       
   141 
       
   142 JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength, ArrayCreationMode creationMode)
       
   143     : JSObject(structure)
       
   144 {
       
   145     unsigned initialCapacity;
       
   146     if (creationMode == CreateCompact)
       
   147         initialCapacity = initialLength;
       
   148     else
       
   149         initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX);
       
   150 
       
   151     m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity)));
       
   152     m_vectorLength = initialCapacity;
       
   153     m_storage->m_sparseValueMap = 0;
       
   154     m_storage->subclassData = 0;
       
   155     m_storage->reportedMapCapacity = 0;
       
   156 
       
   157     if (creationMode == CreateCompact) {
       
   158 #if CHECK_ARRAY_CONSISTENCY
       
   159         m_storage->m_inCompactInitialization = !!initialCapacity;
       
   160 #endif
       
   161         m_storage->m_length = 0;
       
   162         m_storage->m_numValuesInVector = initialCapacity;
       
   163     } else {
       
   164 #if CHECK_ARRAY_CONSISTENCY
       
   165         m_storage->m_inCompactInitialization = false;
       
   166 #endif
       
   167         m_storage->m_length = initialLength;
       
   168         m_storage->m_numValuesInVector = 0;
       
   169         JSValue* vector = m_storage->m_vector;
       
   170         for (size_t i = 0; i < initialCapacity; ++i)
       
   171             vector[i] = JSValue();
       
   172     }
       
   173 
       
   174     checkConsistency();
       
   175 
       
   176     Heap::heap(this)->reportExtraMemoryCost(initialCapacity * sizeof(JSValue));
       
   177 }
       
   178 
       
   179 JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list)
       
   180     : JSObject(structure)
       
   181 {
       
   182     unsigned initialCapacity = list.size();
       
   183 
       
   184     m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity)));
       
   185     m_storage->m_length = initialCapacity;
       
   186     m_vectorLength = initialCapacity;
       
   187     m_storage->m_numValuesInVector = initialCapacity;
       
   188     m_storage->m_sparseValueMap = 0;
       
   189     m_storage->subclassData = 0;
       
   190     m_storage->reportedMapCapacity = 0;
       
   191 #if CHECK_ARRAY_CONSISTENCY
       
   192     m_storage->m_inCompactInitialization = false;
       
   193 #endif
       
   194 
       
   195     size_t i = 0;
       
   196     ArgList::const_iterator end = list.end();
       
   197     for (ArgList::const_iterator it = list.begin(); it != end; ++it, ++i)
       
   198         m_storage->m_vector[i] = *it;
       
   199 
       
   200     checkConsistency();
       
   201 
       
   202     Heap::heap(this)->reportExtraMemoryCost(storageSize(initialCapacity));
       
   203 }
       
   204 
       
   205 JSArray::~JSArray()
       
   206 {
       
   207     ASSERT(vptr() == JSGlobalData::jsArrayVPtr);
       
   208     checkConsistency(DestructorConsistencyCheck);
       
   209 
       
   210     delete m_storage->m_sparseValueMap;
       
   211     fastFree(m_storage);
       
   212 }
       
   213 
       
   214 bool JSArray::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
       
   215 {
       
   216     ArrayStorage* storage = m_storage;
       
   217 
       
   218     if (i >= storage->m_length) {
       
   219         if (i > MAX_ARRAY_INDEX)
       
   220             return getOwnPropertySlot(exec, Identifier::from(exec, i), slot);
       
   221         return false;
       
   222     }
       
   223 
       
   224     if (i < m_vectorLength) {
       
   225         JSValue& valueSlot = storage->m_vector[i];
       
   226         if (valueSlot) {
       
   227             slot.setValueSlot(&valueSlot);
       
   228             return true;
       
   229         }
       
   230     } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
       
   231         if (i >= MIN_SPARSE_ARRAY_INDEX) {
       
   232             SparseArrayValueMap::iterator it = map->find(i);
       
   233             if (it != map->end()) {
       
   234                 slot.setValueSlot(&it->second);
       
   235                 return true;
       
   236             }
       
   237         }
       
   238     }
       
   239 
       
   240     return JSObject::getOwnPropertySlot(exec, Identifier::from(exec, i), slot);
       
   241 }
       
   242 
       
   243 bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
       
   244 {
       
   245     if (propertyName == exec->propertyNames().length) {
       
   246         slot.setValue(jsNumber(exec, length()));
       
   247         return true;
       
   248     }
       
   249 
       
   250     bool isArrayIndex;
       
   251     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
       
   252     if (isArrayIndex)
       
   253         return JSArray::getOwnPropertySlot(exec, i, slot);
       
   254 
       
   255     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
       
   256 }
       
   257 
       
   258 bool JSArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
       
   259 {
       
   260     if (propertyName == exec->propertyNames().length) {
       
   261         descriptor.setDescriptor(jsNumber(exec, length()), DontDelete | DontEnum);
       
   262         return true;
       
   263     }
       
   264     
       
   265     bool isArrayIndex;
       
   266     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
       
   267     if (isArrayIndex) {
       
   268         if (i >= m_storage->m_length)
       
   269             return false;
       
   270         if (i < m_vectorLength) {
       
   271             JSValue& value = m_storage->m_vector[i];
       
   272             if (value) {
       
   273                 descriptor.setDescriptor(value, 0);
       
   274                 return true;
       
   275             }
       
   276         } else if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {
       
   277             if (i >= MIN_SPARSE_ARRAY_INDEX) {
       
   278                 SparseArrayValueMap::iterator it = map->find(i);
       
   279                 if (it != map->end()) {
       
   280                     descriptor.setDescriptor(it->second, 0);
       
   281                     return true;
       
   282                 }
       
   283             }
       
   284         }
       
   285     }
       
   286     return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
       
   287 }
       
   288 
       
   289 // ECMA 15.4.5.1
       
   290 void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
       
   291 {
       
   292     bool isArrayIndex;
       
   293     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
       
   294     if (isArrayIndex) {
       
   295         put(exec, i, value);
       
   296         return;
       
   297     }
       
   298 
       
   299     if (propertyName == exec->propertyNames().length) {
       
   300         unsigned newLength = value.toUInt32(exec);
       
   301         if (value.toNumber(exec) != static_cast<double>(newLength)) {
       
   302             throwError(exec, createRangeError(exec, "Invalid array length."));
       
   303             return;
       
   304         }
       
   305         setLength(newLength);
       
   306         return;
       
   307     }
       
   308 
       
   309     JSObject::put(exec, propertyName, value, slot);
       
   310 }
       
   311 
       
   312 void JSArray::put(ExecState* exec, unsigned i, JSValue value)
       
   313 {
       
   314     checkConsistency();
       
   315 
       
   316     unsigned length = m_storage->m_length;
       
   317     if (i >= length && i <= MAX_ARRAY_INDEX) {
       
   318         length = i + 1;
       
   319         m_storage->m_length = length;
       
   320     }
       
   321 
       
   322     if (i < m_vectorLength) {
       
   323         JSValue& valueSlot = m_storage->m_vector[i];
       
   324         if (valueSlot) {
       
   325             valueSlot = value;
       
   326             checkConsistency();
       
   327             return;
       
   328         }
       
   329         valueSlot = value;
       
   330         ++m_storage->m_numValuesInVector;
       
   331         checkConsistency();
       
   332         return;
       
   333     }
       
   334 
       
   335     putSlowCase(exec, i, value);
       
   336 }
       
   337 
       
   338 NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue value)
       
   339 {
       
   340     ArrayStorage* storage = m_storage;
       
   341     SparseArrayValueMap* map = storage->m_sparseValueMap;
       
   342 
       
   343     if (i >= MIN_SPARSE_ARRAY_INDEX) {
       
   344         if (i > MAX_ARRAY_INDEX) {
       
   345             PutPropertySlot slot;
       
   346             put(exec, Identifier::from(exec, i), value, slot);
       
   347             return;
       
   348         }
       
   349 
       
   350         // We miss some cases where we could compact the storage, such as a large array that is being filled from the end
       
   351         // (which will only be compacted as we reach indices that are less than MIN_SPARSE_ARRAY_INDEX) - but this makes the check much faster.
       
   352         if ((i > MAX_STORAGE_VECTOR_INDEX) || !isDenseEnoughForVector(i + 1, storage->m_numValuesInVector + 1)) {
       
   353             if (!map) {
       
   354                 map = new SparseArrayValueMap;
       
   355                 storage->m_sparseValueMap = map;
       
   356             }
       
   357 
       
   358             pair<SparseArrayValueMap::iterator, bool> result = map->add(i, value);
       
   359             if (!result.second) { // pre-existing entry
       
   360                 result.first->second = value;
       
   361                 return;
       
   362             }
       
   363 
       
   364             size_t capacity = map->capacity();
       
   365             if (capacity != storage->reportedMapCapacity) {
       
   366                 Heap::heap(this)->reportExtraMemoryCost((capacity - storage->reportedMapCapacity) * (sizeof(unsigned) + sizeof(JSValue)));
       
   367                 storage->reportedMapCapacity = capacity;
       
   368             }
       
   369             return;
       
   370         }
       
   371     }
       
   372 
       
   373     // We have decided that we'll put the new item into the vector.
       
   374     // Fast case is when there is no sparse map, so we can increase the vector size without moving values from it.
       
   375     if (!map || map->isEmpty()) {
       
   376         if (increaseVectorLength(i + 1)) {
       
   377             storage = m_storage;
       
   378             storage->m_vector[i] = value;
       
   379             ++storage->m_numValuesInVector;
       
   380             checkConsistency();
       
   381         } else
       
   382             throwOutOfMemoryError(exec);
       
   383         return;
       
   384     }
       
   385 
       
   386     // Decide how many values it would be best to move from the map.
       
   387     unsigned newNumValuesInVector = storage->m_numValuesInVector + 1;
       
   388     unsigned newVectorLength = increasedVectorLength(i + 1);
       
   389     for (unsigned j = max(m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j)
       
   390         newNumValuesInVector += map->contains(j);
       
   391     if (i >= MIN_SPARSE_ARRAY_INDEX)
       
   392         newNumValuesInVector -= map->contains(i);
       
   393     if (isDenseEnoughForVector(newVectorLength, newNumValuesInVector)) {
       
   394         unsigned proposedNewNumValuesInVector = newNumValuesInVector;
       
   395         // If newVectorLength is already the maximum - MAX_STORAGE_VECTOR_LENGTH - then do not attempt to grow any further.
       
   396         while (newVectorLength < MAX_STORAGE_VECTOR_LENGTH) {
       
   397             unsigned proposedNewVectorLength = increasedVectorLength(newVectorLength + 1);
       
   398             for (unsigned j = max(newVectorLength, MIN_SPARSE_ARRAY_INDEX); j < proposedNewVectorLength; ++j)
       
   399                 proposedNewNumValuesInVector += map->contains(j);
       
   400             if (!isDenseEnoughForVector(proposedNewVectorLength, proposedNewNumValuesInVector))
       
   401                 break;
       
   402             newVectorLength = proposedNewVectorLength;
       
   403             newNumValuesInVector = proposedNewNumValuesInVector;
       
   404         }
       
   405     }
       
   406 
       
   407     if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) {
       
   408         throwOutOfMemoryError(exec);
       
   409         return;
       
   410     }
       
   411 
       
   412     unsigned vectorLength = m_vectorLength;
       
   413 
       
   414     if (newNumValuesInVector == storage->m_numValuesInVector + 1) {
       
   415         for (unsigned j = vectorLength; j < newVectorLength; ++j)
       
   416             storage->m_vector[j] = JSValue();
       
   417         if (i > MIN_SPARSE_ARRAY_INDEX)
       
   418             map->remove(i);
       
   419     } else {
       
   420         for (unsigned j = vectorLength; j < max(vectorLength, MIN_SPARSE_ARRAY_INDEX); ++j)
       
   421             storage->m_vector[j] = JSValue();
       
   422         for (unsigned j = max(vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j)
       
   423             storage->m_vector[j] = map->take(j);
       
   424     }
       
   425 
       
   426     storage->m_vector[i] = value;
       
   427 
       
   428     m_vectorLength = newVectorLength;
       
   429     storage->m_numValuesInVector = newNumValuesInVector;
       
   430 
       
   431     m_storage = storage;
       
   432 
       
   433     checkConsistency();
       
   434 
       
   435     Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
       
   436 }
       
   437 
       
   438 bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName)
       
   439 {
       
   440     bool isArrayIndex;
       
   441     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
       
   442     if (isArrayIndex)
       
   443         return deleteProperty(exec, i);
       
   444 
       
   445     if (propertyName == exec->propertyNames().length)
       
   446         return false;
       
   447 
       
   448     return JSObject::deleteProperty(exec, propertyName);
       
   449 }
       
   450 
       
   451 bool JSArray::deleteProperty(ExecState* exec, unsigned i)
       
   452 {
       
   453     checkConsistency();
       
   454 
       
   455     ArrayStorage* storage = m_storage;
       
   456 
       
   457     if (i < m_vectorLength) {
       
   458         JSValue& valueSlot = storage->m_vector[i];
       
   459         if (!valueSlot) {
       
   460             checkConsistency();
       
   461             return false;
       
   462         }
       
   463         valueSlot = JSValue();
       
   464         --storage->m_numValuesInVector;
       
   465         checkConsistency();
       
   466         return true;
       
   467     }
       
   468 
       
   469     if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
       
   470         if (i >= MIN_SPARSE_ARRAY_INDEX) {
       
   471             SparseArrayValueMap::iterator it = map->find(i);
       
   472             if (it != map->end()) {
       
   473                 map->remove(it);
       
   474                 checkConsistency();
       
   475                 return true;
       
   476             }
       
   477         }
       
   478     }
       
   479 
       
   480     checkConsistency();
       
   481 
       
   482     if (i > MAX_ARRAY_INDEX)
       
   483         return deleteProperty(exec, Identifier::from(exec, i));
       
   484 
       
   485     return false;
       
   486 }
       
   487 
       
   488 void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
       
   489 {
       
   490     // FIXME: Filling PropertyNameArray with an identifier for every integer
       
   491     // is incredibly inefficient for large arrays. We need a different approach,
       
   492     // which almost certainly means a different structure for PropertyNameArray.
       
   493 
       
   494     ArrayStorage* storage = m_storage;
       
   495 
       
   496     unsigned usedVectorLength = min(storage->m_length, m_vectorLength);
       
   497     for (unsigned i = 0; i < usedVectorLength; ++i) {
       
   498         if (storage->m_vector[i])
       
   499             propertyNames.add(Identifier::from(exec, i));
       
   500     }
       
   501 
       
   502     if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
       
   503         SparseArrayValueMap::iterator end = map->end();
       
   504         for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
       
   505             propertyNames.add(Identifier::from(exec, it->first));
       
   506     }
       
   507 
       
   508     if (mode == IncludeDontEnumProperties)
       
   509         propertyNames.add(exec->propertyNames().length);
       
   510 
       
   511     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
       
   512 }
       
   513 
       
   514 bool JSArray::increaseVectorLength(unsigned newLength)
       
   515 {
       
   516     // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
       
   517     // to the vector. Callers have to account for that, because they can do it more efficiently.
       
   518 
       
   519     ArrayStorage* storage = m_storage;
       
   520 
       
   521     unsigned vectorLength = m_vectorLength;
       
   522     ASSERT(newLength > vectorLength);
       
   523     ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX);
       
   524     unsigned newVectorLength = increasedVectorLength(newLength);
       
   525 
       
   526     if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage))
       
   527         return false;
       
   528 
       
   529     m_vectorLength = newVectorLength;
       
   530 
       
   531     for (unsigned i = vectorLength; i < newVectorLength; ++i)
       
   532         storage->m_vector[i] = JSValue();
       
   533 
       
   534     m_storage = storage;
       
   535 
       
   536     Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
       
   537 
       
   538     return true;
       
   539 }
       
   540 
       
   541 void JSArray::setLength(unsigned newLength)
       
   542 {
       
   543 #if CHECK_ARRAY_CONSISTENCY
       
   544     if (!m_storage->m_inCompactInitialization)
       
   545         checkConsistency();
       
   546     else
       
   547         m_storage->m_inCompactInitialization = false;
       
   548 #endif
       
   549 
       
   550     ArrayStorage* storage = m_storage;
       
   551 
       
   552     unsigned length = m_storage->m_length;
       
   553 
       
   554     if (newLength < length) {
       
   555         unsigned usedVectorLength = min(length, m_vectorLength);
       
   556         for (unsigned i = newLength; i < usedVectorLength; ++i) {
       
   557             JSValue& valueSlot = storage->m_vector[i];
       
   558             bool hadValue = valueSlot;
       
   559             valueSlot = JSValue();
       
   560             storage->m_numValuesInVector -= hadValue;
       
   561         }
       
   562 
       
   563         if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
       
   564             SparseArrayValueMap copy = *map;
       
   565             SparseArrayValueMap::iterator end = copy.end();
       
   566             for (SparseArrayValueMap::iterator it = copy.begin(); it != end; ++it) {
       
   567                 if (it->first >= newLength)
       
   568                     map->remove(it->first);
       
   569             }
       
   570             if (map->isEmpty()) {
       
   571                 delete map;
       
   572                 storage->m_sparseValueMap = 0;
       
   573             }
       
   574         }
       
   575     }
       
   576 
       
   577     m_storage->m_length = newLength;
       
   578 
       
   579     checkConsistency();
       
   580 }
       
   581 
       
   582 JSValue JSArray::pop()
       
   583 {
       
   584     checkConsistency();
       
   585 
       
   586     unsigned length = m_storage->m_length;
       
   587     if (!length)
       
   588         return jsUndefined();
       
   589 
       
   590     --length;
       
   591 
       
   592     JSValue result;
       
   593 
       
   594     if (length < m_vectorLength) {
       
   595         JSValue& valueSlot = m_storage->m_vector[length];
       
   596         if (valueSlot) {
       
   597             --m_storage->m_numValuesInVector;
       
   598             result = valueSlot;
       
   599             valueSlot = JSValue();
       
   600         } else
       
   601             result = jsUndefined();
       
   602     } else {
       
   603         result = jsUndefined();
       
   604         if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {
       
   605             SparseArrayValueMap::iterator it = map->find(length);
       
   606             if (it != map->end()) {
       
   607                 result = it->second;
       
   608                 map->remove(it);
       
   609                 if (map->isEmpty()) {
       
   610                     delete map;
       
   611                     m_storage->m_sparseValueMap = 0;
       
   612                 }
       
   613             }
       
   614         }
       
   615     }
       
   616 
       
   617     m_storage->m_length = length;
       
   618 
       
   619     checkConsistency();
       
   620 
       
   621     return result;
       
   622 }
       
   623 
       
   624 void JSArray::push(ExecState* exec, JSValue value)
       
   625 {
       
   626     checkConsistency();
       
   627 
       
   628     if (m_storage->m_length < m_vectorLength) {
       
   629         m_storage->m_vector[m_storage->m_length] = value;
       
   630         ++m_storage->m_numValuesInVector;
       
   631         ++m_storage->m_length;
       
   632         checkConsistency();
       
   633         return;
       
   634     }
       
   635 
       
   636     if (m_storage->m_length < MIN_SPARSE_ARRAY_INDEX) {
       
   637         SparseArrayValueMap* map = m_storage->m_sparseValueMap;
       
   638         if (!map || map->isEmpty()) {
       
   639             if (increaseVectorLength(m_storage->m_length + 1)) {
       
   640                 m_storage->m_vector[m_storage->m_length] = value;
       
   641                 ++m_storage->m_numValuesInVector;
       
   642                 ++m_storage->m_length;
       
   643                 checkConsistency();
       
   644                 return;
       
   645             }
       
   646             checkConsistency();
       
   647             throwOutOfMemoryError(exec);
       
   648             return;
       
   649         }
       
   650     }
       
   651 
       
   652     putSlowCase(exec, m_storage->m_length++, value);
       
   653 }
       
   654 
       
   655 void JSArray::markChildren(MarkStack& markStack)
       
   656 {
       
   657     markChildrenDirect(markStack);
       
   658 }
       
   659 
       
   660 static int compareNumbersForQSort(const void* a, const void* b)
       
   661 {
       
   662     double da = static_cast<const JSValue*>(a)->uncheckedGetNumber();
       
   663     double db = static_cast<const JSValue*>(b)->uncheckedGetNumber();
       
   664     return (da > db) - (da < db);
       
   665 }
       
   666 
       
   667 typedef std::pair<JSValue, UString> ValueStringPair;
       
   668 
       
   669 static int compareByStringPairForQSort(const void* a, const void* b)
       
   670 {
       
   671     const ValueStringPair* va = static_cast<const ValueStringPair*>(a);
       
   672     const ValueStringPair* vb = static_cast<const ValueStringPair*>(b);
       
   673     return codePointCompare(va->second, vb->second);
       
   674 }
       
   675 
       
   676 void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
       
   677 {
       
   678     unsigned lengthNotIncludingUndefined = compactForSorting();
       
   679     if (m_storage->m_sparseValueMap) {
       
   680         throwOutOfMemoryError(exec);
       
   681         return;
       
   682     }
       
   683 
       
   684     if (!lengthNotIncludingUndefined)
       
   685         return;
       
   686         
       
   687     bool allValuesAreNumbers = true;
       
   688     size_t size = m_storage->m_numValuesInVector;
       
   689     for (size_t i = 0; i < size; ++i) {
       
   690         if (!m_storage->m_vector[i].isNumber()) {
       
   691             allValuesAreNumbers = false;
       
   692             break;
       
   693         }
       
   694     }
       
   695 
       
   696     if (!allValuesAreNumbers)
       
   697         return sort(exec, compareFunction, callType, callData);
       
   698 
       
   699     // For numeric comparison, which is fast, qsort is faster than mergesort. We
       
   700     // also don't require mergesort's stability, since there's no user visible
       
   701     // side-effect from swapping the order of equal primitive values.
       
   702     qsort(m_storage->m_vector, size, sizeof(JSValue), compareNumbersForQSort);
       
   703 
       
   704     checkConsistency(SortConsistencyCheck);
       
   705 }
       
   706 
       
   707 void JSArray::sort(ExecState* exec)
       
   708 {
       
   709     unsigned lengthNotIncludingUndefined = compactForSorting();
       
   710     if (m_storage->m_sparseValueMap) {
       
   711         throwOutOfMemoryError(exec);
       
   712         return;
       
   713     }
       
   714 
       
   715     if (!lengthNotIncludingUndefined)
       
   716         return;
       
   717 
       
   718     // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
       
   719     // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
       
   720     // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
       
   721     // random or otherwise changing results, effectively making compare function inconsistent.
       
   722 
       
   723     Vector<ValueStringPair> values(lengthNotIncludingUndefined);
       
   724     if (!values.begin()) {
       
   725         throwOutOfMemoryError(exec);
       
   726         return;
       
   727     }
       
   728 
       
   729     for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
       
   730         JSValue value = m_storage->m_vector[i];
       
   731         ASSERT(!value.isUndefined());
       
   732         values[i].first = value;
       
   733     }
       
   734 
       
   735     // FIXME: While calling these toString functions, the array could be mutated.
       
   736     // In that case, objects pointed to by values in this vector might get garbage-collected!
       
   737 
       
   738     // FIXME: The following loop continues to call toString on subsequent values even after
       
   739     // a toString call raises an exception.
       
   740 
       
   741     for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
       
   742         values[i].second = values[i].first.toString(exec);
       
   743 
       
   744     if (exec->hadException())
       
   745         return;
       
   746 
       
   747     // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
       
   748     // than O(N log N).
       
   749 
       
   750 #if HAVE(MERGESORT)
       
   751     mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
       
   752 #else
       
   753     // FIXME: The qsort library function is likely to not be a stable sort.
       
   754     // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
       
   755     qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
       
   756 #endif
       
   757 
       
   758     // FIXME: If the toString function changed the length of the array, this might be
       
   759     // modifying the vector incorrectly.
       
   760 
       
   761     for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
       
   762         m_storage->m_vector[i] = values[i].first;
       
   763 
       
   764     checkConsistency(SortConsistencyCheck);
       
   765 }
       
   766 
       
   767 struct AVLTreeNodeForArrayCompare {
       
   768     JSValue value;
       
   769 
       
   770     // Child pointers.  The high bit of gt is robbed and used as the
       
   771     // balance factor sign.  The high bit of lt is robbed and used as
       
   772     // the magnitude of the balance factor.
       
   773     int32_t gt;
       
   774     int32_t lt;
       
   775 };
       
   776 
       
   777 struct AVLTreeAbstractorForArrayCompare {
       
   778     typedef int32_t handle; // Handle is an index into m_nodes vector.
       
   779     typedef JSValue key;
       
   780     typedef int32_t size;
       
   781 
       
   782     Vector<AVLTreeNodeForArrayCompare> m_nodes;
       
   783     ExecState* m_exec;
       
   784     JSValue m_compareFunction;
       
   785     CallType m_compareCallType;
       
   786     const CallData* m_compareCallData;
       
   787     JSValue m_globalThisValue;
       
   788     OwnPtr<CachedCall> m_cachedCall;
       
   789 
       
   790     handle get_less(handle h) { return m_nodes[h].lt & 0x7FFFFFFF; }
       
   791     void set_less(handle h, handle lh) { m_nodes[h].lt &= 0x80000000; m_nodes[h].lt |= lh; }
       
   792     handle get_greater(handle h) { return m_nodes[h].gt & 0x7FFFFFFF; }
       
   793     void set_greater(handle h, handle gh) { m_nodes[h].gt &= 0x80000000; m_nodes[h].gt |= gh; }
       
   794 
       
   795     int get_balance_factor(handle h)
       
   796     {
       
   797         if (m_nodes[h].gt & 0x80000000)
       
   798             return -1;
       
   799         return static_cast<unsigned>(m_nodes[h].lt) >> 31;
       
   800     }
       
   801 
       
   802     void set_balance_factor(handle h, int bf)
       
   803     {
       
   804         if (bf == 0) {
       
   805             m_nodes[h].lt &= 0x7FFFFFFF;
       
   806             m_nodes[h].gt &= 0x7FFFFFFF;
       
   807         } else {
       
   808             m_nodes[h].lt |= 0x80000000;
       
   809             if (bf < 0)
       
   810                 m_nodes[h].gt |= 0x80000000;
       
   811             else
       
   812                 m_nodes[h].gt &= 0x7FFFFFFF;
       
   813         }
       
   814     }
       
   815 
       
   816     int compare_key_key(key va, key vb)
       
   817     {
       
   818         ASSERT(!va.isUndefined());
       
   819         ASSERT(!vb.isUndefined());
       
   820 
       
   821         if (m_exec->hadException())
       
   822             return 1;
       
   823 
       
   824         double compareResult;
       
   825         if (m_cachedCall) {
       
   826             m_cachedCall->setThis(m_globalThisValue);
       
   827             m_cachedCall->setArgument(0, va);
       
   828             m_cachedCall->setArgument(1, vb);
       
   829             compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame(m_exec));
       
   830         } else {
       
   831             MarkedArgumentBuffer arguments;
       
   832             arguments.append(va);
       
   833             arguments.append(vb);
       
   834             compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, m_globalThisValue, arguments).toNumber(m_exec);
       
   835         }
       
   836         return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent.
       
   837     }
       
   838 
       
   839     int compare_key_node(key k, handle h) { return compare_key_key(k, m_nodes[h].value); }
       
   840     int compare_node_node(handle h1, handle h2) { return compare_key_key(m_nodes[h1].value, m_nodes[h2].value); }
       
   841 
       
   842     static handle null() { return 0x7FFFFFFF; }
       
   843 };
       
   844 
       
   845 void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
       
   846 {
       
   847     checkConsistency();
       
   848 
       
   849     // FIXME: This ignores exceptions raised in the compare function or in toNumber.
       
   850 
       
   851     // The maximum tree depth is compiled in - but the caller is clearly up to no good
       
   852     // if a larger array is passed.
       
   853     ASSERT(m_storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max()));
       
   854     if (m_storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max()))
       
   855         return;
       
   856 
       
   857     if (!m_storage->m_length)
       
   858         return;
       
   859 
       
   860     unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength);
       
   861 
       
   862     AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
       
   863     tree.abstractor().m_exec = exec;
       
   864     tree.abstractor().m_compareFunction = compareFunction;
       
   865     tree.abstractor().m_compareCallType = callType;
       
   866     tree.abstractor().m_compareCallData = &callData;
       
   867     tree.abstractor().m_globalThisValue = exec->globalThisValue();
       
   868     tree.abstractor().m_nodes.resize(usedVectorLength + (m_storage->m_sparseValueMap ? m_storage->m_sparseValueMap->size() : 0));
       
   869 
       
   870     if (callType == CallTypeJS)
       
   871         tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, asFunction(compareFunction), 2, exec->exceptionSlot()));
       
   872 
       
   873     if (!tree.abstractor().m_nodes.begin()) {
       
   874         throwOutOfMemoryError(exec);
       
   875         return;
       
   876     }
       
   877 
       
   878     // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
       
   879     // right out from under us while we're building the tree here.
       
   880 
       
   881     unsigned numDefined = 0;
       
   882     unsigned numUndefined = 0;
       
   883 
       
   884     // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
       
   885     for (; numDefined < usedVectorLength; ++numDefined) {
       
   886         JSValue v = m_storage->m_vector[numDefined];
       
   887         if (!v || v.isUndefined())
       
   888             break;
       
   889         tree.abstractor().m_nodes[numDefined].value = v;
       
   890         tree.insert(numDefined);
       
   891     }
       
   892     for (unsigned i = numDefined; i < usedVectorLength; ++i) {
       
   893         JSValue v = m_storage->m_vector[i];
       
   894         if (v) {
       
   895             if (v.isUndefined())
       
   896                 ++numUndefined;
       
   897             else {
       
   898                 tree.abstractor().m_nodes[numDefined].value = v;
       
   899                 tree.insert(numDefined);
       
   900                 ++numDefined;
       
   901             }
       
   902         }
       
   903     }
       
   904 
       
   905     unsigned newUsedVectorLength = numDefined + numUndefined;
       
   906 
       
   907     if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {
       
   908         newUsedVectorLength += map->size();
       
   909         if (newUsedVectorLength > m_vectorLength) {
       
   910             // Check that it is possible to allocate an array large enough to hold all the entries.
       
   911             if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) {
       
   912                 throwOutOfMemoryError(exec);
       
   913                 return;
       
   914             }
       
   915         }
       
   916 
       
   917         SparseArrayValueMap::iterator end = map->end();
       
   918         for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) {
       
   919             tree.abstractor().m_nodes[numDefined].value = it->second;
       
   920             tree.insert(numDefined);
       
   921             ++numDefined;
       
   922         }
       
   923 
       
   924         delete map;
       
   925         m_storage->m_sparseValueMap = 0;
       
   926     }
       
   927 
       
   928     ASSERT(tree.abstractor().m_nodes.size() >= numDefined);
       
   929 
       
   930     // FIXME: If the compare function changed the length of the array, the following might be
       
   931     // modifying the vector incorrectly.
       
   932 
       
   933     // Copy the values back into m_storage.
       
   934     AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
       
   935     iter.start_iter_least(tree);
       
   936     for (unsigned i = 0; i < numDefined; ++i) {
       
   937         m_storage->m_vector[i] = tree.abstractor().m_nodes[*iter].value;
       
   938         ++iter;
       
   939     }
       
   940 
       
   941     // Put undefined values back in.
       
   942     for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
       
   943         m_storage->m_vector[i] = jsUndefined();
       
   944 
       
   945     // Ensure that unused values in the vector are zeroed out.
       
   946     for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
       
   947         m_storage->m_vector[i] = JSValue();
       
   948 
       
   949     m_storage->m_numValuesInVector = newUsedVectorLength;
       
   950 
       
   951     checkConsistency(SortConsistencyCheck);
       
   952 }
       
   953 
       
   954 void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
       
   955 {
       
   956     JSValue* vector = m_storage->m_vector;
       
   957     unsigned vectorEnd = min(m_storage->m_length, m_vectorLength);
       
   958     unsigned i = 0;
       
   959     for (; i < vectorEnd; ++i) {
       
   960         JSValue& v = vector[i];
       
   961         if (!v)
       
   962             break;
       
   963         args.append(v);
       
   964     }
       
   965 
       
   966     for (; i < m_storage->m_length; ++i)
       
   967         args.append(get(exec, i));
       
   968 }
       
   969 
       
   970 void JSArray::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
       
   971 {
       
   972     ASSERT(m_storage->m_length >= maxSize);
       
   973     UNUSED_PARAM(maxSize);
       
   974     JSValue* vector = m_storage->m_vector;
       
   975     unsigned vectorEnd = min(maxSize, m_vectorLength);
       
   976     unsigned i = 0;
       
   977     for (; i < vectorEnd; ++i) {
       
   978         JSValue& v = vector[i];
       
   979         if (!v)
       
   980             break;
       
   981         buffer[i] = v;
       
   982     }
       
   983 
       
   984     for (; i < maxSize; ++i)
       
   985         buffer[i] = get(exec, i);
       
   986 }
       
   987 
       
   988 unsigned JSArray::compactForSorting()
       
   989 {
       
   990     checkConsistency();
       
   991 
       
   992     ArrayStorage* storage = m_storage;
       
   993 
       
   994     unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength);
       
   995 
       
   996     unsigned numDefined = 0;
       
   997     unsigned numUndefined = 0;
       
   998 
       
   999     for (; numDefined < usedVectorLength; ++numDefined) {
       
  1000         JSValue v = storage->m_vector[numDefined];
       
  1001         if (!v || v.isUndefined())
       
  1002             break;
       
  1003     }
       
  1004     for (unsigned i = numDefined; i < usedVectorLength; ++i) {
       
  1005         JSValue v = storage->m_vector[i];
       
  1006         if (v) {
       
  1007             if (v.isUndefined())
       
  1008                 ++numUndefined;
       
  1009             else
       
  1010                 storage->m_vector[numDefined++] = v;
       
  1011         }
       
  1012     }
       
  1013 
       
  1014     unsigned newUsedVectorLength = numDefined + numUndefined;
       
  1015 
       
  1016     if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
       
  1017         newUsedVectorLength += map->size();
       
  1018         if (newUsedVectorLength > m_vectorLength) {
       
  1019             // Check that it is possible to allocate an array large enough to hold all the entries - if not,
       
  1020             // exception is thrown by caller.
       
  1021             if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength))
       
  1022                 return 0;
       
  1023             storage = m_storage;
       
  1024         }
       
  1025 
       
  1026         SparseArrayValueMap::iterator end = map->end();
       
  1027         for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
       
  1028             storage->m_vector[numDefined++] = it->second;
       
  1029 
       
  1030         delete map;
       
  1031         storage->m_sparseValueMap = 0;
       
  1032     }
       
  1033 
       
  1034     for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
       
  1035         storage->m_vector[i] = jsUndefined();
       
  1036     for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
       
  1037         storage->m_vector[i] = JSValue();
       
  1038 
       
  1039     storage->m_numValuesInVector = newUsedVectorLength;
       
  1040 
       
  1041     checkConsistency(SortConsistencyCheck);
       
  1042 
       
  1043     return numDefined;
       
  1044 }
       
  1045 
       
  1046 void* JSArray::subclassData() const
       
  1047 {
       
  1048     return m_storage->subclassData;
       
  1049 }
       
  1050 
       
  1051 void JSArray::setSubclassData(void* d)
       
  1052 {
       
  1053     m_storage->subclassData = d;
       
  1054 }
       
  1055 
       
  1056 #if CHECK_ARRAY_CONSISTENCY
       
  1057 
       
  1058 void JSArray::checkConsistency(ConsistencyCheckType type)
       
  1059 {
       
  1060     ASSERT(m_storage);
       
  1061     if (type == SortConsistencyCheck)
       
  1062         ASSERT(!m_storage->m_sparseValueMap);
       
  1063 
       
  1064     unsigned numValuesInVector = 0;
       
  1065     for (unsigned i = 0; i < m_vectorLength; ++i) {
       
  1066         if (JSValue value = m_storage->m_vector[i]) {
       
  1067             ASSERT(i < m_storage->m_length);
       
  1068             if (type != DestructorConsistencyCheck)
       
  1069                 value.isUndefined(); // Likely to crash if the object was deallocated.
       
  1070             ++numValuesInVector;
       
  1071         } else {
       
  1072             if (type == SortConsistencyCheck)
       
  1073                 ASSERT(i >= m_storage->m_numValuesInVector);
       
  1074         }
       
  1075     }
       
  1076     ASSERT(numValuesInVector == m_storage->m_numValuesInVector);
       
  1077     ASSERT(numValuesInVector <= m_storage->m_length);
       
  1078 
       
  1079     if (m_storage->m_sparseValueMap) {
       
  1080         SparseArrayValueMap::iterator end = m_storage->m_sparseValueMap->end();
       
  1081         for (SparseArrayValueMap::iterator it = m_storage->m_sparseValueMap->begin(); it != end; ++it) {
       
  1082             unsigned index = it->first;
       
  1083             ASSERT(index < m_storage->m_length);
       
  1084             ASSERT(index >= m_vectorLength);
       
  1085             ASSERT(index <= MAX_ARRAY_INDEX);
       
  1086             ASSERT(it->second);
       
  1087             if (type != DestructorConsistencyCheck)
       
  1088                 it->second.isUndefined(); // Likely to crash if the object was deallocated.
       
  1089         }
       
  1090     }
       
  1091 }
       
  1092 
       
  1093 #endif
       
  1094 
       
  1095 } // namespace JSC